Chapter 22
Deployment
Considerations
|
In this chapter: 1. You will understand why packaging is important. 2. You will understand what application partitioning is and how to effectively partition a J2EE application in various scenarios. 3. You will learn about different kinds of deployment. |
In the last chapter you gained a thorough understanding of class loaders. In this chapter we will apply the class loader knowledge to appreciate the necessity for good packaging disciplines for deployment and more importantly effectively partition the application at design time to avoid class loader problems before it is too late. Appropriate packaging, application partitioning and deployment are the key to survival and success of J2EE projects itself, not just you! A good packaging and deployment strategy stands the test of time by isolating one J2EE application from another deployed in the same environment. It does so by giving due consideration to class loader hierarchies in J2EE, appropriate packaging and application partitioning, and controlling the dependency graphs – at class, package and system levels.
22.1 Introducing Application Partitioning
Application partitioning is best applied as forethought rather than after-thought. It involves deciding the package structure of the application in advance and deciding which deployment units (jars, wars etc.) contain which packages. It is always convenient when an entire java package is part of a single deployment unit. Thus when build scripts are written, they can include or exclude entire packages when creating WARs or jars. If part of a java package belongs to a certain deployment unit and the rest belongs to another, every time a new class is added to that package, you have to revisit the build script and decide which deployment unit the class belongs to. Worse, it prompts the developers to introduce dependencies that can cause headaches later. For example, a developer might make a class in EJB deployment unit have dependencies on classes in web tier deployment unit.
Application Partitioning and Project organization
|
Application partitioning will be simpler if the development time package design mimics the deployment unit structure. IDEs are built to address this kind of problem. They provide a concept of “Projects” – a group of closely coupled classes bound logically together. Each project can map to a deployment unit. Each project holds the knowledge of other projects it depends on and has its own Ant build script. This makes the build scripts much easier, since each of the build scripts now have to just build all the classes in their respective projects instead of possessing knowledge of which java packages from the entire application has to be included in building a particular deployment unit. |
Figure 22.1 Sample Project organization in Eclipse. |
Another major advantage of this segregation is that it encourages the developers to think in the lines of deployment units and class loaders. Figure 22.1 shows such the projects organization in Eclipse IDE mimicking the deployment structure. As you can see, the entire J2EE application has been split into 3 (or more) different projects. Each project has a src, test, deploy and optionally a conf directory. The src folder has the source code. The test directory has the JUnit or Cactus test classes. The deploy directory contains the deployment artifacts. For a web application these can be MANIFEST.MF and web.xml files. In a EJB application, this directory contains at the least, a MANIFEST.MF and ejb-jar.xml.
The conf directory is present only in the web application since only a servlet can read resources outside of the classes hierarchy in an EAR. There are three mechanisms of accessing a resource in an EAR. When the resource is present in a jar file, either in a dependency library, WEB-INF/lib jars or an EJB-JAR. The second is when it is present under the WEB-INF/classes directory of the WAR. In each of these cases, the resource is accessed using the ClassLoader.getResourceAsStream() method. The third mechanism is using the method getResourceAsStream in ServletContext. This method can read a resource from anywhere within the WAR file. We use the third mechanism to read the configuration files for the web application. At runtime the contents of the conf directory are present as WEB-INF/conf to make it inaccessible to the external world (According to the Servlet specification, contents under WEB-INF cannot be directly accessed by an external client). The Web Application project will also hold the jsps and other artifacts necessary (not shown in the figure).
You will also find a project.xml and optionally a maven.xml in each of the projects. That is the default Maven script for that project. The project.xml for each project creates the deployment unit for that project. It also has knowledge of other projects on which it is dependent upon at run time. The build is always started the top level and it will resolve the dependency as specified in each project.xml. Thus, if the EJB deployment units are not yet created, it will invoke the build on the Session EJBs and also any other projects it depends before creating the final artifact.

