public byte[] toWffBMBytes(final Charset charset) {

        final byte[] encodedBytesForAtChar = "@".getBytes(charset);
        final byte[] encodedByesForHashChar = "#".getBytes(charset);

        final Lock lock = sharedObject.getLock(ACCESS_OBJECT).readLock();
        try {
            lock.lock();

            final Deque<NameValue> nameValues = new ArrayDeque<>();

            // ArrayDeque give better performance than Stack, LinkedList
            final Deque<Set<AbstractHtml>> childrenStack = new ArrayDeque<>();
            // passed 2 instead of 1 because the load factor is 0.75f
            final HashSet<AbstractHtml> initialSet = new HashSet<>(2);
            initialSet.add(this);
            childrenStack.push(initialSet);

            Set<AbstractHtml> children;
            while ((children = childrenStack.poll()) != null) {

                for (final AbstractHtml tag : children) {

                    final String nodeName = tag.getTagName();

                    if (nodeName != null && !nodeName.isEmpty()) {

                        final NameValue nameValue = new NameValue();

                        final byte[] nodeNameBytes = nodeName.getBytes(charset);
                        final byte[][] wffAttributeBytes = AttributeUtil
                                .getWffAttributeBytes(charset, tag.attributes);

                        final int parentWffSlotIndex = tag.parent == null ? -1
                                : tag.parent.wffSlotIndex;
                        nameValue.setName(WffBinaryMessageUtil
                                .getBytesFromInt(parentWffSlotIndex));

                        final byte[][] values = new byte[wffAttributeBytes.length
                                + 1][0];

                        values[0] = nodeNameBytes;

                        System.arraycopy(wffAttributeBytes, 0, values, 1,
                                wffAttributeBytes.length);

                        nameValue.setValues(values);
                        tag.wffSlotIndex = nameValues.size();
                        nameValues.add(nameValue);

                    } else if (!tag.getClosingTag().isEmpty()) {

                        final int parentWffSlotIndex = tag.parent == null ? -1
                                : tag.parent.wffSlotIndex;

                        final NameValue nameValue = new NameValue();

                        // # short for #text
                        // @ short for html content
                        final byte[] nodeNameBytes = tag.noTagContentTypeHtml
                                ? encodedBytesForAtChar
                                : encodedByesForHashChar;

                        nameValue.setName(WffBinaryMessageUtil
                                .getBytesFromInt(parentWffSlotIndex));

                        final byte[][] values = new byte[2][0];

                        values[0] = nodeNameBytes;
                        values[1] = tag.getClosingTag().getBytes(charset);

                        nameValue.setValues(values);

                        tag.wffSlotIndex = nameValues.size();
                        nameValues.add(nameValue);
                    }

                    final Set<AbstractHtml> subChildren = tag.children;

                    if (subChildren != null && subChildren.size() > 0) {
                        childrenStack.push(subChildren);
                    }

                }

            }

            final NameValue nameValue = nameValues.getFirst();
            nameValue.setName(new byte[] {});

            return WffBinaryMessageUtil.VERSION_1
                    .getWffBinaryMessageBytes(nameValues);
        } catch (final NoSuchElementException e) {
            throw new InvalidTagException(
                    "Not possible to build wff bm bytes on this tag.\nDon't use an empty new NoTag(null, \"\") or new Blank(null, \"\")",
                    e);
        } catch (final Exception e) {
            throw new WffRuntimeException(e.getMessage(), e);
        } finally {
            lock.unlock();
        }
    }
public byte [ ] toWffBMBytes ( final Charset charset ) { final byte [ ] encodedBytesForAtChar = "@" . getBytes ( charset ) ; final byte [ ] encodedByesForHashChar = "#" . getBytes ( charset ) ; final Lock lock = sharedObject . getLock ( ACCESS_OBJECT ) . readLock ( ) ; try { lock . lock ( ) ; final Deque < NameValue > nameValues = new ArrayDeque < > ( ) ; final Deque < Set < AbstractHtml > > childrenStack = new ArrayDeque < > ( ) ; final HashSet < AbstractHtml > initialSet = new HashSet < > ( 2 ) ; initialSet . add ( this ) ; childrenStack . push ( initialSet ) ; Set < AbstractHtml > children ; while ( ( children = childrenStack . poll ( ) ) != null ) { for ( final AbstractHtml tag : children ) { final String nodeName = tag . getTagName ( ) ; if ( nodeName != null && ! nodeName . isEmpty ( ) ) { final NameValue nameValue = new NameValue ( ) ; final byte [ ] nodeNameBytes = nodeName . getBytes ( charset ) ; final byte [ ] [ ] wffAttributeBytes = AttributeUtil . getWffAttributeBytes ( charset , tag . attributes ) ; final int parentWffSlotIndex = tag . parent == null ? - 1 : tag . parent . wffSlotIndex ; nameValue . setName ( WffBinaryMessageUtil . getBytesFromInt ( parentWffSlotIndex ) ) ; final byte [ ] [ ] values = new byte [ wffAttributeBytes . length + 1 ] [ 0 ] ; values [ 0 ] = nodeNameBytes ; System . arraycopy ( wffAttributeBytes , 0 , values , 1 , wffAttributeBytes . length ) ; nameValue . setValues ( values ) ; tag . wffSlotIndex = nameValues . size ( ) ; nameValues . add ( nameValue ) ; } else if ( ! tag . getClosingTag ( ) . isEmpty ( ) ) { final int parentWffSlotIndex = tag . parent == null ? - 1 : tag . parent . wffSlotIndex ; final NameValue nameValue = new NameValue ( ) ; final byte [ ] nodeNameBytes = tag . noTagContentTypeHtml ? encodedBytesForAtChar : encodedByesForHashChar ; nameValue . setName ( WffBinaryMessageUtil . getBytesFromInt ( parentWffSlotIndex ) ) ; final byte [ ] [ ] values = new byte [ 2 ] [ 0 ] ; values [ 0 ] = nodeNameBytes ; values [ 1 ] = tag . getClosingTag ( ) . getBytes ( charset ) ; nameValue . setValues ( values ) ; tag . wffSlotIndex = nameValues . size ( ) ; nameValues . add ( nameValue ) ; } final Set < AbstractHtml > subChildren = tag . children ; if ( subChildren != null && subChildren . size ( ) > 0 ) { childrenStack . push ( subChildren ) ; } } } final NameValue nameValue = nameValues . getFirst ( ) ; nameValue . setName ( new byte [ ] { } ) ; return WffBinaryMessageUtil . VERSION_1 . getWffBinaryMessageBytes ( nameValues ) ; } catch ( final NoSuchElementException e ) { throw new InvalidTagException ( "Not possible to build wff bm bytes on this tag.\nDon't use an empty new NoTag(null, \"\") or new Blank(null, \"\")" , e ) ; } catch ( final Exception e ) { throw new WffRuntimeException ( e . getMessage ( ) , e ) ; } finally { lock . unlock ( ) ; } }
@param charset
@return the Wff Binary Message bytes of this tag
@author WFF
@throws InvalidTagException
@version 1.1
@since 3.0.1 initial implementation
@since 3.0.2 improved to handle NoTag with contentTypeHtml true