class SoftwareVersionManager extends BasicModule implements SessionEventListener {
    private static final Logger Log = LoggerFactory.getLogger(SoftwareVersionManager.class);

    public static final SystemProperty<Boolean> VERSION_QUERY_ENABLED = SystemProperty.Builder.ofType( Boolean.class )
        .setKey("xmpp.client.version-query.enabled")
        .setDefaultValue(true)
        .setDynamic(true)
        .build();

    public static final SystemProperty<Duration> VERSION_QUERY_DELAY = SystemProperty.Builder.ofType( Duration.class )
        .setKey("xmpp.client.version-query.delay")
        .setChronoUnit(ChronoUnit.MILLIS)
        .setDefaultValue(Duration.ofSeconds(5))
        .setDynamic(true)
        .build();

    public SoftwareVersionManager() {
        super("Software Version Manager");
    }

    @Override
    public void start() throws IllegalStateException {
        super.start();
        SessionEventDispatcher.addListener(this);
    }

    @Override
    public void stop() {
        super.stop();
        SessionEventDispatcher.removeListener(this);
    }

    @Override
    public void sessionCreated(Session session) {

    }

    @Override
    public void sessionDestroyed(Session session) {

    }

    @Override
    public void anonymousSessionCreated(Session session) {

    }

    @Override
    public void anonymousSessionDestroyed(Session session) {

    }

    @Override
    public void resourceBound(final Session session) {<FILL_FUNCTION_BODY>}
}

        if (!VERSION_QUERY_ENABLED.getValue()) {
            return;
        }

        // Prevent retaining a reference to the session object, while waiting for the right time to execute the query.
        // There's (unproven) concern that this is a factor in issue OF-2367. Better safe than sorry.
        final JID address = session.getAddress();

        // The server should not send requests to the client before the client session
        // has been established (see IQSessionEstablishmentHandler). Sadly, Openfire
        // does not provide a hook for this. For now, the resource bound event is
        // used instead (which should be immediately followed by session establishment).
        TaskEngine.getInstance().schedule( new TimerTask() {
            @Override
            public void run() { try {
                final Session session = SessionManager.getInstance().getSession(address);
                if (session == null || session.isClosed() || !VERSION_QUERY_ENABLED.getValue()){
                    return;
                }

                IQ versionRequest = new IQ(IQ.Type.get);
                versionRequest.setTo(session.getAddress());
                versionRequest.setFrom(session.getServerName());
                versionRequest.setChildElement("query", "jabber:iq:version");
                session.process(versionRequest);
            } catch (Exception e) {
                Log.error("Exception while trying to query a client ({}) for its software version.", session.getAddress(), e);
            }}
        }, VERSION_QUERY_DELAY.getValue()); // Let time pass for the session establishment to have occurred.
    
<methods>public void <init>(java.lang.String) ,public void destroy() ,public java.lang.String getName() ,public void initialize(org.jivesoftware.openfire.XMPPServer) ,public void start() throws java.lang.IllegalStateException,public void stop() <variables>private java.lang.String name