Figure 22.2 Runtime class dependency.
What this essentially means is that the dependencies between the different tiers have to be unidirectional. Also dependencies should point from web tier to EJB tier and from both EJB and web tier into the dependency libraries. Figure 22.2 shows this dependency. The direction of arrows indicates the direction of dependency. Compare this with Figure 24.5 and the similarities are immediately obvious. The classes loaded by a child class loader depend on classes loaded by one of the parent class loaders in the hierarchy and not vice versa. This follows from the first principle on visibility stated at the beginning of this section i.e. Classes loaded by parent class loader are visible to child class loaders but not vice versa. Also notice that the project organization in Figure 22.1 is along the lines of class visibility.
Traditionally developers have been partitioning applications into projects along the line of components and business logic implementation. For instance, if there are use cases related to loans, then developers naturally tend to create a project in their IDE for Loan Management and create several artifacts out of a single source tree. The process is repeated for other “verticals” in the project. This is one extreme. Another extreme is shown in Figure 22.1. Something in the middle is realistic. This realistic partitioning should let you divide the project along deployment units and also along disparate business areas like Loan Management, Customer Management and so on. Such a division can be achieved by letting the deployment unit organization drive the top-level project folders and the “verticals” drive the second level project folders.
Not all of the application partitioning can be thought of in advance. During application development it is possible that someone inadvertently introduced incorrect dependencies. Three such sample scenarios are explained in the next section.
22.2 Scenarios in Application Partitioning
The first scenario occurs when a new method is added to an existing class, say ClassA. ClassA resides in a WAR. Another class, ClassX residing in EJB-JAR is using the new code from ClassA. In this case, instead of moving the ClassA to the EJB-JAR, refactor it to “Extract a Class”, ClassB that provides services to the EJB tier independent of ClassA and other WAR classes. In other words, ClassX from EJB tier is now dependent only on ClassB. Now, move ClassB into the EJB tier. Figure 22.3 shows this scenario. If such a refactoring is impossible, then move ClassA (and/or a limited set of classes) into the EJB tier and break the dependencies between ClassA and other web tier classes.

Figure 22.3 Refactoring dependencies.
The second scenario is when an EJB class (Bean class – LoanManagerEJB) has a private method methodZ() that that has ClassZ (from a dependency library say z.jar) as an input argument as follows.
private void methodZ(ClassZ z)
The remote interface (LoanManagerRemote) however, is not dependent on ClassZ. Hence the dependency on z.jar is limited to the EJB-JAR. A web tier class for instance, ClassA is using the LoanManagerRemote. Since LoanManagerRemote does not import ClassZ, the web tier is not dependent on ClassZ. Figure 22.4 shows this scenario.

Figure 22.4 ClassA and ClassZ are not linked.

Figure 22.5 Class A cannot see ClassZ but the LoanManagerRemote imports ClassZ.
Now suppose that another EJB class (Bean class – PersonManagerEJB) wants to use methodZ() from LoanManagerEJB. Since any EJB can access another only by invoking the methods on the local or remote interface, the methodZ() is defined on the remote interface, LoanManagerRemote. Accordingly the LoanManagerRemote will have a import statement for ClassZ. Now recall that LoanManagerRemote is used by ClassA from web tier, but ClassZ is not visible in the web tier. A NoClassDefFoundError is thrown immediately. Figure 22.5 shows this scenario.
A quick and dirty solution is to modify the WAR manifest file to create the dependency on z.jar. There are better solutions however. One solution to this problem is to create a Local Interface for LoanManager EJB and move methodZ() into the Local Interface. Another alternative is to move the methodZ() into a new EJB – LoanHelperEJB so that LoanManagerRemote is not dependent and hence does not import ClassZ. The new EJB is used only within the EJB tier and thus the dependency on z.jar is controlled. Figure 22.6 illustrates this solution.

