class HttpBindBody
{
    private static final Logger Log = LoggerFactory.getLogger( HttpBindBody.class );

    private static XmlPullParserFactory factory;

    static
    {
        try
        {
            factory = XmlPullParserFactory.newInstance( MXParser.class.getName(), null );
        }
        catch ( XmlPullParserException e )
        {
            Log.error( "Error creating a parser factory", e );
        }
    }

    private final ThreadLocal<XMPPPacketReader> localReader = new ThreadLocal<>();

    private final Document document;

    public static HttpBindBody from( String content ) throws DocumentException, XmlPullParserException, IOException
    {
        return new HttpBindBody( content );
    }

    protected HttpBindBody( String content ) throws DocumentException, XmlPullParserException, IOException
    {
        // Parse document from the content.
        document = getPacketReader().read( new StringReader( content ), "UTF-8" );
        final Element node = document.getRootElement();
        if ( node == null || !"body".equals( node.getName() ) )
        {
            throw new IllegalArgumentException( "Root element 'body' is missing from parsed request data" );
        }
    }

    private XMPPPacketReader getPacketReader()
    {<FILL_FUNCTION_BODY>}

    public Long getRid()
    {
        final String value = document.getRootElement().attributeValue( "rid" );
        if ( value == null )
        {
            return null;
        }

        return getLongAttribute( value, -1 );
    }

    public String getSid()
    {
        return document.getRootElement().attributeValue( "sid" );
    }

    public boolean isEmpty()
    {
        return document.getRootElement().elements().isEmpty();
    }

    public boolean isPoll()
    {
        boolean isPoll = isEmpty();
        if ( "terminate".equals( document.getRootElement().attributeValue( "type" ) ) )
        { isPoll = false; }
        else if ( "true".equals( document.getRootElement().attributeValue( new QName( "restart", document.getRootElement().getNamespaceForPrefix( "xmpp" ) ) ) ) )
        { isPoll = false; }
        else if ( document.getRootElement().attributeValue( "pause" ) != null )
        { isPoll = false; }

        return isPoll;
    }

    public String getLanguage()
    {
        // Default language is English ("en").
        final String language = document.getRootElement().attributeValue( QName.get( "lang", XMLConstants.XML_NS_URI ) );
        if ( language == null || "".equals( language ) )
        {
            return "en";
        }

        return language;
    }

    public Duration getWait()
    {
        return Duration.ofSeconds( getIntAttribute( document.getRootElement().attributeValue( "wait" ), 60 ) );
    }

    public int getHold()
    {
        return getIntAttribute( document.getRootElement().attributeValue( "hold" ), 1 );
    }

    public Duration getPause()
    {
        final int value = getIntAttribute( document.getRootElement().attributeValue( "pause" ), -1  );
        if (value == -1) {
            return null;
        }
        return Duration.ofSeconds(value);
    }

    public String getVersion()
    {
        final String version = document.getRootElement().attributeValue( "ver" );
        if ( version == null || "".equals( version ) )
        {
            return "1.5";
        }

        return version;
    }

    public int getMajorVersion()
    {
        return Integer.parseInt( getVersion().split( "\\." )[0] );
    }

    public int getMinorVersion()
    {
        return Integer.parseInt( getVersion().split( "\\." )[1] );
    }

    public String getType()
    {
        return document.getRootElement().attributeValue( "type" );
    }

    public boolean isRestart()
    {
        final String restart = document.getRootElement().attributeValue( new QName( "restart", document.getRootElement().getNamespaceForPrefix( "xmpp" ) ) );
        return "true".equals( restart );
    }

    public List<Element> getStanzaElements()
    {
        return document.getRootElement().elements();
    }

    public String asXML()
    {
        return document.getRootElement().asXML();
    }

    @Override
    public String toString()
    {
        return asXML();
    }

    public Document getDocument()
    {
        return document;
    }

    protected static long getLongAttribute(String value, long defaultValue) {
        if (value == null || "".equals(value)) {
            return defaultValue;
        }
        try {
            return Long.parseLong(value);
        }
        catch (Exception ex) {
            return defaultValue;
        }
    }

    protected static int getIntAttribute(String value, int defaultValue) {
        if (value == null || "".equals(value)) {
            return defaultValue;
        }
        try {
            return Integer.parseInt(value);
        }
        catch (Exception ex) {
            return defaultValue;
        }
    }
}

        // Reader is associated with a new XMPPPacketReader
        XMPPPacketReader reader = localReader.get();
        if ( reader == null )
        {
            reader = new XMPPPacketReader();
            reader.setXPPFactory( factory );
            localReader.set( reader );
        }
        return reader;
    
<no_super_class>