PHP - - By Scott Molinari

Appserver – Server Configuration, Dir Structure and Threads

Mastering Appserver

In the first part of our Appserver series, we discussed the very high level differences of Appserver’s architecture to standard web server stacks and got you up and running with an Appserver instance. If you missed that part, please take the time to read it.

Appserver node diagram

In this part, we will be exploring the Appserver architecture a bit more in depth. We will go through the concepts of the different contexts and the parts of Appserver you get out of the box, which cover some of the ground most of the popular PHP frameworks offer. We will also configure the web server and look into an application’s structure. Once we are finished, you should have a fair understanding about Appserver’s contexts in relation to threading, the web server, and its setup.

In subsequent parts, we’ll continue to go over the servlet engine in more detail, the persistence container, beans, the messaging system and the timer module. (Note: as this series evolved, the direction also changed, in order to include more practical information to break up the dry theory.)

The Contexts and Threading

As we had discussed in the first part, in today’s standard web server scenario, you will have a web server and either a web server module (mod_php) or a php process manager (PHP-FPM), to serve the PHP scripts/applications. The web server and the PHP process manager or module both handle their own work and threading to serve either the web page or the PHP application.

Server module gif

In this same respect, Appserver also handles threading for the client developer. However, the usage of the threads is somewhat different. The contents built within a thread aren’t constantly built and destroyed during the time appserver is running. In other words, as long as the appserver is running, the code you have given it to run, will continue to run (stay in memory) for each request. This fundamental difference is being repeated, as it is very important for understanding everything else we’ll be diving into.

We went over threads in the last post. Now you might be asking, what is a context? The definition of a context in Appserver is “the runtime environment of a thread”. Thus, each thread has its own context. The advantage of a thread and its context, above a general process, is its ability to share its contents with other threads and still be “thread safe”. One can call this an advantage, but left uncontrolled, it can become a nightmare. So, in order to avoid the nightmare, Appserver controls sharing for you, and it is done through context or thread inheritance.

Appserver offers a number of standard contexts. Once Appserver is started and running, it will have constructed a hierarchy or tree of contexts, with the root context being the top level or parent context. From there, you will have the container context and below that the server context, were the web server resides. The web server builds worker contexts (the number of workers is configurable). It is the worker contexts which allow the parallel processing of requests, which are built and controlled within each worker.

Worker contexts

The child contexts can inherit instances, configuration values, constants, functions, class definitions and even comments from their parents in a selective way. The forming of contexts also allows for clear separation of concerns, where necessary. Though, please don’t confuse this inheritance with the usual OOP inheritance. It isn’t quite the same.

The sharing of data between contexts, and the fact the contexts aren’t destroyed with each request, is the capability within Appserver, which promises a boost in performance of an application specifically built for Appserver. Things like the results of the initialization of an application (bootstrapping), which is often considered one of the most costly processes in a PHP application, can now reside in memory. Also, work can be passed off to other contexts, so the application process doesn’t have to wait for the accomplishment of that work (asynchronous programming). These are some of the greater advantages given to a web developer using Appserver.

Before we get into the deep end of appserver’s modules and programming for them, we need to cover some of the programming concepts it uses.

Programming Concepts and Techniques within Appserver

Annotations

Annotations in use

One important and probably controversial technique used throughout Appserver is annotations. The core idea behind using annotations is “keep Appserver easy to configure” or rather, “keep Appserver easy to program for”. Annotations play a major role in programming within Appserver’s environment from routing, to declaring beans and setting up servlets.

Although annotations are a core part of appserver’s configuration system, it is still possible for the client developer to configure with XML files. In fact, practically everything that is annotated can also be set and even overridden through a web.xml file found in the application’s directory (/WEB-INF). So, for those who’d rather not have annotations peppered in the code, you can use the XML file to set things up.

AOP – Aspect Oriented Programming

Aspect oriented programming diagram

The fundamental programming paradigm used within Appserver is AOP or Aspect Oriented Programming. You aren’t locked into this, but it is a modern way of programming also followed by the likes of Laravel, probably the most popular PHP framework currently. Thus, this paradigm of OOP is well worth looking into. Understanding the meaning of cross-cutting concerns or aspects, weaving, and join points will help you understand some of the underpinnings behind the design and proper usage of Appserver.

Design by Contract

Design by contract is also followed within Appserver. This is handy, as it enforces stricter typing between all the modules. Appserver uses the commented type annotations for parameters and return values of methods (something standard in most IDEs) and uses them to enforce stricter typing. If typing is not properly followed during runtime, exceptions can be thrown. Exceptions, which you can also create yourself. It is also possible to log these exceptions. We’ll show an example of this later.

Now let’s go down into each of the modules available.

