Import Tags — Functional Description

<c:import>
<c:param>
<c:urlEncode>


1. Introduction

In the JSP specification, a <jsp:include .../> element provides for the inclusion of static and dynamic resources in the same context as the current page. This is a very convenient feature that is widely used by page authors.

However, <jsp:include> falls short in flexibility and efficiency when page authors need to get access to resources that reside outside of the web application, as well as when the content of the imported resource is used as the source for a companion process/transformation element. More specifically:

Limited to web-app resources

<jsp:include> only supports the inclusion of resources within the same web application. In many situations, page authors have the need to import the content of internet resources specified via an absolute URL. Moreover, as sites grow in size, they may have to be implemented as a set of web applications where importing resources across web-applications is a requirement.

Unnecessary buffering when the resource included is fed into another element

In the example below, the <transform> element uses the content of the included resource as the input of its transformation. The <jsp:include> reads the content of the response, writes it to the body content of the enclosing <transform> element, which then re-reads the exact same content. It would be more efficient if the <transform> element could access the input source directly and avoid the buffering involved in the body content of the <transform> tag.

  <acme:transform>
      <jsp:include page="/exec/employeesList"/>
  <acme:transform/>

The <import> tag has been designed to address the above shortcomings.

2. <import>

There is a wide variety of resources that a page author might be interested in including and/or processing within a JSP page. For instance, the example below shows how the content of the README file at the ftp site of acme.com could be included within the page.

<c:import url="ftp://ftp.acme.com/README"/>

The main motivation behind <import> is to provide a simple, straightforward mechanism to access resources that can be specified via a URL, nothing more. If accessing a resource requires specifying more arguments, then a protocol specific action (e.g. an <http> action) should be used for that purpose. JSTL1.0 does not currently address these protocol specific elements but may do so in future releases.

<import> is therefore the simple, generic way to access URL based resources whose content can then be included and or processed within the JSP page.

Exporting an object: String or Reader

By default, the content of the resource is included inline into the JSP page.

It is also possible to export the content of the resource in two different ways: as a String object (attribute "var"), or as a Reader object (attribute "varReader"). Process/Transform tags can get access to a resource's content through that exported object. Only one of "var" and "varReader" can be specified.

Simplest way to export the resource content as an object is via the "var" atttibute. The data is cached in a String object and is reusable.

Although more complex in its usage, there may be some performance gains if the resource content is exported as a Reader object (instead of String object). Depending on the implementation and on the type of URL being accessed, it may be possible to access the content directly, without any unnecessary buffering. But please note that there are no performance guarantees; this is an implementation detail.

The use of the varReader attribute comes with some restrictions. It is the responsibility of the <import> tag to ensure that if a Reader object is exported, it is properly closed by the end of the page.
[If the responsibility was left to the consumer tag, this could lead to resource leaks (e.g. connection left open, memory space for buffers) until garbage collection is activated if a consumer tag would not close the Reader, or simply if the page author would remove the consumer tag while leaving inadvertantly the <import> tag in the page.]

Because of this, the visibility of a varReader object is nested, so that the Reader may be properly closed when reaching the closing </import>. It therefore makes sense to export a Reader object only when the <import> has nested content that consumes the resource. Using a bodyless <import> tag with varReader is flagged as an error at translation time.
[This restriction could eventually be lifted when the JSP spec supports the notion of page events that actions could register to. On a pageExit event, an <import> tag would then simply release its resources if it had not already been done, removing the requirement for nested visibility. An RFE has been submitted to the JSP expert group.]

