Nicklas Karlsson [
https://community.jboss.org/people/nickarls] modified the document:
"A debuggers guide to 'AS7 Internal Architechture Overview'"
To view the document, visit:
https://community.jboss.org/docs/DOC-48190
--------------------------------------------------------------
*Introduction*
Since Brian Stansberry was kind enough to write an article on the AS 7 interal
architechture, the aptly named "AS7 Internal Architecture Overview",
https://community.jboss.org/docs/DOC-47970
https://community.jboss.org/wiki/AS7InternalArchitectureOverview, I thought I'd
document my attempts of walking through it in the form of a tounge-in-cheek diary.
Hopefully, he'll have time to correct my misunderstandings (as I'm sure there will
be plenty). If nothing else, he will at least have proof that at least one person has read
through his article.
The first part of this article will deal with setting up the debugging environment and
stepping through the aquiring of the ServerEnvironment and the initializations of the
BootStrapImpl and ServerContainerImpl instances involved. More will follow as I debug
along.
*Environment*
Well, where to start? Since we all know by now that the AS7 is blazingly fast, we'll
need a debugger to place some breakpoints so we'll have a chance of seeing what's
going on. Grab Eclipse Juno SR1 from
http://eclipse.org/downloads/
http://eclipse.org/downloads/ and JDK 7 from
http://www.oracle.com/technetwork/java/javase/downloads/index.html
http://www.oracle.com/technetwork/java/javase/downloads/index.html. Install the JDK and
Eclipse, you might also want to set JAVA_HOME to point at the JDK and set -vm
C:\Java\jvm\jdk1.7.0_12\bin\javaw.exe (on Windows) in eclipse.ini. You'll also want
JBoss Tools (since you're the 'living on the edge' kind of person, use the
nightlies at
http://download.jboss.org/jbosstools/updates/nightly/core/trunk/
http://download.jboss.org/jbosstools/updates/nightly/core/trunk/). Then we'll need
some sources. Grab the source zip from
https://github.com/jbossas/jboss-as
https://github.com/jbossas/jboss-as or even better, install git and do a 'git clone
git://github.com/jbossas/jboss-as.git';. Since you're in a hurry (and running tests
is for CI-systems anyway, right?), build the as with 'build clean install
-DskipTests' After the build has completed, start Eclipse and define a new server
pointing at that runtime (it's under the build/target dir). Remember to set the
startup timeout to a large number (integers are cheap).
*The main method*
In the beginning was Main.main(String...). And the return was void. And he thought
he'd better roll up his sleeves and get to work. Since Brian told us bootstrapping
starts at the server module, use the Eclipse "Import existing Maven
project"-feature to pull in the jboss-as-server project from the "server"
folder in the AS source. In the article we learn that the startup scripts point JBoss
Modules to this very module and the Main server class so this is where we'll place our
breakpoint and press the server debug button to boot it up in debug mode.
Takeoff! The breakpoint is hit and you can point the source lookup to the jboss-as-server
project on your workspace. If you look at the import list of Main, you will notice
references to projects and subprojects such as "controller",
"process", "version", "logmanager", "modules",
"msc" and "stdio". As this tutorial proceed, I might venture further
in but for now I'll take the stance that as-subprojects (such as
"controller") are imported and examined when stumbled upon but as-sibling
projects (such as modules and threads) are stepped out of in the debugger. Those who
can't wait are of course invited to check out the sibling projects also and step into
them. The notable exception to the policy will be the MSC (Modular Service Container)
which we will open up since, well, that's a large part of the AS.
The first thing the main module does is sets up the basic logging and capturing of the
standard I/O streams. It also sets up JBoss Modules with the basic information it need to
be able to do it's job (apparently access to the stuff in "org.jboss.vfs",
the Virtual File System module) is required. The first real "AS"-work is done in
determineEnvironment, where we determine the running environment by assembling a
ServerEnviroment. You might also want to import the controller project at this point
because we will see RunningMode there (although it's just a simple enum that tells if
we're running in normal or admin mode).
*The running environment*
This method takes the parameters to main(String...), the system properties, the system
environment and a flag that tells if this is a standalone instance booting. Both the
fetching of the system properties and the environment checks for precense of a security
manager and runs the call through AccessController.doPrivileged if one is found. In other
cases, a straight call is performed. The main job of determineEnvironment is parsing
through the arguments, sometimes just printing out usage or version information and
exiting or setting various system/env values based in the incoming prameters.
In our case we hit the determineEnvironment with the "-b" "localhost",
"--server-config=standalone.xml" and some system properties/env data. The args
are looped and "-b, "localhost" is converted added to the system properties
as "jboss.bind.address" => "localhost" and the serverConfig value
is set to standalone.xml. A new ProductConfig is created (it's in the version project,
import it), it looks for a system env JBOSS_PRODUCT_CONF and if that can't be found
returns the path to a product.conf in the AS bin dir. We don't have any of that so we
end up with null for all values, on an EAP, apparently the manifest data of the jar in the
org.jboss.as.product module is read according to the slot property which was read from the
for-us-fictional property file.
Equipped with a deeper knowledge of our three null values, we move on. The
determineEnvironemt should return a ServerEnvironment and so it does in the last line by
throwing all it got into the constructor of said class. The code in the constuctor is
longish but fairly easy to step through, essentially what it does is determine host names
and various directories (temp, work, deployments etc) to use based on the information
passed in. All this is the encapsulated into the ServerEnvironment object. It
also places some of these values back into the system properties. At one point it also
copies the original system properties and tucks them away, possibly to be restored when
the server reloads or something. Anyways, at this point when the object is returned, the
boot process has determined everything it needs to know about its running enviroment and
can move on.
*Bootstrapping the bootstrapping*
At the end of the main loop we get an instance of BootstrapImpl and by doing so we also
get a ServiceContainerImpl and here the simple part of the tutorial ends ;-) Import the
jboss-msc project.
BootstrapImpl creates a ServiceContainerImpl which extends a ServiceTargetImpl. A
ServiceTargetImpl is a hiearchial construct with a parent, a Map of ServiceListener with
assoicated inheritance data and a Set of dependent service names. The ServiceTargetImpl
has various methods for adding/removing dependencies and listeners and working with
ServiceBuilders. The javadoc says it's a "Abstract base class used for
ServiceTargets" but the implementation looks quite concrete (and central) to the MSC.
A ServiceListener is an interfaces that can be used for listening for various events in
the MSC, such as state transitions, services added, various dependencies becoming
available/unavailable etc. The ServiceListener.Inheritance determines if the listener
should be inherited to all sub-service-targets, only once or not at all. By using the
subTarget() method you can get a new ServiceTargetImpl with the current instance as the
parent (the hiearchial part). There is apparently also a batch-version
of the method but let's skip it for now. A ServiceName is an unique (complicated,
hierarchial) identifier with a String name, a ServiceName parent and a hashcode.
But back to the ServiceContainerImpl. In the instance variables we have a
'registry' - a Map of ServiceName -> ServiceRegistrationImpl, 'start'
(more on the ServiceRegistrationImpl later on) - timestamp of start time,
'shutdownInitiated' - timestamp of shutdown started, 'terminateListeners'
- a list of TerminateListener instances interested in the shutdown event,
'profileOutput' - ?, 'terminateInfo' - timestamps of a possible shutdown
in progress, 'down' - flag telling if container is down, 'executor' - the
container thread pool executor, 'name' - the name of the container,
'mBeanServer' - a handle to the MBeanServer, 'objectName' - the MBean name
of the container and 'containerMXBean' - a MBean interface implementation for the
container,
'SERIAL' - an AtomicInteger used for getting a serial number for the container,
'PROFILE_OUTPUT' - the value of the system property jboss.msc.profile.output (or
null), 'executorSeq' - an AtomicInteger used for getting a sequence number for the
executor, 'HANDLER' - an exception handler for uncaught exceptions slipping
through and 'POLICY' - a Thread pool executor policy. Phew!
There are also some nested classes available. The executor is a ContainerExecutor, which
extends a ThreadPoolExecutor. When created, it grabs an id from executorSeq and creates a
threadSeq sequence for threads. It offers a newThread(Runnable) method that returns an
instance of ServiceThread extends Thread after setting the thread name (including the
executors id and an incremented sequence number from the threadSeq). ServiceThread is a
basic Thread extension that can keep a reference to a ServiceContainerImpl. The
ContainerExecutor also uses HANDLER and POLICY defined in the parent class. LatchListener
is a TerminateListener that increases in the constructor and decreases when a termination
is observed, essentially keeping a count of running containers.
ShutdownHookHolder hold a boolean down flag that says if the container is shutting down
(possibly preventing new containers from being registered). It also contains a set of
known containers. A cleanup thread is registered with Runtime.getRuntime().addShutdownHook
that sets the down to true, iterates over all known containers, attaches a LatchListener
(set to the size of known containers) to them and shuts them down. The terminating
containers will fire the termination listener and then the thread can just sit and wait
until the latch is finshed (all known containers signalled termination).
So we are in the constructor of the ServiceContainerImpl (from BootstrapImpl). Well, first
the static stuff is called, causing a greeting to be printed out, then field
initialization occurs. But then we get ourselves a serialNo (1) and set the name
(jboss-as). The ContainerExecutor is initialized. The objectName is intialized
(jboss.msc:type=container,name=jboss-as), the mBeanServer is fetched from the
ManagementFactory.getPlatformMBeanServer and the containerMXBean is registered with the
server. The mBeanServer and objectName are stored to the instance variables. We register
the container with the static Set in the ShutdownHookHolder, adding the container and a
Reaper that will remove the registration. Finally, if the container was registered as a
MBean, we add a termination listener that will unregister the container from the MBean
server.
With the service container initialized, booting can begin.
--------------------------------------------------------------
Comment by going to Community
[
https://community.jboss.org/docs/DOC-48190]
Create a new document in JBoss AS 7 Development at Community
[
https://community.jboss.org/choose-container!input.jspa?contentType=102&a...]