SaxWriterImpl.java

/*
** Module   : SaxWriterImpl
** Abstract : SAX writer specific features implementation.
**
** Copyright (c) 2013-2025, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------Description----------------------------------
** 001 EVL 20130208 Created initial version. Implementation is limited to the stubs to get the
**                  converted java code compiled.
** 002 CA  20130221 This resource doesn't have NAME attribute support.
** 003 EVL 20130320 Spelling fixes for comments.
** 004 EVK 20131001 Implement methods and class logic.
** 005 EVK 20140113 Added method resourceDelete to properly remove the object.
** 006 OM  20160129 Fixed ClassCastException in SET-OUTPUT-DESTINATION.
** 007 ECF 20160419 Fixed NPE in writeDataElement and writeEmptyElement.
** 008 IAS 20160707 Fixed the behavior to be more consistent with 4GL SAX-WRITER one.
** 009 CA  20211126 Fixed performance when writing a XML via FileOutputStreamWrapper. 
**     EVL 20221017 Added namespace repair option set.
** 010 CA  20230116 Avoid using handle.unwrap, handle.getReference or other BDT usage from within FWD runtime.
** 011 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
** 012 AS  20250903 Honor the fragment attribute of the writer.
** 013 CA  20250516 Fixed issues with XML namespaces - these need to be scoped for each XML element, and
**                  ensure that when an element is written, it uses the prefix (if it exists). 
** 014 CA  20250526 Namespace URIs and prefixes are looked up in all scopes, not just current scope. 
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
** 
** Additional terms under GNU Affero GPL version 3 section 7:
** 
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
**   terms apply to the works covered under the License.  These additional terms
**   are non-permissive additional terms allowed under Section 7 of the GNU
**   Affero GPL version 3 and may not be removed by you.
** 
**   0. Attribution Requirement.
** 
**     You must preserve all legal notices or author attributions in the covered
**     work or Appropriate Legal Notices displayed by works containing the covered
**     work.  You may not remove from the covered work any author or developer
**     credit already included within the covered work.
** 
**   1. No License To Use Trademarks.
** 
**     This license does not grant any license or rights to use the trademarks
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
**     of Golden Code Development Corporation. You are not authorized to use the
**     name Golden Code, FWD, or the names of any author or contributor, for
**     publicity purposes without written authorization.
** 
**   2. No Misrepresentation of Affiliation.
** 
**     You may not represent yourself as Golden Code Development Corporation or FWD.
** 
**     You may not represent yourself for publicity purposes as associated with
**     Golden Code Development Corporation, FWD, or any author or contributor to
**     the covered work, without written authorization.
** 
**   3. No Misrepresentation of Source or Origin.
** 
**     You may not represent the covered work as solely your work.  All modified
**     versions of the covered work must be marked in a reasonable way to make it
**     clear that the modified work is not originating from Golden Code Development
**     Corporation or FWD.  All modified versions must contain the notices of
**     attribution required in this license.
*/

package com.goldencode.p2j.xml;

import java.io.*;
import java.util.*;
import java.util.concurrent.atomic.*;
import java.util.function.*;
import java.util.logging.*;

import javax.xml.namespace.*;
import javax.xml.stream.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;

import com.goldencode.p2j.util.logging.*;
import org.codehaus.stax2.*;
import org.w3c.dom.*;
import org.xml.sax.*;

import com.ctc.wstx.api.*;
import com.ctc.wstx.stax.*;
import com.goldencode.p2j.util.*;
import com.goldencode.p2j.util.ErrorManager;
import com.goldencode.p2j.util.Text;

import javanet.staxutils.*;

/**
 * Implementation SAX-Writer specific features of the SAX objects.
 */