It is also illegal to use nested <param> tags with varReader.
[Because varReader takes an arbitrary body and exposes a Reader for it, it needs to open a connection when the start tag is encountered. But if it opens the connection there, it won't have had a chance to hear from its <param> subtags (which modify the URL that <import> connects to).]

Character Encoding

When the var attribute is used to expose a Reader object, it is possible to specify the character encoding of the content at the input resource. For example:

  <c:import url="..." varReader="doc" charEncoding="..."/>

If the character encoding is not specified, the following rules apply:

Note that the charEncoding attribute should normally only be required when accessing absolute URL resources where the protocol is not HTTP, and where the encoding is not ISO-8859-1.

Also, when dealing with relative URLs and the HTTP protocol, if the target resource declares a content encoding but proceeds to write a character invalid in that encoding, the treatment of that character is undefined.

3. Relative and Absolute URLs

The url attribute is used to specify the URL of the resource to access. It can either be an absolute URL (i.e. one that starts with a protocol followed by a colon), a relative URL used to access a resource within the same context, or a relative URL used to access a resource within a foreign context (context name must be specified).

The exact semantics of the <import> tag depends on what type of URL is being accessed.

Relative URL - same context

This is processed in the exact same way as the standard include action (<jsp:include>) of the JSP specification. The resource belongs to the same web-app as the including page and it is specified as a relative URL. For example:

  <c:import url="/copyright.html"/>

As specified in the JSP spec, a relative URL may either be a context-relative path, or a page-relative path. A context-relative path is a path that starts with a “/”. It is to be interpreted as relative to the application to which the JSP page belongs. A page-relative path is a path that does not start with a “/”. It is to be interpreted as relative to the current JSP page.

The semantics of importing a resource specified with a relative URL in the same context are the same as an include performed by a RequestDispatcher in the Servlet specification. This means that the whole environment (request, session, application) of the importing page is available to the target resource (including request parameters of the importing page).

Relative URL - foreign context

The resource belongs to a foreign context (web application) hosted under the same container as the importing page. The context name for the resource is specified via argument "context". For example:

  <c:import url="/logo.html" context="/master"/>

The relative URL must be context-relative (i.e. must start with a "/") since the including page does not belong to the same context. Similarly, the context name must also start with a "/".

The semantics of importing a resource specified with a relative URL in a foreign context are the same as an include performed by a RequestDispatcher on a foreign context in the Servlet specification. This means that only the "request" environment of the importing page is available to the target resource.

It is important to note though that importing resources in foreign contexts may not work in all containers. A security conscious environment may not allow access to foreign contexts. As a workaround, a foreign context resource can also be accessed using an absolute URL. For example:

  <c:import url="http://www.acme.com/master/logo.html"/>

However, it is much more efficient to use a relative URL because the resource is then accessed using RequestDispatcher of the servlet API.

Absolute URL

Given that JSP1.2 assumes a J2SE platform at a minimum, the <import> tag therefore supports at a minimum the protocols offered in that platform for absolute URLs. More protocols can still be available to a web application, but this will depend on the the class libraries made available to the webapp by the platform the container runs on.

The example below shows how a request is sent to a remote site to obtain a list of customers, and how that list is then used as input to a notification tag.

  <c:import url="http://acme.com/exec/customers?country=USA" var="customers"/>
<acme:notify in="$customers"/>

When using an absolute URL to import a resource, none of the current execution environment (request, session, application) is made available to the target resource, even if that absolute URL resolves to the same host and context path. Therefore, the request parameters of the importing page are not propagated to the target "absolute URL".

4. <urlEncode>

URL encoding refers to the process of encoding special characters in a string, according to the encoding rules defined in RFC 1738 (section 2.2. URL Character Encoding Issues).

For example, a space must be encoded in a URL string as a '+':

http://www.acme.com/app/register?name=Aristide+Bertrand&country=Republique+Dominicaine

The <urlEncode> action will encode the string specified in attribute 'value'. If the value attribute is not specified, encoding is performed on the tag's body content.

By default, the result of the encoding is written to the page. It is also possible to export the result of the encoding as a JSP scoped attribute (java.lang.String) defined via attribute "var". For example:

  <urlEncode var="nameEncoded" value="$name"/>

With respect to the <import> tag, it is important to note that all URLs need to be encoded. However, URL encoding is normally necessary only when dealing with query string parameters.

For example, assuming the following absolute URL

http://www.acme.com/app/register

to which two query string parameters must be passed: "name" and "country", both of which are retrieved from JSP scoped attributes. Since special characters can be part of these scoped attributes, they must be encoded before they can be added to the URL. This could be done as follows:

<urlEncode var="nameEncoded" value="$name"/>
<urlEncode var="countryEncoded" value="$country"/>
<c:import url="$'http://www.acme.com/app/register?name='+nameEncoded+'&country='+countryEncoded"/>

However this is somewhat awkward. A better way is to use nested <param> tags to specify the query string parameters to be added to the URL. As a convenience, the <param> action has been designed such that query string parameters (both "name" and "value") are automatically encoded for the <import> action. The following could therefore be used without having to worry about any encoding:

<c:import url="http://www.acme.com/app/register">
  <param name="name" value="$name"/>
  <param name="country" value="$country"/>
</c:import>

5. <param>

The <param> element can be used with <import> to specify request parameters.

One might argue that this is redundant given that the URL can be constructed to include query string parameters.

For example:

  <c:import url="/exec/doIt>
<c:param name="action" value="register"/>
</c:import>

is the same as:

  <c:import url="/exec/doIt?action=register"/>

It is indeed redundant, but is consistent with <jsp:include> supporting nested <jsp:param> sub-elements. Moreover, it has been designed such that the parameter "name" and "value" are automatically url encoded (as described in the previous section). Automatic encoding can be disabled using optional attribute "encode", whose value defaults to "true" otherwise.

It is important to note that that the query parameter aggregation rules work the same way they do with <jsp:include>; the original parameters are augmented with the new parameters, with new values taking precedence over existing values when applicable.The scope of the new parameters is the import call; the new parameters (and values) will not apply after the import. This is the same behavior as in the ServletRequest include and forward methods (see Section 8.1.1 in the Servlet 2.2 specification).

For example:

  <c:import url="http://acme.com/exec/doIt?foo=foovalOne"/>
<c:param name="foo" value="fooval 2"/>
<c:param name="bar" value="bar value"/>
</c:import>
modifies the absolute URL as follows:
  http://acme.com/exec/doIt?foo=fooval+2&bar=bar+value&foo=foovalOne

5. Summary

Import Tags
Element Sample usage

<import>
url var varReader charEncoding context

Action for a simple, generic way to access URL based resources. Extends <jsp:include> to support foreign contexts and absolute URLs, as well as to export an object for explicit collaboration with process/transformation tags (avoiding unnecessary buffering).

<c:import url="ftp://ftp.acme.com/README"/>

<c:import url="/xml/doc.xml" varReader="in"/>
<acme:process in="$in"
/>

<param>
name value encode

Sub-element to specify request parameters for the enclosing <import>. The name and value of the parameter are url encoded (unless encode is false).

<c:import url="/exec/register">
  <c:param name="id" value="foo"/>
</c:import>

<urlEncode>
value var

URL encoding.

<a href="http://acme.com/register
   ?name=<c:urlEncode value='$name'/>"/>

6. Networking Properties

If the web container executes behind a firewall, some absolute URL resources may be inaccessible. To provide access to these resources, the JVM of the container should be started with the proper networking properties (e.g. proxyHost, proxyPort). More details can be found in the Java 2 SDK, Standard Edition Documentation (Networking Features — Networking Properties).

7. Notes

8. Design decisions of interest

We know you'd eventually ask these questions. Here are the answers...

Transparently map absolute URLs to relative ones when possible? No.

If a resource is specified as an absolute URL, it may still refer to a resource located on the same container (same or foreign context). Why not have the <import> tag transparently map absolute URLs to relative ones when possible to improve performance?

We've decided against it simply because doing things behind the scenes may lead to confusion. Users should understand the difference between absolute and relative URLs, and the impact of using one vs the other in terms of performance as well as execution environment of the imported resource.

So, even if a request with an absolute URL does go back to the same webapp, we are not propogating session identity either.

Transparently map foreign context relative URLs to absolute URLs in "security conscious" containers? No.

If accessing a resource in a foreign context using a relative URL fails (security conscious container that does not allow it), why not design the tag so it transparently maps the foreign context relative URL to an absolute URL?

We've decided against it because for the same reason as above, as well as for portability concerns. In container X, the resource might be accessed via RequestDispatcher and has therefore access to request attributes, the foreign context session and application environment. However, if in container Y the resource is accessed via a new HTTP request, the resource is not accessed with that same environment.