The Web Server

One of the main goals of Appserver is to offer a relatively easy to use, but enterprise ready web server stack for PHP developers. It does this by also offering a good bit of functionality found in most PHP frameworks, which form the basis for a more rapid PHP development environment. In fact, a “built in” web server is actually an important part missing from these frameworks.

The web server in Appserver is part of the server framework. It is a web server written purely in PHP. Yes! PHP! It also represents the main module of the server context of Appserver. Currently, connectivity to the web server is possible over HTTP 1.1. Support for HTTP 2.0 is planned for a future version, currently 1.3.0 or possibly 2.0.

A core functionality, which most of you probably recognize from most of the popular frameworks, comes from the web server in the form of the $request and $response objects. Since Appserver follows AOP, the objects will actually be called though an interface like HttpServletRequestInterface. We’ll get into using the request and response objects in our review of the example app installed with Appserver in the next part.

From the Appserver user’s or client developer’s perspective, the web server’s configuration and usage is similar to that of the Apache web server. Things like rewrites, virtual hosts, setting environment variables and HTTP authentication are all possible within the web server module.

The most important config files for the server context are under /etc/appserver. There, you will find the appserver.xml file for the server, web server and container settings and the /conf.d/virtual-hosts.xml files, where your virtual host definitions will be added. There is an example file already installed, which will help you set up a virtual host.

Let’s set up a virtual host in appserver’s webserver now.

Creating a Virtual Host

Hopefully you’ve followed the directions from the first part of this series and have Appserver running on your handy local VM. In the past blog post, we were using a Debian Wheezy VM. The installation should have set you up with the example app, which you can find under the URL http://my-app.com:9080/example. We’re going to set up Appserver to serve the example app under the URL http://my-app.com (my-app.com representing the name you’ve set up for the server, should it be different than what Bruno suggested in his article). This short process will give you a feel for setting up a virtual host.

Step 1 – Change the Port (One Time Change)

Not completely necessary, but still handy. We will get rid of the need to enter the port number :9080 with every URL. First, make sure no other web server is blocking port 80 by stopping the service, with something like:

service nginx stop

or

service apache2 stop

Then go to the /opt/appserver/etc/appserver directory and open appserver.xml. Search for the following lines.

<server 
    name="http"
    type="\AppserverIo\Server\Servers\MultiThreadedServer"

Below them, look for the port parameter.

<param name="port" type="integer">9080</param>

And change 9080 to 80.

Step 2 – Change/ Add the Virtual Host

Now go to the /conf.d directory and open the virtual-hosts.xml file. It should look like this.

<?xml version="1.0" encoding="UTF-8"?>
<!--
 ! The following is a basic showcase example for a virtual host configuration.
 ! Some more examples can be found at:
 !
 ! http://appserver.io/get-started/documentation/webserver.html#virtualhost-examples
 -->
<virtualHosts xmlns="http://www.appserver.io/appserver">
    <virtualHost name="example.local www.example.local">
        <params>
           <param name="admin" type="string">info@appserver.io</param>
           <param name="documentRoot" type="string">webapps/example</param>
        </params>
        <rewrites>
            <rewrite condition="-d{OR}-f{OR}-l" target="" flag="L" />
        </rewrites>
        <accesses>
            <access type="allow">
                <params>
                    <param name="X_REQUEST_URI" type="string">^.*
                    </param>
                </params>
            </access>
        </accesses>
        </virtualHost>
            <virtualHost name="dbadmin.awesome.dev">
                <params>
                    <param name="admin" type="string">info@appserver.io</param>
                    <param name="documentRoot" type="string">webapps/phpmyadmin</param>
                </params>
            <rewrites>
                <rewrite condition="-d{OR}-f{OR}-l" target="" flag="L" />   
            </rewrites>
        <accesses>
            <access type="allow">
                <params>
                    <param name="X_REQUEST_URI" type="string">^.*
                    </param>
                </params>
            </access>
        </accesses>
    </virtualHost>
</virtualHosts>

Important to note are the different areas of the file like, virtualHost, accesses and rewrites. These are the common configurations you’ll be dealing with per virtual host. Also notice the documentRoot parameter. This will now help us avoid adding the directory /example to the URL.

Change the virtualHost name to look like this.

 <virtualHost name="my-app.com www.my-app.com">

Again, my-app.com is the name you created with the Vagrant box. We are also adding www.my-app.com here too, as we are simulating a proper website with access to a www. sub-domain.

For these changes to take effect, you now need to restart Appserver.

service appserver restart

If you wanted to (and you should), you could add a rewrite rule, which will intercept any call to the www. subdomain and reroute it to the main domain or vice versa. We’ll go with the former, www. subdomain to the main domain. This follows a very important and fairly standard rule of SEO. The same content should never be accessible under different URLs!

