You’re right - you don’t find a lot of information on this in the documentation that ships with Openfire. This kind of information is documented in javadoc only (the documentation that is embedded in the source code).
Openfire does not feature an internal pluggable system (OSGI like) that offers one generic plugin architecture for every feature. That said, most of the core functionality is based on interfaces, of which new implementations can be added. Authentication, for example, is performed by classes that implement the AuthProvider interface. There are a number of default implementations available, but you’re free to create your own. Have a look at
http://www.igniterealtime.org/builds/openfire/docs/latest/documentation/javadoc/ org/jivesoftware/openfire/auth/package-summary.html or more specificly http://www.igniterealtime.org/builds/openfire/docs/latest/documentation/javadoc/ index.html for information on how this works.
We’re likely not as “pluggable-by-architecture” as Tigase (although I’m not familiar with their implementation), but in practice things that you’d like to change or modify in Openfire are typically easily changable.
Openfire is not based around Servlets, no. Openfire was developed in a way that would allow you to run it either stand-alone, or in an application server. This is probably where you got the references from. As far as I know, most people run Openfire as a standalone application.
To get an entrypoint in the code of Openfire, I’d start by following an XMPP stanza that arrives on the network. This is roughly what happens:
Openfire uses socket acceptors to receive raw data that is sent. For each type of connection, a specific socket acceptor is instantiated within Openfire. All data that is sent from client connections, for example, is handled by one socket acceptor (although a separate acceptor is used for clients that connect using SSL). All data that is sent from connections from multiplexers (the connectionmanagers) are handled by acceptor. The data sent from external components is handled by yet another acceptor.
A socket acceptor will first put raw bytes into XML. Next, these XML fragments are handed over to a connection handler (specific to the socket acceptor) that will process the data. This is where most of the magic happens: Sessions are opened and closed, XMPP stanzas are parsed from the XML data and are routed through all the appropriate subsystems of Openfire. Eventually, the stanza is delivered to its destination.
In all this, classes like http://www.igniterealtime.org/builds/openfire/docs/latest/documentation/javadoc/ org/jivesoftware/openfire/nio/ConnectionHandler.html play a central role. Start investigating there, I’d suggest.
I hope this helps. Let me know if you need more.