public class SaxWriterImpl
extends SaxEntityImpl
implements SaxWriter
{
   /** default version of XML */
   private static final String DEFAULT_XML_VERSION = "1.0";

   /** Anonymous log instance. */
   private static final CentralLogger LOG = CentralLogger.get(SaxWriterImpl.class.getName());

   /** Current status of SAX-Writer */
   private WriteStatus writeStatus = WriteStatus.SAX_WRITE_IDLE;

   /** Current output source of SAX-Writer */
   private OutputStream outputWrapper = null;

   /** encoding of SAX-Writer */
   private String encoding = "";

   /** version of xml */
   private String version = DEFAULT_XML_VERSION;

   /** formatted attribute */
   private boolean formatted = false;

   /** strict attribute. */
   private boolean strict = true;

   /** fragment attribute. */
   private boolean fragment = false;

   /** standalone attribute. */
   private Boolean standalone = null;

   /** XML stream cursor writer.*/
   private XMLStreamWriter writer = null;
   
   /** Track the namespaces for each element. */
   private ScopedNamespaceContext nscontext = null;

   /**
    * Default constructor.
    */
   public SaxWriterImpl()
   {
      // no-op
   }

   /**
    * Gets the value of the encoding attribute for the given SAX-Writer object.
    *
    * @return   The character value of the encoding attribute.
    */
   @Override
   public character getEncoding()
   {
      return new character(encoding);
   }

   /**
    * Sets the new value of the encoding attribute for the given SAX-Writer object.
    *
    * @param    encoding
    *           The encoding value to be set for the given writer.
    */
   @Override
   public void setEncoding(String encoding)
   {
      setEncoding(new character(encoding));
   }

   /**
    * Sets the new value of the encoding attribute for the given SAX-Writer object.
    *
    * @param    encoding
    *           The encoding value to be set for the given writer.
    */
   @Override
   public void setEncoding(character encoding)
   {
      if (encoding.isUnknown())
      {
         invalidArgumentAssignError("ENCODING");
         return;
      }

      if (!WriteStatus.nonWritableStatuses.contains(writeStatus))
      {
         invalidStatusAttributeError("ENCODING", writeStatus);
         return;
      }

      this.encoding = encoding.toStringMessage();
   }

   /**
    * Gets the value of the formatted attribute for the given SAX-Writer object. Formatted means
    * extra space or carrage returns should be added to preserve the hierarchical view of the
    * document.
    * 
    * @return   The <code>true</code> in case of formatted <code>false</code> otherwise.
    */
   @Override
   public logical getFormatted()
   {
      return new logical(formatted);
   }
   
   /**
    * Sets the value of the formatted attribute for the given SAX-Writer object. Formatted means
    * extra space or carriage returns should be added to preserve the hierarchical view of the
    * document.
    * 
    * @param    isFormatted
    *           The <code>true</code> in case of formatted <code>false</code> otherwise.
    */
   @Override
   public void setFormatted(logical isFormatted)
   {
      if (!WriteStatus.nonWritableStatuses.contains(writeStatus))
      {
         invalidStatusAttributeError("FORMATTED", writeStatus);
         return;
      }

      formatted = isFormatted.booleanValue();
   }

   /**
    * Sets the value of the formatted attribute for the given SAX-Writer object. Formatted means
    * extra space or carrage returns should be added to preserve the hierarchical view of the
    * document.
    *
    * @param    isFormatted
    *           The <code>true</code> in case of formatted <code>false</code> otherwise.
    */
   @Override
   public void setFormatted(boolean isFormatted)
   {
      setFormatted(new logical(isFormatted));
   }

   /**
    * Gets the value of the strict attribute for the given SAX-Writer object. Strict means
    * SAX-Writer should make well formed XML document. The default is true.
    * 
    * @return   The <code>true</code> in case of strict <code>false</code> otherwise.
    */
   @Override
   public logical getStrict()
   {
      return new logical(strict);
   }
   
   /**
    * Sets the value of the strict attribute for the given SAX-Writer object. Strict means
    * SAX-Writer should make well formed XML document. The default is true.
    * 
    * @param    isStrict
    *           The <code>true</code> in case of strict <code>false</code> otherwise.
    */
   @Override
   public void setStrict(logical isStrict)
   {
      if (!WriteStatus.nonWritableStatuses.contains(writeStatus))
      {
         invalidStatusAttributeError("STRICT", writeStatus);
         return;
      }

      strict = isStrict.booleanValue();
   }

   /**
    * Sets the value of the strict attribute for the given SAX-Writer object. Strict means
    * SAX-Writer should make well formed XML document. The default is true.
    * 
    * @param    isStrict
    *           The <code>true</code> in case of strict <code>false</code> otherwise.
    */
   @Override
   public void setStrict(boolean isStrict)
   {
      setStrict(new logical(isStrict));
   }

   /**
    * Gets the value of the fragment attribute for the given SAX-Writer object. Fragment means
    * SAX-Writer output is part of the document or full.
    * 
    * @return   The <code>true</code> in case of fragment <code>false</code> for full document.
    */
   @Override
   public logical getFragment()
   {
      return new logical(fragment);
   }
   
   /**
    * Sets the value of the fragment attribute for the given SAX-Writer object. Fragment means
    * SAX-Writer output is part of the document or full.
    * 
    * @param    isFragment
    *           The <code>true</code> in case of fragment <code>false</code> for full document.
    */
   @Override
   public void setFragment(logical isFragment)
   {
      if (!WriteStatus.nonWritableStatuses.contains(writeStatus))
      {
         invalidStatusAttributeError("FRAGMENT", writeStatus);
         return;
      }

      fragment = isFragment.booleanValue();
   }
   
   /**
    * Sets the value of the fragment attribute for the given SAX-Writer object. Fragment means
    * SAX-Writer output is part of the document or full.
    * 
    * @param    isFragment
    *           The <code>true</code> in case of fragment <code>false</code> for full document.
    */
   @Override
   public void setFragment(boolean isFragment)
   {
      setFragment(new logical(isFragment));
   }
   
   /**
    * Gets the value of the standalone attribute for the given SAX-Writer object.
    * 
    * @return   The character value of the standalone attribute.
    */
   @Override
   public logical getStandalone()
   {
      return new logical(standalone);
   }
   
   /**
    * Sets the value of the standalone attribute for the given SAX-Writer object.
    * 
    * @param    isStandalone
    *           The <code>true</code> in case of standalone <code>false</code> otherwise.
    */
   @Override
   public void setStandalone(logical isStandalone)
   {
      if (!WriteStatus.nonWritableStatuses.contains(writeStatus))
      {
         invalidStatusAttributeError("STANDALONE", writeStatus);
         return;
      }

      standalone = isStandalone.toJavaType();
   }
   
   /**
    * Sets the value of the standalone attribute for the given SAX-Writer object.
    * 
    * @param    isStandalone
    *           The <code>true</code> in case of standalone <code>false</code> otherwise.
    */
   @Override
   public void setStandalone(boolean isStandalone)
   {
      setStandalone(new logical(isStandalone));
   }
   
   /**
    * Gets the value of the version attribute for the given SAX-Writer object.
    * 
    * @return   The character value of the version attribute.
    */
   @Override
   public character getVersion()
   {
      return new character(version);
   }
   
   /**
    * Sets the new value of the version attribute for the given SAX-Writer object.
    * 
    * @param    version
    *           The version value to be set for the given writer.
    */
   @Override
   public void setVersion(String version)
   {
      setVersion(new character(version));
   }
   
   /**
    * Sets the new value of the version attribute for the given SAX-Writer object.
    * 
    * @param    version
    *           The version value to be set for the given writer.
    */
   @Override
   public void setVersion(character version)
   {
      if (version.isUnknown())
      {
         invalidArgumentAssignError("VERSION");
         return;
      }

      if (!WriteStatus.nonWritableStatuses.contains(writeStatus))
      {
         invalidStatusAttributeError("VERSION", writeStatus);
         return;
      }

      this.version = version.toStringMessage();
   }
   
   /**
    * Gets the value of the write-status attribute for the given SAX-Writer object. This is one
    * of the SAX_WRITE_* constants defined by the {@link SaxWriter} interface.
    * <p>
    * Documentation states that the type of this attribute is character, but this is incorrect. 
    * The attribute's real type is integer, same as PARSE-STATUS for the SAX-Reader object.
    * 
    * @return   The integer value of the write-status attribute.
    */
   @Override
   public integer getWriteStatus()
   {
      return new integer(writeStatus.getStatus());
   }
   
   /**
    * Adds namespace declaration to a tag in a XML document associated with SAX-Writer object.
    * 
    * @param    uri
    *           The URI namespace to add.
    * @param    prefix
    *           The prefix of the namespace to add.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical declareNamespace(Text uri, Text prefix)
   {
      if (!WriteStatus.writableBodyStatuses.contains(writeStatus))
      {
         invalidStatusMethodError("DECLARE-NAMESPACE", writeStatus);
         return new logical(false);
      }

      String prefixStr = prefix.isUnknown() ? "" : prefix.toStringMessage();
      try
      {
         writer.writeNamespace(prefixStr, uri.toStringMessage());
      }
      catch (XMLStreamException ignored)
      {
         writerOutputError("DECLARE-NAMESPACE");
         return new logical(false);
      }

      return new logical(true);
   }

   /**
    * Adds namespace declaration to a tag in a XML document associated with SAX-Writer object.
    *
    * @param    uri
    *           The URI namespace to add.
    * @param    prefix
    *           The prefix of the namespace to add.
    *
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical declareNamespace(String uri, Text prefix)
   {
      return declareNamespace(new character(uri), prefix);
   }

   /**
    * Adds namespace declaration to a tag in a XML document associated with SAX-Writer object.
    * 
    * @param    uri
    *           The URI namespace to add.
    * @param    prefix
    *           The prefix of the namespace to add.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical declareNamespace(Text uri, String prefix)
   {
      return declareNamespace(uri, new character(prefix));
   }

   /**
    * Adds namespace declaration to a tag in a XML document associated with SAX-Writer object.
    * 
    * @param    uri
    *           The URI namespace to add.
    * @param    prefix
    *           The prefix of the namespace to add.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical declareNamespace(String uri, String prefix)
   {
      return declareNamespace(new character(uri), new character(prefix));
   }

   /**
    * Adds namespace declaration to a tag in a XML document associated with SAX-Writer object.
    * 
    * @param    uri
    *           The URI namespace to add.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical declareNamespace(String uri)
   {
      return declareNamespace(new character(uri), new character());
   }
   
   /**
    * Adds namespace declaration to a tag in a XML document associated with SAX-Writer object.
    * 
    * @param    uri
    *           The URI namespace to add.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical declareNamespace(Text uri)
   {
      return declareNamespace(uri, new character());
   }
   
   /**
    * Closes the XML document associated with SAX-Writer object.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical endDocument()
   {
      if (!WriteStatus.writableStatuses.contains(writeStatus))
      {
         invalidStatusMethodError("END-DOCUMENT", writeStatus);
         return new logical(false);
      }

      try
      {
         writer.writeEndDocument();
         writer.close();
         writeStatus = WriteStatus.SAX_WRITE_COMPLETE;
         outputWrapper.close();
         nscontext.endElement();
      }
      catch (XMLStreamException | IOException ignored)
      {
         writerOutputError("END-DOCUMENT");
         return new logical(false);
      }

      return new logical(true);
   }

   /**
    * Ends an XML node of the given name in a XML document associated with SAX-Writer object.
    * 
    * @param    name
    *           The name of the node to end.
    * @param    uri
    *           The URI namespace of the node to end.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical endElement(Text name, Text uri)
   {
      if (!BaseDataType.elementsOfType(character.class, uri, name))
      {
         invalidArgumentError("END-ELEMENT");
         return new logical(false);
      }

      if (!WriteStatus.writableStatuses.contains(writeStatus))
      {
         invalidStatusMethodError("END-ELEMENT", writeStatus);
         return new logical(false);
      }

      try
      {
         writer.writeEndElement();
         nscontext.endElement();
         writeStatus = WriteStatus.SAX_WRITE_ELEMENT;
      }
      catch (XMLStreamException ignored)
      {
         writerOutputError("END-ELEMENT");
         return new logical(false);
      }

      return new logical(true);
   }

   /**
    * Ends an XML node of the given name in a XML document associated with SAX-Writer object.
    * 
    * @param    name
    *           The name of the node to end.
    * @param    uri
    *           The URI namespace of the node to end.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical endElement(String name, Text uri)
   {
      return endElement(new character(name), uri);
   }

   /**
    * Ends an XML node of the given name in a XML document associated with SAX-Writer object.
    * 
    * @param    name
    *           The name of the node to end.
    * @param    uri
    *           The URI namespace of the node to end.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical endElement(Text name, String uri)
   {
      return endElement(name, new character(uri));
   }

   /**
    * Ends an XML node of the given name in a XML document associated with SAX-Writer object.
    * 
    * @param    name
    *           The name of the node to end.
    * @param    uri
    *           The URI namespace of the node to end.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical endElement(String name, String uri)
   {
      return endElement(new character(name), new character(uri));
   }

   /**
    * Ends an XML node of the given name in a XML document associated with SAX-Writer object.
    * 
    * @param    name
    *           The name of the node to end.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical endElement(String name)
   {
      return endElement(new character(name), new character());
   }
   
   /**
    * Ends an XML node of the given name in a XML document associated with SAX-Writer object.
    * 
    * @param    name
    *           The name of the node to end.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical endElement(Text name)
   {
      return endElement(name, new character());
   }
   
   /**
    * Specifies the output destination of the XML document to be created by a SAX-Writer object.
    * 
    * @param    mode
    *           The type of the destination to write to. Can be 'FILE', 'STREAM', 'MEMPTR', 
    *           'STREAM-HANDLE' or 'LONGCHAR'.
    * @param    destination
    *           The appropriate object to write.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical setOutputDestination(String mode, Object destination)
   {
      return setOutputDestination(new character(mode), destination);
   }

   /**
    * Specifies the output destination of the XML document to be created by a SAX-Writer object.
    * 
    * @param    mode
    *           The type of the destination to write to. Can be 'FILE', 'STREAM', 'MEMPTR', 
    *           'STREAM-HANDLE' or 'LONGCHAR'.
    * @param    destination
    *           The appropriate object to write.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical setOutputDestination(character mode, Object destination)
   {
      if (!WriteStatus.nonWritableStatuses.contains(writeStatus))
      {
         invalidStatusAttributeError("SET-OUTPUT-DESTINATION", writeStatus);
         return new logical(false);
      }
      
      final String writeMode;
      if (mode.isUnknown())
      {
         writeMode = "file";
      }
      else
      {
         writeMode = mode.getValue();
      }
      
      if ("file".equalsIgnoreCase(writeMode))
      {
         String fileName = null;
         if (destination instanceof String)
         {
            fileName = (String) destination;
         }
         else if (destination instanceof Text)
         {
            fileName = ((Text) destination).getValue();
         }
         else
         {
            String msg = "The SET-OUTPUT-DESTINATION attribute on the SAX-WRITER widget has " +
                         "invalid arguments";
            ErrorManager.recordOrShowError(4065, msg, false, true);
            return new logical(false);
         }
         
         outputWrapper = new FileOutputStreamWrapper(fileName);
      }
      else if ("stream".equalsIgnoreCase(writeMode))
      {
         LOG.warning("Stream is not supported");
         return new logical(false);
      }
      else if ("memptr".equalsIgnoreCase(writeMode))
      {
         outputWrapper = new MemptrOutputStream((memptr) destination);
      }
      else if ("stream-handle".equalsIgnoreCase(writeMode))
      {
         LOG.warning("Stream-handle is not supported");
         return new logical(false);
      }
      else if ("longchar".equalsIgnoreCase(writeMode))
      {
         outputWrapper = new LongcharOutputStream((longchar) destination);
      }
      else
      {
         invalidReadWriteModeError("SET-OUTPUT-DESTINATION");
         return new logical(false);
      }

      return new logical(true);
   }

   /**
    * Creates the XML document with the prolog information.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical startDocument()
   {
      if (!WriteStatus.nonWritableStatuses.contains(writeStatus))
      {
         invalidStatusMethodError("START-DOCUMENT", writeStatus);
         return new logical(false);
      }

      if (outputWrapper == null)
      {
         String msg = "START-DOCUMENT was unable to open the output destination. " +
                      "No output destination was specified";
         ErrorManager.recordOrShowError(14610, msg, false, false, false);
      }

      XMLOutputFactory2 output = (XMLOutputFactory2) XMLOutputFactory2.newFactory();
      output.configureForSpeed();
      output.setProperty(WstxOutputProperties.P_OUTPUT_VALIDATE_STRUCTURE, false);
      output.setProperty(WstxOutputProperties.P_AUTOMATIC_END_ELEMENTS, false);
      output.setProperty(WstxOutputFactory.P_AUTOMATIC_EMPTY_ELEMENTS, false);
      output.setProperty("javax.xml.stream.isRepairingNamespaces", true);
      
      try
      {
         writer = output.createXMLStreamWriter(outputWrapper);
         if (formatted)
         {
            writer = new IndentingXMLStreamWriter(writer) 
            {
               int depth = 0;

               @Override
               protected void beforeEndElement()
               {
                  if (depth == 1 && writeStatus == WriteStatus.SAX_WRITE_TAG)
                  {
                     writeLn();
                  }
                  super.beforeEndElement();
               }

               @Override
               protected void afterEndElement()
               {
                  super.afterEndElement();
                  if (--depth == 0)
                  {
                     writeLn();
                  }
               }
               
               @Override
               protected void afterStartElement()
               {
                  super.afterStartElement();
                  depth++;
               }
               
               protected void writeLn()
               {
                  try
                  {
                     writeNewLine(0);
                  }
                  catch (XMLStreamException ignore)
                  {
                  }
               }
            };
         }
         
         nscontext = new ScopedNamespaceContext();
         nscontext.startElement();
         writer.setNamespaceContext(nscontext);
      }
      catch (XMLStreamException ignored)
      {
         writerOutputError("START-DOCUMENT");
         return new logical(false);
      }

      if (!fragment)
      {
         try
         {
            writeXMLDeclaration(writer, version, encoding, standalone == null ? null : standalone);
         }
         catch (XMLStreamException ignored) {
            writerOutputError("START-DOCUMENT");
            return new logical(false);
         }
      }
      writeStatus = WriteStatus.SAX_WRITE_BEGIN;
      
      return new logical(true);
   }

   /**
    * Starts the XML node according to the specified name, namespace URI and handle of the SAX
    * attribute object.
    * 
    * @param    name
    *           The name of the element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical startElement(Text name)
   {
      return startElement(name, new character(), null);
   }

   /**
    * Starts the XML node according to the specified name, namespace URI and handle of the SAX
    * attribute object.
    * 
    * @param    name
    *           The name of the element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical startElement(String name)
   {
      return startElement(new character(name), new character(), null);
   }

   /**
    * Starts the XML node according to the specified name, namespace URI and handle of the SAX
    * attribute object.
    * 
    * @param    name
    *           The name of the element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical startElement(Text name, handle handle)
   {
      return startElement(name, new character(), handle);
   }

   /**
    * Starts the XML node according to the specified name, namespace URI and handle of the SAX
    * attribute object.
    * 
    * @param    name
    *           The name of the element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical startElement(String name, handle handle)
   {
      return startElement(new character(name), new character(), handle);
   }

   /**
    * Starts the XML node according to the specified name, namespace URI and handle of the SAX
    * attribute object.
    * 
    * @param    name
    *           The name of the element.
    * @param    uri
    *           The namespace URI of the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical startElement(Text name, Text uri)
   {
      return startElement(new character(name), uri, null);
   }

   /**
    * Starts the XML node according to the specified name, namespace URI and handle of the SAX
    * attribute object.
    * 
    * @param    name
    *           The name of the element.
    * @param    uri
    *           The namespace URI of the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical startElement(String name, Text uri)
   {
      return startElement(new character(name), uri, null);
   }

   /**
    * Starts the XML node according to the specified name, namespace URI and handle of the SAX
    * attribute object.
    * 
    * @param    name
    *           The name of the element.
    * @param    uri
    *           The namespace URI of the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical startElement(Text name, String uri)
   {
      return startElement(name, new character(uri), null);
   }

   /**
    * Starts the XML node according to the specified name, namespace URI and handle of the SAX
    * attribute object.
    * 
    * @param    name
    *           The name of the element.
    * @param    uri
    *           The namespace URI of the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical startElement(String name, String uri)
   {
      return startElement(new character(name), new character(uri), null);
   }

   /**
    * Starts the XML node according to the specified name, namespace URI and handle of the SAX
    * attribute object.
    * 
    * @param    name
    *           The name of the element.
    * @param    uri
    *           The namespace URI of the given element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical startElement(String name, Text uri, handle handle)
   {
      return startElement(new character(name), uri, handle);
   }

   /**
    * Starts the XML node according to the specified name, namespace URI and handle of the SAX
    * attribute object.
    * 
    * @param    name
    *           The name of the element.
    * @param    uri
    *           The namespace URI of the given element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical startElement(Text name, String uri, handle handle)
   {
      return startElement(name, new character(uri), handle);
   }

   /**
    * Starts the XML node according to the specified name, namespace URI and handle of the SAX
    * attribute object.
    * 
    * @param    name
    *           The name of the element.
    * @param    uri
    *           The namespace URI of the given element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical startElement(String name, String uri, handle handle)
   {
      return startElement(new character(name), new character(uri), handle);
   }

   /**
    * Adding the single attribute to the start tag in the XML document if applied for SAX writer
    * object. For SAX attributes object inserts attribute and its name into SAX attributes object.
    *
    * @param    name
    *           The attribute name to insert.
    * @param    value
    *           The attribute value to insert.
    * @param    uri
    *           The URI of the attribute to insert or '?' for unknown value.
    *
    * @return The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical insertAttribute(Text name, Text value, Text uri)
   {
      if (!BaseDataType.elementsOfType(character.class, uri, name, value))
      {
         invalidArgumentError("INSERT-ATTRIBUTE");
         return new logical(false);
      }

      if (name.isUnknown() || value.isUnknown())
      {
         invalidArgumentError("INSERT-ATTRIBUTE");
         return new logical(false);
      }

      try
      {
         if (uri.isUnknown())
         {
            String attr = name.toStringMessage();
            if (attr.startsWith("xmlns:"))
            {
               String xmlns = attr.substring(attr.indexOf(':') + 1);
               nscontext.setPrefix(xmlns, value.toStringMessage());
            }
            writer.writeAttribute(attr, value.toStringMessage());
         }
         else
         {
            writer.writeAttribute(uri.toStringMessage(),
                                   name.toStringMessage(),
                                   value.toStringMessage());
         }
      }
      catch (XMLStreamException ignored)
      {
         writerOutputError("INSERT-ATTRIBUTE");
         return new logical(false);
      }

      return new logical(true);
   }

   /**
    * Starts the XML node according to the specified name, namespace URI and handle of the SAX
    * attribute object.
    * 
    * @param    name
    *           The name of the element.
    * @param    uri
    *           The namespace URI of the given element.
    * @param    attr
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical startElement(Text name, Text uri, handle attr)
   {
      if (!BaseDataType.elementsOfType(character.class, uri, name))
      {
         invalidArgumentError("START-ELEMENT");
         return new logical(false);
      }

      if (!WriteStatus.writableStatuses.contains(writeStatus))
      {
         invalidStatusMethodError("START-ELEMENT", writeStatus);
         return new logical(false);
      }

      if (name.isUnknown())
      {
         invalidArgumentError("START-ELEMENT");
         return new logical(false);
      }
      if (attr != null && !attr.isUnknown() && !handle.isHandleTypeOf(attr, SaxAttributes.class))
      {
         invalidArgumentError("START-ELEMENT");
         return new logical(false);
      }
      try
      {
         String uriStr = uri.isUnknown() ? "" : uri.toStringMessage();
         String prefix = nscontext.getPrefix(uriStr);
         if (prefix == null)
         {
            writer.setDefaultNamespace(uriStr);
            writer.writeStartElement(uriStr, name.toStringMessage());
         }
         else
         {
            writer.writeStartElement(prefix, name.toStringMessage(), uriStr);
         }
         writeStatus = WriteStatus.SAX_WRITE_TAG;
         nscontext.startElement();

         if (attr == null || attr.isUnknown())
         {
            return new logical(true);
         }

         Attributes attributes = ((SaxAttributesImpl) attr.getResource()).getAttributes();
         for (int i = 0; i < attributes.getLength(); i++)
         {
            logical res = insertAttribute(attributes.getLocalName(i), attributes.getValue(i));
            if (!res.booleanValue())
            {
               return res;
            }
         }
      }
      catch (XMLStreamException ignored)
      {
         writerOutputError("WRITE-ELEMENT");
         return new logical(false);
      }

      return new logical(true);
   }

   /**
    * Adds CDATA block to the XML document crating by SAX-Writer object.
    * 
    * @param    cdataBlock
    *           The data to be written with CDATA block.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeCdata(String cdataBlock)
   {
      return writeCdata(new character(cdataBlock));
   }

   /**
    * Adds CDATA block to the XML document crating by SAX-Writer object.
    * 
    * @param    cdataBlock
    *           The data to be written with CDATA block.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeCdata(Text cdataBlock)
   {
      if (!WriteStatus.writableStatuses.contains(writeStatus))
      {
         invalidStatusMethodError("WRITE-CDATA", writeStatus);
         return new logical(false);
      }

      if (cdataBlock.isUnknown())
      {
         invalidArgumentError("WRITE-CDATA");
         return new logical(false);
      }

      try
      {
         writer.writeCData(cdataBlock.toStringMessage());
      }
      catch (XMLStreamException ignored)
      {
         writerOutputError("WRITE-CDATA");
         return new logical(false);
      }

      return new logical(true);
   }

   /**
    * Adds character data to the XML document crating by SAX-Writer object.
    * 
    * @param    chardata
    *           The character or longchar data to be written.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeCharacters(String chardata)
   {
      return writeCharacters(new character(chardata));
   }

   /**
    * Adds character data to the XML document crating by SAX-Writer object.
    * 
    * @param    chardata
    *           The character or longchar data to be written.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeCharacters(Text chardata)
   {
      if (!WriteStatus.writableStatuses.contains(writeStatus))
      {
         invalidStatusMethodError("WRITE-CHARACTERS", writeStatus);
         return new logical(false);
      }

      if (chardata.isUnknown())
      {
         invalidArgumentError("WRITE-CHARACTERS");
         return new logical(false);
      }

      try
      {
         writer.writeCharacters(chardata.toStringMessage());
         writeStatus = WriteStatus.SAX_WRITE_CONTENT;
      }
      catch (XMLStreamException ignored)
      {
         writerOutputError("WRITE-CHARACTERS");
         return new logical(false);
      }

      return new logical(true);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(Text name, Text chardata)
   {
      return writeDataElement(name, chardata, new character(), null);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(String name, Text chardata)
   {
      return writeDataElement(new character(name), chardata, new character(), null);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(Text name, String chardata)
   {
      return writeDataElement(name, new character(chardata), new character(), null);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(String name, String chardata)
   {
      return writeDataElement(new character(name), new character(chardata), new character(),
                              null);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(Text name, Text chardata, Text uri)
   {
      return writeDataElement(name, chardata, uri, null);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(String name, Text chardata, Text uri)
   {
      return writeDataElement(new character(name), chardata, uri, null);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(Text name, String chardata, Text uri)
   {
      return writeDataElement(name, new character(chardata), uri, null);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(String name, String chardata, Text uri)
   {
      return writeDataElement(new character(name), new character(chardata), uri, null);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(Text name, Text chardata, String uri)
   {
      return writeDataElement(name, chardata, new character(uri), null);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(String name, Text chardata, String uri)
   {
      return writeDataElement(new character(name), chardata, new character(uri), null);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(Text name, String chardata, String uri)
   {
      return writeDataElement(name, new character(chardata), new character(uri), null);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(String name, String chardata, String uri)
   {
      return writeDataElement(new character(name), new character(chardata),
                              new character(uri), null);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(Text name, Text chardata, handle handle)
   {
      return writeDataElement(name, chardata, new character(), handle);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(String name, Text chardata, handle handle)
   {
      return writeDataElement(new character(name), chardata, new character(), handle);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(Text name, String chardata, handle handle)
   {
      return writeDataElement(name, new character(chardata), new character(), handle);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(String name, String chardata, handle handle)
   {
      return writeDataElement(new character(name), new character(chardata), new character(),
                              handle);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(String name, Text chardata, Text uri, handle handle)
   {
      return writeDataElement(new character(name), chardata, uri, handle);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(Text name, String chardata, Text uri, handle handle)
   {
      return writeDataElement(name, new character(chardata), uri, handle);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(Text name, Text chardata, String uri, handle handle)
   {
      return writeDataElement(name, chardata, new character(uri), handle);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(String name, String chardata, Text uri, handle handle)
   {
      return writeDataElement(new character(name), new character(chardata), uri, handle);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(String name, Text chardata, String uri, handle handle)
   {
      return writeDataElement(new character(name), chardata, new character(uri), handle);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(Text name, String chardata, String uri, handle handle)
   {
      return writeDataElement(name, new character(chardata), new character(uri), handle);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * @param    handle
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(String name, String chardata, String uri, handle handle)
   {
      return writeDataElement(new character(name), new character(chardata),
                              new character(uri), handle);
   }

   /**
    * Creates complete XML node with a given SAX-Writer object.
    * 
    * @param    name
    *           The name of the element.
    * @param    chardata
    *           The XML text to write for the given element.
    * @param    uri
    *           The namespace URI of the given element.
    * @param    attr
    *           The handle of the SAX-Attribute object to be added into XML document.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeDataElement(Text name, Text chardata, Text uri, handle attr)
   {
      if (!BaseDataType.elementsOfType(character.class, uri, name))
      {
         invalidArgumentError("WRITE-DATA-ELEMENT");
         return new logical(false);
      }

      if (!WriteStatus.writableStatuses.contains(writeStatus))
      {
         invalidStatusMethodError("WRITE-DATA-ELEMENT", writeStatus);
         return new logical(false);
      }

      if (name.isUnknown())
      {
         invalidArgumentError("WRITE-DATA-ELEMENT");
         return new logical(false);
      }

      if (attr != null && !attr.isUnknown() && !handle.isHandleTypeOf(attr, SaxAttributes.class))
      {
         invalidArgumentError("WRITE-DATA-ELEMENT");
         return new logical(false);
      }

      try
      {
         String uriStr = uri.isUnknown() ? "" : uri.toStringMessage();
         String prefix = nscontext.getPrefix(uriStr);
         if (prefix != null)
         {
            writer.writeStartElement(prefix, name.toStringMessage(), uriStr);
         }
         else
         {
            // for this node, ensure the uri is the default namespace, so it will not use a prefix
            writer.setDefaultNamespace(uriStr);
            writer.writeStartElement(uriStr, name.toStringMessage());
            writer.setDefaultNamespace(null);
         }
         writeStatus = WriteStatus.SAX_WRITE_TAG;

         if (attr != null)
         {
            Attributes attributes = ((SaxAttributesImpl) attr.getResource()).getAttributes();
            for(int i = 0; i < attributes.getLength(); i++)
            {
               logical res = insertAttribute(attributes.getLocalName(i), attributes.getValue(i));
               if (!res.booleanValue())
               {
                  return res;
               }
            }
         }

         if (!chardata.isUnknown())
         {
            writer.writeCharacters(chardata.toStringMessage());
         }

         writer.writeEndElement();
         writeStatus = WriteStatus.SAX_WRITE_ELEMENT;
      }
      catch (XMLStreamException ignored)
      {
         writerOutputError("WRITE-EMPTY-ELEMENT");
         return new logical(false);
      }

      return new logical(true);
   }

   /**
    * Adds character data to the XML document crating by SAX-Writer object.
    * 
    * @param    chardata
    *           The character or longchar data to be written.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeFragment(String chardata)
   {
      return writeFragment(new character(chardata));
   }

   /**
    * Adds character data to the XML document crating by SAX-Writer object.
    * 
    * @param    chardata
    *           The character or longchar data to be written.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeFragment(Text chardata)
   {
      if (!WriteStatus.writableStatuses.contains(writeStatus))
      {
         invalidStatusMethodError("WRITE-FRAGMENT", writeStatus);
         return new logical(false);
      }

      if (chardata.isUnknown())
      {
         invalidArgumentError("WRITE-FRAGMENT");
         return new logical(false);
      }

      String content = chardata.toStringMessage();

      return writeCharacterData(content);
   }

   /**
    * Adds character data to the XML document crating by SAX-Writer object.
    *
    * @param    content
    *           string to write.
    *
    * @return   {@code true} if success, {@code false} otherwise.
    */
   private logical writeCharacterData(String content)
   {
      try
      {
         writer.writeCharacters(content);
         writeStatus = WriteStatus.SAX_WRITE_CONTENT;
      }
      catch (XMLStreamException ignored)
      {
         writerOutputError("WRITE-FRAGMENT");
         return new logical(false);
      }
      return new logical(true);
   }

   /**
    * Adds character data to the XML document crating by SAX-Writer object.
    * 
    * @param    xhandle
    *           The valid X-Nodereference handle containing XML text.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeFragment(handle xhandle)
   {
      if (!WriteStatus.writableStatuses.contains(writeStatus))
      {
         invalidStatusMethodError("WRITE-FRAGMENT", writeStatus);
         return new logical(false);
      }

      if (!XEntityImpl.isXNodeHandle(xhandle) || !XEntityImpl.isXNodeHandleInitialized(xhandle))
      {
         invalidArgumentError("WRITE-FRAGMENT");
         return new logical(false);
      }

      Node node = ((XEntityImpl) xhandle.get()).getNode();

      String nodeXML;
      try
      {
         nodeXML = serializeNodeToString(node);
      }
      catch (TransformerException ignored)
      {
         invalidArgumentError("WRITE-FRAGMENT");
         return new logical(false);
      }


      return writeCharacterData(nodeXML);
   }
   
   /**
    * Closes the open stream and resets the SAX-Writer object to the default state.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical reset()
   {
      if (outputWrapper != null)
      {
         try
         {
            outputWrapper.close();
         }
         catch (IOException ignored)
         {
            // no-op
         }
      }
      writeStatus = WriteStatus.SAX_WRITE_IDLE;
      return new logical(true);
   }

   /**
    * Adds comment to the XML document crating by SAX-Writer object.
    * 
    * @param    comment
    *           The character or longchar text comment to be written.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeComment(String comment)
   {
      return writeComment(new character(comment));
   }

   /**
    * Adds comment to the XML document crating by SAX-Writer object.
    * 
    * @param    comment
    *           The character or longchar text comment to be written.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeComment(Text comment)
   {
      if (!WriteStatus.writableStatuses.contains(writeStatus))
      {
         invalidStatusMethodError("WRITE-COMMENT", writeStatus);
         return new logical(false);
      }

      if (comment.isUnknown())
      {
         invalidArgumentError("WRITE-COMMENT");
         return new logical(false);
      }

      try
      {
         writer.writeComment(comment.toStringMessage());
      }
      catch (XMLStreamException ignored)
      {
         writerOutputError("WRITE-COMMENT");
         return new logical(false);
      }

      return new logical(true);
   }

   /**
    * Creates an empty node in a given SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar element name to be written.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeEmptyElement(Text name)
   {
      return writeEmptyElement(name, new character(), null);
   }

   /**
    * Creates an empty node in a given SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar element name to be written.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeEmptyElement(String name)
   {
      return writeEmptyElement(new character(name), new character(), null);
   }

   /**
    * Creates an empty node in a given SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar element name to be written.
    * @param    uri
    *           The character or longchar element URI to be written.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeEmptyElement(Text name, Text uri)
   {
      return writeEmptyElement(name, uri, null);
   }

   /**
    * Creates an empty node in a given SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar element name to be written.
    * @param    uri
    *           The character or longchar element URI to be written.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeEmptyElement(String name, Text uri)
   {
      return writeEmptyElement(new character(name), uri, null);
   }

   /**
    * Creates an empty node in a given SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar element name to be written.
    * @param    uri
    *           The character or longchar element URI to be written.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeEmptyElement(Text name, String uri)
   {
      return writeEmptyElement(name, new character(uri), null);
   }

   /**
    * Creates an empty node in a given SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar element name to be written.
    * @param    uri
    *           The character or longchar element URI to be written.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeEmptyElement(String name, String uri)
   {
      return writeEmptyElement(new character(name), new character(uri), null);
   }

   /**
    * Creates an empty node in a given SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar element name to be written.
    * @param    attr
    *           The handle of the SAX-Attributes object to be used.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeEmptyElement(Text name, handle attr)
   {
      return writeEmptyElement(name, new character(), attr);
   }

   /**
    * Creates an empty node in a given SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar element name to be written.
    * @param    attr
    *           The handle of the SAX-Attributes object to be used.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeEmptyElement(String name, handle attr)
   {
      return writeEmptyElement(new character(name), new character(), attr);
   }

   /**
    * Creates an empty node in a given SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar element name to be written.
    * @param    uri
    *           The character or longchar element URI to be written.
    * @param    attr
    *           The handle of the SAX-Attributes object to be used.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeEmptyElement(String name, Text uri, handle attr)
   {
      return writeEmptyElement(new character(name), uri, attr);
   }

   /**
    * Creates an empty node in a given SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar element name to be written.
    * @param    uri
    *           The character or longchar element URI to be written.
    * @param    attr
    *           The handle of the SAX-Attributes object to be used.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeEmptyElement(Text name, String uri, handle attr)
   {
      return writeEmptyElement(name, new character(uri), attr);
   }

   /**
    * Creates an empty node in a given SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar element name to be written.
    * @param    uri
    *           The character or longchar element URI to be written.
    * @param    attr
    *           The handle of the SAX-Attributes object to be used.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeEmptyElement(String name, String uri, handle attr)
   {
      return writeEmptyElement(new character(name), new character(uri), attr);
   }

   /**
    * Creates an empty node in a given SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar element name to be written.
    * @param    uri
    *           The character or longchar element URI to be written.
    * @param    attr
    *           The handle of the SAX-Attributes object to be used.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeEmptyElement(Text name, Text uri, handle attr)
   {
      if (!BaseDataType.elementsOfType(character.class, uri, name))
      {
         invalidArgumentError("WRITE-EMPTY-ELEMENT");
         return new logical(false);
      }

      if (!WriteStatus.writableStatuses.contains(writeStatus))
      {
         invalidStatusMethodError("WRITE-EMPTY-ELEMENT", writeStatus);
         return new logical(false);
      }

      if (name.isUnknown())
      {
         invalidArgumentError("WRITE-EMPTY-ELEMENT");
         return new logical(false);
      }

      if (attr != null && !attr.isUnknown() && !handle.isHandleTypeOf(attr, SaxAttributes.class))
      {
         invalidArgumentError("WRITE-EMPTY-ELEMENT");
         return new logical(false);
      }

      try
      {
         String uriStr = uri.isUnknown() ? null : uri.toStringMessage();

         writer.writeEmptyElement(uriStr, name.toStringMessage());
         writeStatus = WriteStatus.SAX_WRITE_TAG;

         if (attr != null)
         {
            Attributes attributes = ((SaxAttributesImpl) attr.getResource()).getAttributes();
            for (int i = 0; i < attributes.getLength(); i++)
            {
               logical res = insertAttribute(attributes.getLocalName(i), attributes.getValue(i));
               if (!res.booleanValue())
               {
                  return res;
               }
            }
         }
      }
      catch (XMLStreamException ignored)
      {
         writerOutputError("WRITE-EMPTY-ELEMENT");
         return new logical(false);
      }

      return new logical(true);
   }

   /**
    * Adds an entity referenc to the XML document associated with given SAX-Writer object.
    * 
    * @param    value
    *           The character or longchar value to be written.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeEntityRef(String value)
   {
      return writeEntityRef(new character(value));
   }

   /**
    * Adds an entity referenc to the XML document associated with given SAX-Writer object.
    * 
    * @param    value
    *           The character or longchar value to be written.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeEntityRef(Text value)
   {
      if (!WriteStatus.writableStatuses.contains(writeStatus))
      {
         invalidStatusMethodError("WRITE-ENTITY-REF", writeStatus);
         return new logical(false);
      }

      if (value.isUnknown())
      {
         invalidArgumentError("WRITE-ENTITY-REF");
         return new logical(false);
      }

      try
      {
         writer.writeEntityRef(value.toStringMessage());
      }
      catch (XMLStreamException ignored)
      {
         writerOutputError("WRITE-ENTITY-REF");
         return new logical(false);
      }
      return new logical(true);
   }

   /**
    * Adds an external DTD reference to the XML document associated with a SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar name of the document root node.
    * @param    systemId
    *           The character or longchar system ID of the DTD.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeExternalDtd(Text name, Text systemId)
   {
      return writeExternalDtd(name, systemId, new character());
   }

   /**
    * Adds an external DTD reference to the XML document associated with a SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar name of the document root node.
    * @param    systemId
    *           The character or longchar system ID of the DTD.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeExternalDtd(String name, Text systemId)
   {
      return writeExternalDtd(new character(name), systemId, new character());
   }

   /**
    * Adds an external DTD reference to the XML document associated with a SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar name of the document root node.
    * @param    systemId
    *           The character or longchar system ID of the DTD.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeExternalDtd(Text name, String systemId)
   {
      return writeExternalDtd(name, new character(systemId), new character());
   }

   /**
    * Adds an external DTD reference to the XML document associated with a SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar name of the document root node.
    * @param    systemId
    *           The character or longchar system ID of the DTD.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeExternalDtd(String name, String systemId)
   {
      return writeExternalDtd(new character(name), new character(systemId), new character());
   }

   /**
    * Adds an external DTD reference to the XML document associated with a SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar name of the document root node.
    * @param    systemId
    *           The character or longchar system ID of the DTD.
    * @param    publicId
    *           The character or longchar public ID of the DTD.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeExternalDtd(String name, Text systemId, Text publicId)
   {
      return writeExternalDtd(new character(name), systemId, publicId);
   }

   /**
    * Adds an external DTD reference to the XML document associated with a SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar name of the document root node.
    * @param    systemId
    *           The character or longchar system ID of the DTD.
    * @param    publicId
    *           The character or longchar public ID of the DTD.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeExternalDtd(Text name, String systemId, Text publicId)
   {
      return writeExternalDtd(name, new character(systemId), publicId);
   }

   /**
    * Adds an external DTD reference to the XML document associated with a SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar name of the document root node.
    * @param    systemId
    *           The character or longchar system ID of the DTD.
    * @param    publicId
    *           The character or longchar public ID of the DTD.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeExternalDtd(String name, String systemId, Text publicId)
   {
      return writeExternalDtd(new character(name), new character(systemId), publicId);
   }

   /**
    * Adds an external DTD reference to the XML document associated with a SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar name of the document root node.
    * @param    systemId
    *           The character or longchar system ID of the DTD.
    * @param    publicId
    *           The character or longchar public ID of the DTD.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeExternalDtd(Text name, Text systemId, String publicId)
   {
      return writeExternalDtd(name, systemId, new character(publicId));
   }

   /**
    * Adds an external DTD reference to the XML document associated with a SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar name of the document root node.
    * @param    systemId
    *           The character or longchar system ID of the DTD.
    * @param    publicId
    *           The character or longchar public ID of the DTD.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeExternalDtd(String name, Text systemId, String publicId)
   {
      return writeExternalDtd(new character(name), systemId, new character(publicId));
   }

   /**
    * Adds an external DTD reference to the XML document associated with a SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar name of the document root node.
    * @param    systemId
    *           The character or longchar system ID of the DTD.
    * @param    publicId
    *           The character or longchar public ID of the DTD.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeExternalDtd(Text name, String systemId, String publicId)
   {
      return writeExternalDtd(name, new character(systemId), new character(publicId));
   }

   /**
    * Adds an external DTD reference to the XML document associated with a SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar name of the document root node.
    * @param    systemId
    *           The character or longchar system ID of the DTD.
    * @param    publicId
    *           The character or longchar public ID of the DTD.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeExternalDtd(String name, String systemId, String publicId)
   {
      return writeExternalDtd(new character(name), new character(systemId),
                              new character(publicId));
   }

   /**
    * Adds an external DTD reference to the XML document associated with a SAX-Writer object.
    * 
    * @param    name
    *           The character or longchar name of the document root node.
    * @param    systemId
    *           The character or longchar system ID of the DTD.
    * @param    publicId
    *           The character or longchar public ID of the DTD.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeExternalDtd(Text name, Text systemId, Text publicId)
   {
      if (writeStatus != WriteStatus.SAX_WRITE_BEGIN)
      {
         invalidStatusMethodError("WRITE-EXTERNAL-DTD", writeStatus);
         return new logical(false);
      }

      if (name.isUnknown())
      {
         invalidArgumentError("WRITE-EXTERNAL-DTD");
         return new logical(false);
      }

      if (systemId.isUnknown())
      {
         invalidArgumentError("WRITE-EXTERNAL-DTD");
         return new logical(false);
      }

      StringBuilder xmlDeclarationBuilder = new StringBuilder();
      xmlDeclarationBuilder.append("<!DOCTYPE ");
      xmlDeclarationBuilder.append(name.toStringMessage());
      xmlDeclarationBuilder.append(' ');
      xmlDeclarationBuilder.append(systemId.toStringMessage());
      if (!publicId.isUnknown())
      {
         xmlDeclarationBuilder.append(" \"");
         xmlDeclarationBuilder.append(publicId.toStringMessage());
         xmlDeclarationBuilder.append('"');
      }
      xmlDeclarationBuilder.append(">\n");

      try
      {
         writer.writeDTD(xmlDeclarationBuilder.toString());
      }
      catch (XMLStreamException ignored)
      {
         writerOutputError("WRITE-EXTERNAL-DTD");
         return new logical(false);
      }

      return new logical(true);
   }

   /**
    * Creates a processing instruction node in XML document for given SAX-Writer object.
    * 
    * @param    target
    *           The character or longchar target of the processing instruction.
    * @param    data
    *           The character or longchar data associated with the processing instruction.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeProcessingInstruction(String target, Text data)
   {
      return writeProcessingInstruction(new character(target), data);
   }

   /**
    * Creates a processing instruction node in XML document for given SAX-Writer object.
    * 
    * @param    target
    *           The character or longchar target of the processing instruction.
    * @param    data
    *           The character or longchar data associated with the processing instruction.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeProcessingInstruction(Text target, String data)
   {
      return writeProcessingInstruction(target, new character(data));
   }

   /**
    * Creates a processing instruction node in XML document for given SAX-Writer object.
    * 
    * @param    target
    *           The character or longchar target of the processing instruction.
    * @param    data
    *           The character or longchar data associated with the processing instruction.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeProcessingInstruction(String target, String data)
   {
      return writeProcessingInstruction(new character(target), new character(data));
   }

   /**
    * Creates a processing instruction node in XML document for given SAX-Writer object.
    * 
    * @param    target
    *           The character or longchar target of the processing instruction.
    * @param    data
    *           The character or longchar data associated with the processing instruction.
    * 
    * @return   The <code>true</code> in case of success <code>false</code> otherwise.
    */
   @Override
   public logical writeProcessingInstruction(Text target, Text data)
   {
      if (!WriteStatus.writableStatuses.contains(writeStatus))
      {
         invalidStatusMethodError("WRITE-PROCESSING-INSTRUCTION", writeStatus);
         return new logical(false);
      }

      if (target.isUnknown())
      {
         invalidArgumentError("WRITE-PROCESSING-INSTRUCTION");
         return new logical(false);
      }

      if (data.isUnknown())
      {
         invalidArgumentError("WRITE-PROCESSING-INSTRUCTION");
         return new logical(false);
      }

      try
      {
         writer.writeProcessingInstruction(target.toStringMessage(), data.toStringMessage());
      }
      catch (XMLStreamException ignored)
      {
         writerOutputError("WRITE-PROCESSING-INSTRUCTION");
         return new logical(false);
      }

      return new logical(true);
   }
   
   /**
    * Check if this resource supports the NAME attribute.
    * 
    * @return   Always <code>false</code>.
    */
   @Override
   protected boolean hasName()
   {
      return false;
   }

   /**
    * Delete the resource.
    *
    * @return   <code>true</code> if the resource was deleted.
    */
   @Override
   protected boolean resourceDelete()
   {
      if (writer != null)
      {
         try
         {
            writer.close();
         }
         catch (XMLStreamException e)
         {
            LOG.log(Level.SEVERE, "SaxWriterImpl", e);
         }
      }
      isValid = false;
      writer = null;
      nscontext = null;

      return true;
   }

   /**
    * This method is used to serialize Node from DOM to string.
    *
    * @param    node
    *           Node instance from DOM model.
    *
    * @return   Text representation of the node.
    *
    * @throws   TransformerFactoryConfigurationError
    *           If an error occurs writing the identifier.
    * @throws   TransformerException
    *           If an error occurs writing the identifier.
    */
   static String serializeNodeToString(Node node)
   throws TransformerFactoryConfigurationError,
          TransformerException
   {
      StreamResult xmlOutput = new StreamResult(new StringWriter());
      Transformer transformer = TransformerFactory.newInstance().newTransformer();
      transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
      transformer.transform(new DOMSource(node), xmlOutput);
      return xmlOutput.getWriter().toString();
   }

   /**
    * This method is used to write the XML document declaration at the beginning of an XML
    * document. This version is used when the standalone attribute is to be written as the
    * XMLStreamWriter provides no way for writing this attribute.
    *
    * @param    outputWriter
    *           XMLStreamWriter instance.
    * @param    xmlVersion
    *           Xml version which will specify in xml header.
    * @param    encodingName
    *           encoding which will specify in xml header.
    * @param    standalone
    *           standalone flag.
    *
    * @throws   XMLStreamException
    *           If an error occurs writing the identifier.
    */
   public static void writeXMLDeclaration(XMLStreamWriter outputWriter,
                                          String xmlVersion,
                                          String encodingName,
                                          Boolean standalone)
   throws XMLStreamException
   {
      if (xmlVersion == null || xmlVersion.trim().isEmpty())
      {
         xmlVersion = DEFAULT_XML_VERSION;
      }
      StringBuilder xmlDeclarationBuilder = new StringBuilder();
      xmlDeclarationBuilder.append("<?xml version=\"");
      xmlDeclarationBuilder.append(xmlVersion);
      xmlDeclarationBuilder.append('"');
      if (encodingName != null && !"".equals(encodingName))
      {
         xmlDeclarationBuilder.append(" encoding=\"");
         xmlDeclarationBuilder.append(encodingName);
         xmlDeclarationBuilder.append('"');
      }
      if (standalone != null)
      {
         xmlDeclarationBuilder.append(" standalone=\"");
         xmlDeclarationBuilder.append(standalone ? "yes" : "no");
         xmlDeclarationBuilder.append('"');
      }
      xmlDeclarationBuilder.append("?>");
      //Work around to avoid the angle brackets getting escaped.
      outputWriter.writeDTD(xmlDeclarationBuilder.toString());
   }

   /**
    * Special wrapper to wrap write to file in lazy mode. It's means that first try to write
    * will check if file is available.
    */
   private static class FileOutputStreamWrapper
   extends OutputStream
   {
      /** File name.*/
      private final String fileName;

      /** Lazy initialization flag.*/
      private volatile boolean isStarted;

      /** Buffered output Stream.*/
      private Stream stream;

      /**
       * Constructor accepting a file name, which will read after first call.
       *
       * @param    source
       *           A file name.
       */
      private FileOutputStreamWrapper(String source)
      {
         isStarted = false;
         fileName = source;
      }

      /**
       * Write one byte into the stream.
       * @param    b
       *           the data to write.
       * @throws   IOException
       */
      @Override
      public void write(int b)
      throws IOException
      {
         if (!isStarted)
         {
            init(true);
         }
         stream.writeByte((byte) b);
      }

      /**
       * Writes the entire contents of the specified byte array to this output stream.
       * 
       * @param    b
       *           The byte array to write.
       *
       * @throws   IOException
       *           if an I/O error occurs. In particular, an IOException may be
       *           thrown if the output stream has been closed.
       * @throws   NullPointerException   
       *           if the array is <code>null</code>. 
       */
      @Override
      public void write(byte[] b)
      throws IOException,
             NullPointerException
      {
         write(b, 0, b.length);
      }
      
      /**
       * Writes <code>len</code> bytes from the specified byte array starting
       * at offset <code>off</code> in this output stream. Element b[off] is
       * the first byte written and b[off+len-1] is the last byte written.
       * 
       * @param    b
       *           The array of bytes to write.
       * @param    off
       *           the start offset in the array.
       * @param    len
       *           the number of bytes to write.
       *
       * @throws   IOException
       *           if an I/O error occurs. In particular, an IOException may be
       *           thrown if the output stream has been closed.
       * @throws   NullPointerException
       *           if the array is <code>null</code>.
       * @throws   IndexOutOfBoundsException
       *           if the offset or length are negative, or if offset + length
       *           is larger than the length of the array.
       */
      @Override
      public void write(byte[] b, int off, int len)
      throws IOException,
             NullPointerException,
             IndexOutOfBoundsException
      {
         if (!isStarted)
         {
            init(true);
         }
         stream.write(b, off, len);
      }
      
      /**
       * Close current stream and reset state.
       */
      @Override
      public void close()
      throws IOException
      {
         if (stream != null)
         {
            stream.close();
            isStarted = false;
         }
      }

      /**
       * Initialization method which creates stream wrapper.
       *
       * @param    canWrite
       *           if {@code true} than file will open in read/write mode, otherwise only in
       *           read mode.
       *
       * @throws   IOException
       *           In case of I/O errors.
       */
      private void init(boolean canWrite)
      throws IOException
      {
         try
         {
            stream = StreamFactory.openFileStream(fileName, canWrite, false);
            if (stream == null)
            {
               throw new IOException("An exception occurred!");
            }
         }
         catch (ErrorConditionException e)
         {
            throw new IOException("An exception occurred!", e);
         }
         isStarted = true;
      }
   }

   /**
    * Special wrapper to wrap write to longchar in lazy mode. It's means that first try to write
    * will check if longchar is available.
    */
   private static class LongcharOutputStream
   extends OutputStream
   {
      /** A valid longchar object to write.*/
      private longchar lchar;

      /** Buffered output Stream.*/
      private StringWriter buffer = new StringWriter();

      /** Lazy initialization flag.*/
      private volatile boolean isStarted;

      /**
       * Constructor accepting a longchar, which will read after first call.
       *
       * @param    source
       *           A valid longchar object.
       */
      private LongcharOutputStream(longchar source)
      {
         lchar = source;
      }

      /**
       * Write one byte into the buffer.
       * @param    b
       *           the data to write.
       */
      @Override
      public void write(int b)
      throws IOException
      {
         if (!isStarted)
         {
            lchar.assign("");
            isStarted = true;
         }
         buffer.write(b);
      }

      /**
       * Flush data from internal buffer to longchar object.
       */
      @Override
      public void flush()
      throws IOException
      {
         String buf = buffer.getBuffer().toString();
         buffer.getBuffer().setLength(0);
         lchar.assign(TextOps.concat(lchar, buf));
      }

      /**
       * Close current stream and reset state.
       */
      @Override
      public void close()
      throws IOException
      {
         flush();
         buffer.close();
         isStarted = false;
      }
   }

   /**
    * Special wrapper to wrap write to memptr in lazy mode. It's means that first try to write
    * will check if memptr is available.
    */
   private static class MemptrOutputStream
   extends OutputStream
   {
      /** A valid memptr */
      private final memptr mptr;

      /** Current read cursor position, started from index 1.*/
      private final AtomicLong position = new AtomicLong();

      /** Lazy initialization flag.*/
      private volatile boolean isStarted = false;

      /** Lazy initialization flag.*/
      private long totalSize = 0;

      /**
       * Constructor accepting a memptr to write.
       *
       * @param    source
       *           A valid memptr object.
       */
      private MemptrOutputStream(memptr source)
      {
         mptr = source;
      }

      /**
       * Write one byte into memptr. If capacity of memptr is not enough then expand capacity.
       * @param    b
       *           the data to write.
       * @throws   IOException
       *           wrap any exception from memptr into IO exception.
       */
      @Override
      public void write(int b)
      throws IOException
      {
         if (!isStarted)
         {
            mptr.setLength(0);  //reset memptr
            position.set(1);
            totalSize = mptr.length().longValue();
            isStarted = true;
         }
         ensureCapacity(1);
         try
         {
            mptr.setByte(b, position.getAndIncrement());
         }
         catch (ErrorConditionException e)
         {
            throw new IOException(e);
         }
      }

      /**
       * Wrap super method to ensure that memptr has enough length and reduce number of calls to
       * expand capacity.
       *
       * @param    b
       *           the data.
       * @param    off
       *           the start offset in the data.
       * @param    len
       *           the number of bytes to write.
       * @throws   IOException
       */
      @Override
      public void write(byte[] b, int off, int len)
      throws IOException
      {
         if (!isStarted)
         {
            mptr.setLength(0);  //reset memptr
            position.set(1);
            totalSize = mptr.length().longValue();
            isStarted = true;
         }
         ensureCapacity(len);
         super.write(b, off, len);
      }

      /**
       * Close current stream and reset state.
       */
      @Override
      public void close()
      throws IOException
      {
         isStarted = false;
      }

      /**
       * Check capacity of memptr, if capacity is less then needed, then increase capacity.
       * @param    len
       *           Count of bytes to ensure capacity.
       */
      private void ensureCapacity(int len)
      {
         long freeSpace = totalSize - position.intValue();
         if (len > freeSpace)
         {
            totalSize = mptr.length().longValue() + len;
            mptr.setLength(totalSize);
         }
      }
   }
   
   /**
    * Track the namespaces (prefix and uri) for each XML element scope.
    */
   private static class ScopedNamespaceContext 
   implements NamespaceContext
   {
      /** Map of prefixes to URIs. */
      private Map<String, String> prefixToUri = null;
      
      /** The context stack of namespaces for each XML element. */
      private Deque<Map<String, String>> scopes = new ArrayDeque<>();
      
      /**
       * Notification a new XML element or document starts.
       */
      public void startElement()
      {
         scopes.push(prefixToUri = new HashMap<>());
      }
      
      /**
       * Notification the XML document or element ends.
       */
      public void endElement()
      {
         prefixToUri = scopes.pop();
      }
      
      /**
       * Register the given prefix for the given uri.
       * 
       * @param    prefix
       *           The namespace prefix to use.
       * @param    uri
       *           The URI to use.
       */
      public void setPrefix(String prefix, String uri)
      {
         prefixToUri.put(prefix, uri);
      }
      
      /**
       * Get Namespace URI bound to a prefix in the current scope.
       * 
       * @param    prefix
       *           The prefix.
       *
       * @return   The namespace URI or <code>null</code> if not found..
       */
      @Override
      public String getNamespaceURI(String prefix)
      {
         String uri = prefixToUri.get(prefix);
         if (uri != null)
         {
            return uri;
         }
         
         for (Map<String, String> p : scopes)
         {
            uri = p.get(prefix);
            if (uri != null)
            {
               return uri;
            }
         }
         
         return null;
      }

      /**
       * Get prefix bound to Namespace URI in the current scope.
       * 
       * @param    namespaceURI
       *           The namespace URI.
       *           
       * @return   The prefix or <code>null</code> if not found.
       */
      @Override
      public String getPrefix(String namespaceURI)
      {
         BiFunction<Map<String, String>, String, String> findPrefix = (m, uri) ->
         {
            for (Map.Entry<String, String> entry : m.entrySet())
            {
               if (entry.getValue().equals(uri))
               {
                  return entry.getKey();
               }
            }
            
            return null;
         };
         
         String prefix = findPrefix.apply(prefixToUri, namespaceURI);
         if (prefix != null)
         {
            return prefix;
         }
         
         for (Map<String, String> p : scopes)
         {
            prefix = findPrefix.apply(p, namespaceURI);
            if (prefix != null)
            {
               return prefix;
            }
         }
         
         return null;
      }

      /**
       * Get all the prefixes associated with the specified URI.
       * 
       * @param    namespaceURI
       *           The namespace URI.
       * 
       * @return   An iterator for all prefixes for this URI.
       */
      @Override
      public Iterator<String> getPrefixes(String namespaceURI)
      {
         List<String> ret = new ArrayList<>(2);
         BiConsumer<Map<String, String>, String> findPrefix = (m, uri) ->
         {
            for (Map.Entry<String, String> entry : m.entrySet())
            {
               if (entry.getValue().equals(uri))
               {
                  ret.add(entry.getKey());
               }
            }
         };
         
         findPrefix.accept(prefixToUri, namespaceURI);

         for (Map<String, String> p : scopes)
         {
            findPrefix.accept(p, namespaceURI);
         }

         return ret.iterator();
      }
   }
}