Figure 22.6 LoanManagerRemote does not import ClassZ and ClassA works without a hitch.
Third scenario is when the dependency is specifically parent-child relationship. Consider, a scenario where ClassB subclasses ClassA at design time. However at run time, ClassA is loaded by WAR class loader and ClassB is loaded by EAR class loader. Since it is not a norm for the EAR class loader to depend on classes loaded by WAR class loader, the code that tries to create a new instance of ClassB never works. As soon as you try to do so, you will get a NoClassDefFoundError on ClassA.
22.3 Third party Libraries – To share or not to share
In the previous sections you saw how the class loader hierarchy played a key role in your application structuring during development cycle. When it comes to deployment, there are several other factors impacting the build and deployment apart from the class loaders. We will closely scrutinize each of these factors.
In the preceding sections you saw that the EAR was a self-contained deployable unit. You can achieve this goal by bundling all third party libraries into the EAR. If the J2EE application server has multiple applications running, then each of the applications has their local copy of the third party libraries even if they are the same version of the libraries.
Can’t we just put all the common libraries into a common location and point the classpath to that location during server startup? At first glance, this might appear like a better approach and there are indeed benefits of such an approach in limited situations.
1. By having a fixed version of the library, the production support is considerably eased
2. When the library itself is very large, then it might pose memory problems at runtime if each application had its local copy.
3. If the application server uses the classes (your own or external library) for providing some server wide service, then you have to share these classes across the applications by making them available in the application server’s top-level classpath. Example: Many application servers let you set up database connection pools declaratively through their console. In this case, the database driver classes have to be visible to the application server. Another example is when you have a third party persistence (CMP) provider such as TopLink, the application server uses the classes from the third party provider for persistence and needs to be able to instantiate and use classes from the providers.
4. Any fixes from the vendors of third party libraries will automatically fix all applications.
Having said that, we suggest that you deploy the applications using local copies with except when the libraries consume a lot of memory and it is indeed a constraint (point 2 above) and when the libraries are service providers to the application server (Point 3 above). The risks of going with a shared library solution are:
1. It introduces the “version drift” problem. If one of the deployed applications migrates to a newer version, then other applications move to the newer version too, whether they like it or not.
2. If the newer version of the library is not backward compatible, it can wreak havoc in production. The fact remains that all of your J2EE applications evolve differently over time. You cannot bet your business on backward compatible third party libraries with stable APIs. In general the libraries do not take up a lot of memory. A simple math shows that the cost of migrating all of your deployed applications to use newer software far exceeds the cost of memory! In view of this we suggest that you should always choose the EAR based deployment unless there is some requirement that seriously prevents from doing so.
22.4 Deployment to multiple environments
In a project, typically you develop the application on the developer workstations and then deploy to testing, staging and finally to production. Each of these environments is different. When deploying to these different environments, your code should not be changing, rather the environment changes should be factored out of the application. Typically this is done by using properties file or system properties. This is a legacy carried on the J2SE environment and is not appropriate for J2EE environments. As mentioned earlier in Chapter 4, using system properties affects the entire JVM and hence also all the applications deployed to that environment. So using system properties is definitely ruled out. System properties should be used to set only those values which never change in your enterprise wide environment. For instance http.proxyHost and http.proxyPort are good candidates to be set as system Properties since they do not vary across applications.
Two other important mechanisms that can be used to set application scoped environment properties. The first mechanism is using properties or an xml file and reading it during initialization. The second is using JNDI environment entries.
The first mechanism is ideal when there are a lot of closely related values needed for a framework or application. Examples include log4j configuration xml that might have to change across environments. For instance, in development the default setting might be to log all debug messages to file and also to the console. For production, the default setting might be to log only those messages of priority ERROR or above to a specific file. The key thing to note is that these environment dependent values are closely coupled to warrant a separate xml or properties file for every environment.
The second mechanism is used when the environment dependent values are disparate and not closely connected in any definite manner. In such cases, the application component provider should declare the environment entries in web.xml using the env-entry descriptor as follows
<env-entry>
<description>The value of discount
in prod</description>
<env-entry-name>discount</env-entry-name>
<env-entry-type>java.lang.Integer</env-entry-type>
<env-entry-value>15</env-entry-value>
</env-entry>
The env-entry element consists of an optional description of the environment entry, the environment entry name relative to the java:comp/env context, the expected Java programming language type of the environment entry value (the type of the object returned from the JNDI lookup method), and an optional environment entry value. An environment entry is scoped to the application component whose declaration contains the env-entry element. This means that the environment entry is not accessible from other application components at runtime, and that other application components may define env-entry elements with the same env-entry-name without causing a name conflict. The environment entry values may be one of the following Java types: String, Character, Byte, Short, Integer, Long, Boolean, Double, and Float.
The application code can access the environment dependent values specified earlier using JNDI
Context initCtx = new
InitialContext();
Context myEnv =
(Context)initCtx.lookup("java:comp/env");
Integer disc =
(Integer)myEnv.lookup("discount");
Performing a lookup every time is expensive and time consuming. Hence some mechanism to cache the values in the memory after the lookup can be devised. The caching mechanism can be as simple as a simple Hash table lookup and a subsequent casting or a type safe lookup at compile time using explicit methods to get JNDI values as follows:
public
class EnvValues {
public static HashMap cache = new HashMap();
public static Integer getDiscount() {
Integer disc =
cache.get("discount");
if (obj == null) {
Context initCtx = new
InitialContext();
Context myEnv =
(Context)initCtx.lookup("java:comp/env");
disc =
(Integer)myEnv.lookup("discount");
cache.put("discount",
disc);
}
return disc;
}
..
..
}
In a real world project, the distinction between application component provider, developer and a deployer may be blurred. Moreover the deployer and application assembler will have to use SCM tools to get the deployment configurations instead of doing it on the fly. They will also have to use the build scripts to pick up the right deployment configuration files during deployment.
22.5 Deployment mechanisms
In the previous sub sections, we looked at the pros and cons of sharing third party libraries across the applications deployed in a single application server and then glossed over mechanisms for deploying to multiple environments. In this subsection, we will look at the ways of deploying your own components and libraries from an enterprise wide perspective. Let us consider the banking application itself.
Figure 22.7 Functional diagram of the logical systems in ABC Bank
The use cases in Appendix A can be divided into three sub systems namely Account Management, Loans and Reports. The first two are accessible from the Internet, while the latter is only accessible in the bank’s intranet. It immediately makes sense to have three separate web applications – one for each sub system. Let us forget the third sub system for now.
As you move from the web front to the back, the division among the subsystems is not as black and white. For instance, some of the domain objects that can be persisted and queried (from a RDBMS) are Person, Account and Loan. The Account Management web application uses the Account and Person objects whereas the Loan sub system uses the Loan and Person objects. It is the norm in J2EE applications to have most of the business logic in Session EJBs. Accordingly Account Management and Loan Management are represented with a Session EJB each. Each of these EJBs rely on a third EJB for credit card verification and payment purposes. Figure 22.7 shows the functional diagram of this logical division of responsibilities. The direction of the arrows indicates the dependency among components.
The challenge is to map this logical division into multiple J2EE deployment artifacts for an enterprise. For the ABC Bank use cases we could have wrapped all of the classes into a single EAR. But our intention is to mirror real world enterprise scenario with this simple set of use cases where there are multiple web applications presumably representing different departments within the enterprise. The EJBs represent the enterprise wide reusable business logic. Also in real world, you deploy newer versions of departmental and enterprise wide applications over time into the same or different application server instances. There are several approaches to achieve this. Important ones are Shared Component deployment, Dependent deployment and Independent deployment. There is no single approach that fits all. Each of these approaches has their pros and cons and have to be chosen after considering closely the priorities of your organization. Let us start looking at each of them.
Shared deployment
In a shared deployment approach, the departmental applications deployed either as individual WARs or EARs access the common EJB deployment. In other words both Loan and Account management web applications use the same deployment of Loan and Account EJBs. Figure 22.8 shows such a scenario.
Let us consider the scenario when all the components of ABC Bank – the Loan WAR, Account WAR, Loan, Account Management session EJB-JARs and domain objects (implemented as Persistent Plain Old Java Objects (POJO) or Entity EJBs) all packaged into a single EAR. This approach is very easy to accomplish. However this approach has some drawbacks in the long run. Let us see what they are.

