Programming Jakarta Struts, 2nd Edition [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Programming Jakarta Struts, 2nd Edition [Electronic resources] - نسخه متنی

Chuck Cavaness

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








16.1 To Package or Not to Package


Applications need to be deployed to be useful.
There's really no point in developing an application
that never gets deployed, although this occurs more often than you
might think. The need for deployment is obvious, but what about
packaging? Does every Struts application have to be packaged before
it gets deployed? The short answer is yes. In this chapter, though,
we'll examine the long answer.

Before we get into the details of packaging and deploying Struts
applications, let's define exactly what these two
concepts mean in the context of web applications that are built using
the Struts framework. Although the two concepts are closely related,
they are not the same thing.


16.1.1 What Is Packaging?


Packaging
a Struts application involves gathering all the files and resources
that are part of the application and bundling them together in a
logical structure. Many different types of resources are usually
included in a Struts application, and all of these need to be bundled
with the application. Some of the more common types of resources that
can be packaged with a Struts application are:

  • HTML and/or XML files

  • Images, audio, and video files

  • Stylesheets

  • JavaServer Pages

  • Properties files

  • Java utility classes

  • Configuration files

  • Action and ActionForm classes

  • Third-party JARs


During the design stage, time and effort should be spent on deciding
how you are going to structure the application. Not every detail
needs to be figured out and resolved before construction begins, but
you should understand the target environment's
requirements and how these requirements will affect your packaging
and deployment strategy. Ideally, you should decide on the principal
package and directory structure for the application before
construction gets underway. This will help to alleviate the normal
miscommunication between developers and reduce the number of
redundant resource files.


16.1.2 What Is Deployment?


As the previous section
mentioned, packaging and deployment are closely related, but involve
different tasks. While packaging determines where the resource files
will reside in the package structure and how those resources will be
bundled, deployment deals with how the bundled application will be
installed and configured inside a target web container.

There are two approaches that you can use when deploying a web
application into a container. The first approach is to deploy the web
application in a web archive (WAR) file. Most web containers install
a WAR file and
make it available for users, often without even requiring a restart
of the container. This approach is convenient because once the WAR
file is properly built, the rest of the work is handled by the
container. One of the downsides of this approach, however, is that if
a change is made to any file or resource within the web application,
a new WAR file must be created and redeployed into the container. The
details of how to deploy your Struts application as a WAR file are
discussed later in the chapter.

The second approach to deploying a Struts application puts more work
on the developer. It still involves packaging your application as a
WAR file, but includes manually unpackaging the WAR file into a
directory of the container. The exact location of the directory is
container-dependent. In Tomcat and Resin, for example, the default
web applications directory is webapps. In the
WebLogic application server, you have to unpack the WAR file
underneath the applications directory. (All
three of these containers also allow you to specify alternate
installation directories.)

When expanding the WAR file, you need to create a directory into
which to unpack the files. The name of the directory is usually the
name of the web application. So for example, if the web application
was called Storefront and you wanted to install it into Tomcat, you
could create a directory called storefront under
the webapps directory and unpack the WAR file
there.


The WAR file should not contain the storefront
directory as part of its structure.

This deployment approach is referred to as an
exploded directory
format
, because the WAR file is exploded back into its
original structure within the container. The benefit of this approach
over deploying the WAR file itself is that when there are changes,
only the changed files need to be redeployed into the container. This
is much easier when you're still developing or
debugging the application, but you may not want to leave it like this
for production.


When deploying a web application into production,
it's a better approach to leave the WAR file packed
because there's less chance of one or more files
getting contaminated. Leaving it as a single WAR file forces you to
replace the entire WAR file if changes need to be made, so
there's no chance of a version of a file getting out
of sync with the rest of the application.


16.1.3 Deciding How to Package Your Application


Because Struts applications are web applications,
most of the questions about how to package them are answered in the
Servlet and JavaServer Pages specifications. A web application must
follow a very strict set of guidelines and conventions that make the
web application portable across other web containers.

Fortunately, packaging your Struts application in the WAR format
solves much of the hassle regarding packaging. However, there are
many questions that you will have to resolve. For example,
you'll have to decide where all the JSP pages go and
whether you should store your Struts Action and ActionForm classes
together or in separate action and form packages. Although there are
definitely best practices, there are no hard-and-fast rules for
resolving issues such as these. Some of the solutions will depend on
your organization's requirements and policies.


16.1.4 Namespace Management


A namespace is simply a set of names
that may or may not be associated. A namespace is normally used to
prevent conflicts or collisions between similar entities and to allow
clients to reference these entities by some logical name.

In software development, a namespace is a way to package classes,
interfaces, and other types of information into a hierarchical
structure. There are many examples of namespaces throughout the
computer industry. The manner in which the Internet Domain Name
System (DNS) works is a type of namespace. Within the
oreilly.com domain, for instance, other IP
addresses are linked together in a hierarchal fashion. All of this
referencing helps prevent IP addresses from colliding. Another
example, which is more closely related to software development, is
the namespace that is used within JNDI. But by far the most familiar
use of a namespace in Java development is for creating classes and
interfaces that reside in a package.

As you know, Java applications are organized as sets of packages.
Even when you don't specify a package explicitly,
it's still part of a package.[1] The purpose
of the package is to prevent name collisions and to help identify
entities (in this case, Java classes) easily. When extending the
Struts framework with your own classes and interfaces, you need to
decide how best to package these components for your application. Not
every application will contain the same classes and interfaces.

[1] Any
Java class that doesn't have a package statement
declared in the source file is considered to be part of the
default package.



16.1.5 JSP File Placement


For many developers, where you place the JSP pages may seem like an easy
question to answer. Although you may have to decide which directory a
particular JSP page belongs in, that's normally all
that has to be decided. However, there are situations where more
control may need to be placed on who and what has access to the JSP
pages. One suggestion is to put the JSPs in a directory underneath
the WEB-INF directory.

The purpose of this approach is threefold:

  • It forces all requests to go through the
    ActionServlet class.

  • It prevents users from bookmarking a page.

  • It protects the WEB-INF directory and helps
    protect JSP pages from being called directly.


This alternate approach has gained some popularity, although not all
of the containers currently support it. Although the 2.3 Servlet
specification seems to indicate that something to this effect may be
possible, different vendors may not agree in their interpretation of
the specificationfor example, in the past, the WebLogic
developers have stated that they interpret section SRV.6.5 of the
Servlet specification differently. WebLogic will return a 404 or 500
error code when you attempt to access a JSP page underneath the
WEB-INF directory (although there has been some
indication that WebLogic will make this option available in future
versions of their container).

Even though some containers do support the above approach, you may
not need to put the JSP pages underneath the
WEB-INF directory. If you call Struts actions
only from your web application and don't link to JSP
pages directly (which is a requirement for Struts 1.1), this approach
will not have much benefit for your applications. There are portable
alternativesfor example, you can use the
security-constraint element in the
web.xml file. Just
create the required directories for the JSP pages that you want to
protect. In the Storefront example, suppose that users
shouldn't be able to access the JSP pages underneath
the order directory. A security-constraint
element like this could then be added:

<security-constraint>
<web-resource-collection>
<web-resource-name>SecureOrderJSP</web-resource-name>
<description>Protect the Order JSP Pages </description>
<url-pattern>/order/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name></role-name>
</auth-constraint>
</security-constraint>

Figure 16-1 shows what happens when a client
attempts to access a JSP page directly within the
order directory.


Figure 16-1. A 500 error will occur when accessing a protected JSP

When the security-constraint element is added to the
web.xml file for the Storefront application, it
says that no user without the proper authentication can access the
order JSP pages. However, in this example, the
role-name
element was intentionally left blank and therefore will never match
an actual role. You could also have specified that only users with an
admin role could access the pages, and then never given that role to
an actual user. The container would still be able to access these
pages through forwards and includes.

You must be careful what you put in the
url-pattern element,
however. If you have resources such as images in subdirectories, they
will not be available when the browser attempts to download them.
Using the /order/* pattern means that nothing
under the order directory can be requested
directly by the client; this includes images in subdirectories, and
the browser will have difficulty receiving the images for a returned
HTTP response message.


16.1.6 Precompiling JavaServer Pages


If you are using JavaServer
Pages as your Struts presentation technology, you are probably very
familiar with the compilation process that the JSP container performs
on the application's behalf. When the web container
receives a request for a resource with an extension of
.jsp, the JSP container is selected to process
the request. If this is the first request for the JSP page or if the
timestamp for the JSP page is newer than the existing servlet class,
the page will normally be compiled.[2]

[2] Most containers
have an option that disables detection so that pages that have
changed will not be recompiled. This option is usually selected in a
production environment because incremental changes should not be
introduced in production. Also, allowing this to occur would amount
to a security risk.


The JSP
container uses a two-step process. First, the JSP page is translated
from the JSP code into a Java source file. Each container may have
its own implementation to translate the JSP page. The second step
takes the Java source file and compiles it into a servlet class file
using whichever Java compiler is installed for the JSP container.

Although just-in-time compilation is a nice feature while you are
developing or debugging an application, you may not want to make the
JSP source available in a deployment package. This is an issue of
both security and licensingalthough the JSP pages should
contain only presentation logic, that's still
intellectual property. If this is the case, you can precompile the
JSP pages and not provide the JSP source code to customers.
You'll have to distribute only the compiled
bytecode, making it harder for the source code to be seen. Once the
JSP pages are compiled into Java class files, you can even run them
through an obfuscator to make it harder for them to be viewed through
decompilation tools. Precompiling the JSP pages gives you more
options for dealing with issues like these.

As always, though, there are some downsides to precompiling JSP
pages. For one thing, you lose the ability to update or fix a problem
quickly. Instead of just placing a new JSP file onto the server and
letting the JSP container compile it when it's
accessed, you must do the recompilation by hand and deploy the
servlet class. Another downside is that when some containers detect a
problem with a single JSP, they will stop processing the rest of the
application's JSP pages. When this occurs, you must
make sure that every JSP page compiles successfully before the
container will deploy the web application. Developers may actually
consider this a benefit rather than a disadvantage, but it can be
problematic in production environments if you are trying to make a
quick fix to a bug.

Unfortunately, there's no standard way to precompile
the JSP pages. Each container has a different way of doing it. This
section briefly discusses how to precompile pages using three of the
available containers on the market: Tomcat, Resin, and WebLogic.


16.1.6.1 Precompiling JSP pages with Tomcat

The JSP implementation in Tomcat, which
is called Jasper (or Jasper 2 in Version 5.0), provides a reference
implementation for the latest specification. It's
packaged along with Catalina, the reference implementation of the
latest Servlet specification, inside of Tomcat. The JSP-to-Java
compiler is available as a separate program that can be executed from
the command line. Its job is to convert a JSP page into a Java source
file. From there, a standard Java compiler can convert the source
code into bytecode.

The program is called jspc.bat (or
jspc.sh, depending on which platform
you're using) and is included in the Tomcat
installation directory. Many options can be set to configure
everything from the output directory to the package name of the Java
source. There's even an option that will cause the
compiler to create XML that can be added to the
web.xml file for each JSP page that gets
precompiled. You can do one page at a time or specify an entire web
application.

However, as with many things in Java today, Ant is the preferred way
of compiling a web application, including JSPs. The Tomcat
documentation includes a sample Ant script that will use the
jspc tool to precompile the JSPs. Check the
Tomcat documentation for your particular version of Tomcat. For
Tomcat Version 5.0, see the following link
http://jakarta.apache.org/tomcat/tomcat-5.0-doc/jasper-howtol.


16.1.6.2 Precompiling JSP pages with Resin

To precompile JSP pages using Resin, you
can use the httpd.exe command from the Resin
bin directory, like this:

resin/bin/httpd -conf conf/resin.conf -compile <URL>

Here, the URL is a JSP resource within a web application installed in
Resin.

You can also use the command-line version, like this:

resin/bin/httpd -e <URL>

With this approach, you can compile only a single JSP page at a time,
although you could easily create a script that went through your
entire web application. An easier way to configure this is to use
Ant, as discussed later in this chapter.


Resin 2.1.X had some issues with precompiling JSPs when they used tag
libraries (which all Struts pages do). These issues have been
resolved in Resin 3.0.


16.1.6.3 Precompiling JSP pages with WebLogic

With WebLogic, there are two
approaches to precompiling JSPs. The first approach is to manually
execute the compiler from the command line. This approach is useful
when debugging certain JSP problems.

To run the WebLogic JSP compiler from the command line, you must
execute the following command:

java weblogic.jspc -options fileName

Just replace fileName with the JSP you
need to compile. There are many options that can be added with the
-options flag. For Version 7.0, you can view the
list of options at
http://e-docs.bea.com/wls/docs70/jsp/referencel.
For Version 8.0,
http://e-docs.bea.com/wls/docs81/jsp/referencel
has the available options.

The second approach to precompiling JSPs with WebLogic is to allow
the container to precompile the JSPs when an application is deployed
or first started. To accomplish this, you need to add a
<jsp-descriptor> element.

Using the <jsp-descriptor> element within
the weblogic.xml deployment descriptor, you can
set the precompile parameter to true.

<jsp-descriptor>
<jsp-param>
<param-name>
precompile
</param-name>
<param-value>
true
</param-value>
</jsp-param>
</jsp-descriptor>

When set, WebLogic will compile all of the JSPs when an application
is deployed or redeployed.

However, WebLogic will not deploy the web application if any one of
the JSP pages fails to compile. Once it detects an error compiling a
page, all compilation stops and the web application will not be
deployed until you fix whatever is causing the problem. After fixing
it, you must restart WebLogic to start the process all over again.

One of the major drawbacks to using this option is that the server
will precompile the JSPs every time it's started or
the application is deployed. This can delay how fast the server is
ready to accept incoming requests for the application. To avoid this
problem, you can precompile the JSPs into .class
files using the WebLogic JSP compiler and include them in the
WEB-INF/classes directory of the WAR. You will
also need to add the following
<jsp-descriptor> elements in the WebLogic
deployment descriptor.

<jsp-descriptor> 
<jsp-param>
<param-name>precompile</param-name>
<param-value>false</param-value>
</jsp-param>
<jsp-param>
<param-name>pageCheckSeconds</param-name>
<param-value>-1</param-value>
</jsp-param>
</jsp-descriptor>


16.1.7 Packaging EJB Resources with Struts


If you're communicating
with EJBs in the middle tier, it might be necessary to package some
of the EJB resources along with your web application package. Because
the web tier acts as a client to the EJB server, certain resources
are required to connect and communicate with the beans.

The beans' home and remote interfaces, for example,
need to be packaged either in the classes
directory or as a JAR file in the lib directory
of the web application. Also, some of the JNDI classes need to be
included so that clients can acquire home and remote objects. The
actual client-side EJB stub classes are not required, however. This
wasn't always the case, but the latest specification
now describes a mechanism that allows these to be automatically
downloaded when a request is made using an EJB remote interface.

In many cases, it's enough to put the EJB container
JAR file in the WEB-INF/lib directory. For
example, if you are using WebLogic, you can put the
weblogic. jar file in the web tier, as it
contains all of the necessary client-side resources. You will also
need to include any Data Transfer Objects being referenced by the two
tiers. They will need to be included on both sides.


    / 181