To create this rule, under <rewites> add the following line below the rewrite condition already present.

<rewrite condition="^www\.@$HTTP_HOST" target="$REQUEST_SCHEME://my-app.com$X_REQUEST_URI" flag="R,L" />

This condition looks for any URL prefixed with www. and reroutes it to the target scheme, which is our main domain. Notice also, we can simply add the variable $X_REQUEST_URI, instead of a backreference. This saves a bit of computing for a regex. You can use any $_SERVER array values normally available from PHP in the rewrite rules. That is handy, isn’t it?

Check to see if you can now see the example app under your domain name. In our example, it will be under:

http://my-app.com

If all has gone well, you should see the example app.

Example app running

One last note, before we dig into servlets. Appserver also comes with its own PHP-FPM, currently 5.5.x running on port 9010. You can also run with your own FPM by changing the port in the appserver.xml file. Also, Appserver currently doesn’t start its FPM service automatically, so remember to also start it, should you need to run apps not directly built for Appserver (like WordPress). To start the service, in your shell console enter

service appserver-php5-fpm start

If you need to make any changes to Appserver’s PHP settings, you’ll also find the related .ini file under /opt/appserver/etc.

The Servlet Engine

If you can imagine the web server is the eyes, ears and mouth of Appserver, then the servlet engine is the temporal lobe of the brain. Those of you fond of Java may also recognize the similarities between Appserver’s servlets and Java servlets. In theory and practice, they are pretty much the same thing.

The Painful Bootstrap Process No Longer

One of the most costly processes all major frameworks or heavy duty web applications have with current PHP web server stacks is the bootstrapping process. This process is where configuration is read and the runtime environment is set up. Since this process must be done with each request, it is a source for performance loss and is often compensated for with some sort of caching scheme, which adds complexity to the application. With appserver, the bootstrapping process is done only once, at server start-up, so basically automatically cached. The bootstrapped code, like the servlets in the servlet engine, is held in memory, until appserver is stopped. This initialization portion of appserver is quite important and one of its major benefits.

Appserver File Structure

Before we go any further, we first need to understand the file and directory structure of an Appserver application. It is different than the normal file structure you might find in most PHP projects. The actual applications are found under the directory /webapps. In our Appserver installation, you should see the example app under the /example directory. Under this directory, you’ll find the following directory structure.

Example file structure

Here is a quick synopsis of the important directories in an Appserver application.

/WEB-INF – this directory holds the client facing PHP classes. You’ll notice in the example app there are both examples for servlets (which aren’t directly used in the app) and also “action” classes, which are used in the app. These classes form the controllers of the application.

/META-INF – this directory holds the code for the back-end services. This is where aspects and any entry code for the domain models should be held.

/common – This directory holds common classes shared between META-INF and WEB-INF classes.

/vendor – This directory holds any libraries you may have imported into your project with Composer. Appserver supports Composer and PSR-0 for class autoloading. PSR-4 isn’t supported, due to the custom directory structure required.

/static – This directory is home for all the static resources (i.e. JS, CSS and image files), which are necessary for the web application to render properly.

The above directories are the default directory structure. The structure can also be customized over an additional context.xml file in either META-INF or WEB-INF. If you do intend to break from the default structure, more information on doing so can be found in the appserver docs.

Important to Note – Communication between classes used within the servlet engine (WEB-INF) and the persistence container (META-INF) can be done with proxy objects. These objects can be communicated over a network, similar to remote method invocation in Java. This means it is possible to extrapolate these two layers into their own machines and have them run as services in an SOA based system. This ability to send objects across the network allows for asymmetrical scaling of Appservers, which is another one of its built in features.

Conclusion

We’ve covered contexts and threading in Appserver and how Appserver takes care of the “dirty work” for you with threading, by pre-building the necessary modules within contexts of threads. We’ve briefly covered the different programming tools and paradigms on offer, such as AOP or design by contract. We’ve gotten you up and running with Appserver’s web server, and explained how an app file structure should look like. We also dived into the configuration of the web server.

Phew!

And, we haven’t even scratched the surface of Appserver, really. It is a great platform and offers a new chance to build more powerful and easily scalable web applications in PHP.

In the following parts, we’ll be diving into the other modules offered out-of-the-box, like the servlet engine and the message queue.

As always, your great comments, critique and requests to cover any areas missed are highly welcomed!

Note: The above post was made with appserver version 1.0.6. The newest version, 1.1.0 was released just before this post was put into the publication process. We’ll make sure to cover the new features, as much as possible, in the next parts of this series.

Sponsors
Login or Create Account to Comment
Login Create Account