Figure 22.8 Shared deployment approach for ABC Bank
First, let us look at the usage pattern of these applications. Account Management web application is used by the customers all the time, throughout the year on a daily basis. Loan web application usage is however market driven. When mortgage rates are low during the year or when the real estate is booming, customers opt for applying for the loan and that too only once in a couple of years. Peak load for account web application is predicable. Not so for the Loan management web applications. This means that the two web applications have totally different hardware and software capacity requirements. What about availability? The account management web application has to be up all the time (except may be on Sunday nights after 2:00 pm CST – this is a norm for bank applications on the web). This may not be a requirement for Loan management web application. Based on this knowledge, we conclude that the two web applications for ABC Bank are not closely coupled to warrant a co-deployment. In fact this is the case most of the times when you have a separate web applications.
Another downside of this approach is the version drift common to shared deployment. When different departments provide the individual WARs and one of the departmental WARs wants to use the newer version of EJBs, they cannot do so, until all the involved parties have agreed upon to move ahead.
A variation of this approach is when the session and entity EJBs are completely factored out into a EAR of its own and both the Loan and Account WARs share the EAR.
Dependent deployment
In dependent deployment, each application is deployed as an EAR. Figure 22.9 shows the deployment mechanism for this scheme. In this figure, the Loan WAR, Loan Management EJB-JAR and Loan Entity EJB are bundled in an EAR called Loan EAR. The Account Management WAR, Account Management EJB-JAR, Credit Management EJB-JAR, Person and Account Entity EJBs are bundled into Account EAR. The Account Management EAR is self sufficient and self contained. It does not have dependencies on any components outside the EAR. This makes it possible to keep the Account Management application available without any dependency on external factors. Loan Management EAR on the other hand is dependent on Credit Management EJBs, and may be even Person Entity EJBs that are present in the Account Management EAR. The stubs (Home and Remote interfaces) for the Credit Management EJB and Person EJB are bundled with the Loan Management EAR to provide the access to these EJBs outside the EAR. In other words, Loan Management application is dependent on Account Management application for its availability. This makes sense since the availability requirements are stringent for Account management application.
Deploying the application as two separate EAR files gives us the flexibility of deploying them to different JVMs or probably different hardware altogether. Even if they are deployed to a single application server, we can independently undeploy individual applications if the other application(s) needs more capacity. When the EARs are deployed on different machines, it gives us the flexibility of bringing down the dependent application without affecting the other application. It also gives us better control on deciding the hardware and software requirements for the applications individually, based on their nature and usage.
The down side of this approach is that when the Loan EAR is located on a different JVM, it requires a RMI-IIOP call for which the objects will have to be passed by value and also the network overhead. Application servers optimize EJB calls in collocated EARs by using pass-by-reference mechanism transparently.
Dependent deployment does not solve the version drift problem applicable to Shared Deployment. The dependent web application cannot use latest version of EJB-JARs until the other web application owning the EJB-JARs decides to migrate.
Figure 22.9 Dependent deployment approach for ABC Bank
In spite of these drawbacks one has to choose this approach in scenarios such as when the applications use a shared cache across a set of related applications for performance reasons. For instance, if for some reason, the Loan and Account management applications decide to use a shared cache to enhance performance by eliminating database hits, then dependent deployment or shared deployment are the only options.
Consider a case of dependent deployment when the EJBs in one EAR are used by web application in another EAR. The EJBs and web applications use normal Java objects to exchange data. The Java classes used to exchange data between the web and EJB applications (Data Transfer Objects, Value Objects) are bundled into dependency libraries. Since the web application in the second EAR needs to construct and access instances of the dependency library classes, the dependency library itself has to be bundled with both the EARs. You have earlier learnt that EAR class loaders load dependency libraries and each EAR gets their own class loader. Doesn’t this mean that you would get a ClassCastException when trying to send classes across the EAR boundary? Wrong. For a moment get out of the J2EE mode of thinking and think of EJBs as plain RMI – because that is what they are underneath. In RMI, if you remember, you can bundle Serializable Java classes with both the client and the server and the RMI would magically pass the object by value and de-serialize at the other end. This is exactly what happens here.
Independent deployment
In this approach, each EAR is entirely self-contained. Figure 22.10 shows the independent deployment approach for ABC Bank. The Loan EAR and the Account EAR both have their own copies of all the required EJB-JARs. In this way, the applications can be deployed independently of one another without having to worry about cross-process calls. The only thing you have to worry about is making sure that when the EJBs are deployed multiple times, they have different global JNDI names. In the Figure 22.10, the shaded classes are duplicated across the EARs and hence have to be deployed with different global JNDI names.

Figure 22.10 Independent deployment approach for ABC Bank
It might seem that independent deployment is the solution for every scenario. But that is not the case. In fact we have seen at least one scenario where dependent deployment is the right choice. Sometimes the choice is driven by the granularity of the components. For instance, all the entity EJBs referencing each other in EJB2.0 have to be located in the single EJB-JAR. Sometimes it is not possible to break the coupling to get the separation as in Figure 3.16. In some situations, the memory constraints might prevent transitioning from a dependent to an independent deployment.
In general, as the complexity of the application increases it gets tougher to take the independent deployment approach.
22.6 Deployment – Odds and Ends
In summary, EAR is not just a deployment component but also a build time component. Although theoretically the deployment is transparent to the developer and should not affect the development cycle, in practice it is not the case. There is at least slight impact if not more on the design and architectural decisions based on the deployment mechanism. Hence it is essential to sort this out as early in the project as possible.
Even though it is ideal to share JVM and application servers for different applications, it may not be always practical from an operational and maintenance perspective. Let us consider a case two applications from two different departments are deployed on one application server. Let us also assume that one of the departmental applications needs to stop the server for maintenance reasons. What happens to the other application? In addition the personnel with authority to stop the application from one department may not have authority to do so for the other departmental application. Sharing application servers and JVMs increases the performance when the applications share data. If this not the case, with your applications, then deploying on different physical machines is a better choice since it gives you operational flexibility.
After looking at various deployment choices, let us now consider the mode of deployment. Application Servers can be configured to enable hot deployment. This also requires some coding discipline from the developer. We will look at the hot deployment mode in the next sub section.
Hot deployment
J2EE implementations provide robust lifecycle services, transaction support etc. for your applications. Hence it is quite natural that it takes time to initialize, configure and start the application server platform. One of the ways J2EE helps us to get around this slow startup is hot deployment. Simply put, hot deployment is the application server’s ability to deploy a new set of classes to replace the original ones without having to shutdown the JVM.
Hot deployment is the key to accelerated development. It allows the application developers to re-deploy incremental changes to a class by going through the build process. On successful re-deployment, the server will instantiate new class loaders to load new versions of the class. For hot deployment to function properly, the clients must not directly reference the class to be hot deployed. If this happens to be the case, then either the client’s class loader will implicitly load its own copy of the class or the class loading will totally fail. This is one of the reasons why you obtain the EJBs through JNDI references instead of using a client side factory to create one.
Anyway, once the application server is ready to deploy the new application, it calls the destroy method (or its equivalents) on each of the servlets, filters etc. At that time, it is critical that any resources that might have been held on during its life have to be released. In addition, the JVM does not make any distinction between other classes and the classes and class loaders to be undeployed. Hence any classes outside the scope of hot deployment should also release the memory references to the classes being hot deployed (or their stubs). Typically this happens when a caching framework, plugged in as a service provider to the application server holds references to the objects from your application.
In addition to EAR deployment there is one situation where exploded deployment is useful. When the page author is developing and editing jsps themselves, it is even faster to have an exploded directory deployment. All application servers may not support the hot editing of jsps or even exploded deployment for that matter. Where supported this is least time consuming from a jsp development and debugging point of view. A point to remember is that in exploded deployment, the home and remote interfaces for the EJBs have to be present under WEB-INF/classes in addition to being in the EJB-JARs. Also the EJB local interfaces are not accessible from web tier classes in exploded deployment (Actually local interfaces are not accessible anywhere outside of an EAR. Even if you are deploying EARs, it not advisable to access local interfaces outside the EJB-JARs).
Deployment of static resources
A web application consists of static and dynamic resources. Jsps, Servlets and Tag Library definitions (tlds) etc. are examples of dynamic resources that are interpreted by the servlet engine at run time. Images, html, JavaScript files are examples of static resources. The Servlet specification treats all of this as part of the web application archive – the WAR. Hence it suggests the approach of bundling the resources – both static and dynamic into the WAR. This works without a hitch because the servlet engines, in additions to generating dynamic content, can also serve files like a web server. But this approach is not ideal in practice. Servlet engines are good at processing requests for dynamic content. They are not optimized for handling requests for static resources. Web servers, on the other hand are adept at handling requests for static contents.
In practice it is advisable to extract the static content out of the WAR and place it in a directory preferably with the same name as the web application context of the WAR under the Web Server doc root. The web server plug in (the one that redirects requests for dynamic content to the application server) then can be configured to forward requests for dynamic contents to the application server or the servlet engine based on the url path patterns and/or the suffix of the requested resource.
This separation of static and dynamic contents and serving them from two different sources is one of the reasons why the base href for the jsps has to be changed from the jsp name to the web application context. Recall from Chapter 5 that we developed a Base href tag to point to the web application context and all resource references – static and dynamic is from the web application context root. The advantage is immediately obvious. The images and other static resources are served by the web server. The dynamic content is provided by the servlet engine. Both of them have a single context root (Note that this is different from the web root. If the web server is running at http://www.abcbank.com, then abcbank is the web server root. If the web application is accessed by entering the url say, http://www.abcbank.com/myapp, then myapp is the web application context root. Any resource reference and url starting with a “/” is considered from the web server root. If the base href is http://www.abcbank.com/myapp, then any resource references and urls starting without a “/” are considered to be relatively present in the web application context root.) The web application context is mapped to the physical directory containing the static resources on the web server.
In this section, we looked at an area often not addressed during development cycles since, the servlet engine itself serves as the web server and the distinction is yet not made. However the forward looking architect will make this decision early enough in the project and direct the developers and page authors to code appropriately so that the jsps need not be modified later in the project to reference the static resources from elsewhere. This brings us to the end of a discussion on deployment, which hopefully you found instructional and interesting. In a project, even though the deployment comes after the build, we discussed it first because the deployment considerations drive the build mechanisms and the wisdom of deployment gotchas will help you be wiser when devising your build scripts.
22.7 Summary
In this chapter you gained an in-depth knowledge about impact of classloaders on application partitioning during development and deployment. You also came to know various mechanisms for deployment. Backed with this information you will be able to understand the build strategies in this book better and be able to appreciate the rationale behind the design decisions.