Вы находитесь на странице: 1из 19

Vamos a ver cmo leer desde java una pgina web ofrecida por un servidor http, por un servidor

https que no requiere certificado de cliente y por un servidor https que s requiere certificado de
cliente.
Primero haremos aproximaciones con cdigo java. Al final un ejemplo sin tanto rollo de cdigo,
pero usando las System Properties de java.

Servidor http
El cdigo para leer una pgina web ofrecido por un servidor http normalito puede ser el siguiente
package com.chuidiang.ejemplos;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class PruebaHTTP {
public static void main(String[] args) {
try {
// Se abre la conexin
URL url = new URL("http://www.chuidiang.com");
URLConnection conexion = url.openConnection();
conexion.connect();

// Lectura
InputStream is = conexion.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
char[] buffer = new char[1000];
int leido;
while ((leido = br.read(buffer)) > 0) {
System.out.println(new String(buffer, 0, leido));
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
El cdigo es sencillo. Hacemos un new URL() con la URL en cuestin. Llamamos al mtodo
openConnection() y luego connect(). Slo nos queda obtener el InputStream de lectura y leer en l
como mejor nos venga para nuestras necesidades. En el ejemplo vamos leyendo en buffer de
caracteres y sacndolo por pantalla, por lo que obtendremos en pantalla el texto html de la pgina
cuya URL hemos abierto (suponiendo que esa URL tenga un texto html).

Servidor https que no requiere certificado de cliente
Cuando se abre una conexin con https contra un servidor, el servidor nos presenta un certificado
digital. El cliente debe decidir si acepta o no ese certificado digital. Todos hemos visto esto en
alguna ocasin cuando navegamos por internet. Las pginas https que usamos ofrecen un
certificado digital. Si nuestro navegador confa en l, todo va de perlas. Si nuestro navegador no
confa en ese certificado, nos mostrar un aviso de si estamos seguros que queremos visitar esa
pgina.
El cdigo para leer de un servidor https que no requiere certificado de cliente es en principio
exactamente igual que el anterior salvo por dos pequeos detalles:
En la URL, en vez de http://.... ponemos https://.....
Debemos indicar a nuestro cdigo java en qu certificados de servidor confiamos. Si no
obtendremos error.
Para indicar a nuestro cdigo java los certificados en los que debe confiar, necesitamos tener esos
certificados en ficheros. Cualquier navegador, visitando la pgina en cuestin, suele ofrecer en
algn sitio la posibilidad de ver los detalles del certificado del servidor y guardarlos. En la barra de
la URL del navegador suele aparecer un candadito cuando visitamos una pgina https. Pinchando
el candadito podremos ver los datos del certificado y en la ventana que sale tenemos opcin de
guardarlo en algn fichero.
Una vez que tenemos el o todos los certificados necesarios, debemos guardarlos en un nico
fichero de almacn de certificados. Podemos hacerlo, entre otras, con openssl o con keytool.
Vamos con esta ltima puesto que viene con java. Si hemos guardador los distintos certificados en
servidor1.cer, servidor2.cer, etc, el comando para crear el almacn de certificados de esta manera
keytool -importcert -alias servidor1 -keystore .keystore -file servidor1.cer
keytool -importcert -alias servidor2 -keystore .keystore -file servidor2.cer
...
A cada certificado debemos darle un "alias" distinto para identrificarlo dentro del almacn. En el
ejemplo los hemos llamado servidor1 y servidor2. Con -keystore .keystore estamos indicando que
nuestro fichero de almacn ser ".keystore", podemos darle el nombre que queramos, pero
usaremos el mismo nombre cada vez si queremos que los distintos certificados se vayan
aadiendo a ese fichero. Finalmente, con -file vamos indicando cada uno de los certificados que
nos hemos bajado con el navegador. Al ejecutar estos comandos nos pedir una password. Puede
ser la que queramos, pero es importante que recordarla, ya que es la que nos permitir leer ms
adelante el contenido de ese fichero, aadir ms certificados o borrar los existentes. Esa password
deberemos usarla tambin en nuestro cdigo java.
El cdigo java para leer el contenido de una pgina ofrecida bajo https puede ser como este
package com.chuidiang.ejemplos;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class PruebaHTTPSOneWay {
public static void main(String[] args) {
try {
// Carga del fichero que tiene los certificados de los servidores en
// los que confiamos.
InputStream fileCertificadosConfianza = new FileInputStream(new File(
"c:/unpath/.keystore"));
KeyStore ksCertificadosConfianza = KeyStore.getInstance(KeyStore
.getDefaultType());
ksCertificadosConfianza.load(fileCertificadosConfianza,
"unaPassword".toCharArray());
fileCertificadosConfianza.close();

// Ponemos el contenido en nuestro manager de certificados de
// confianza.
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ksCertificadosConfianza);

// Creamos un contexto SSL con nuestro manager de certificados en los
// que confiamos.
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
SSLSocketFactory sslSocketFactory = context.getSocketFactory();

// Abrimos la conexin y le pasamos nuestro contexto SSL
URL url = new URL("https://una.url.com");
URLConnection conexion = url.openConnection();
((HttpsURLConnection) conexion).setSSLSocketFactory(sslSocketFactory);

// Ya podemos conectar y leer
conexion.connect();
InputStream is = conexion.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
char[] buffer = new char[1000];
int leido;
while ((leido = br.read(buffer)) > 0) {
System.out.println(new String(buffer, 0, leido));
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (CertificateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

En el primer bloque de cdigo leemos el fichero de almacn de certificados que generamos con
keytool. Debemos indicar la password que usamos para crear ese fichero almacn. Tambin
debemos indicar de qu tipo es el fichero almacn, con la lnea que dice
KeyStore.getInstance(KeyStore.getDefaultType()). El defaultType, cmo no, es el formato que usa
java y la herramienta keytool.
Dejamos el segundo bloque para explicar despus.
En el tercer bloque creamos un contexto SSL y a l tenemos que pasarle un TrutManager (en
realidad un array de TrustManager). Este TrusManager no es ms que una clase a la que el socket
SSL (nuestra conexin https) preguntar si un certificado ofrecido por un servidor es o no vlido.
Este TrusManager se pasa como segundo parmetro en el mtodo context.init() del SSLContext.
Y cmo obtenemos ese TrusManager a partir de nuestro almacn .keystore?. A travs de una
fbrica de TrusManager, es decir, a partir de la clase TrustManagerFactory. Ese es nuestro
segundo bloque de cdigo. Obtenemos esa fbrica con el mtodo
TrustManagerFactory.getInstante() y la inicializamos con el KeyStore que cargamos en el primer
paso.
Ya slo nos queda preparar la conexin como hicimos antes, pasarle nuestro contexto SSL y leer
de la forma habitual.
Servidor https que requiere certificado de cliente
El certificado de cliente es un fichero que normalmente alguien nos proporcionar para que
podamos acceder a un servidor que lo requiera. Sin l no podremos acceder. Este fichero suele
tener extensin .p12 y debemos cargarlo tambin en nuestro cdigo java de una forma similar a
como hicimos con el almacen de certificados de servidor que admitimos.
El cdigo java puede ser como este
package com.chuidiang.ejemplos;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class PruebaHTTPSTwoWay {
public static void main(String[] args) {
try {
// Carga del fichero que tiene los certificados de los servidores en
// los que confiamos.
InputStream fileCertificadosConfianza = new FileInputStream(new File(
"c:/unpath/.keystore"));
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(fileCertificadosConfianza, "unaPassword".toCharArray());
fileCertificadosConfianza.close();

// Ponemos el contenido en nuestro manager de certificados de
// confianza.
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);

// Cargamos el fichero con el certificado de cliente
InputStream fileCertificadoCliente = new FileInputStream(
new File(
"c:/unpath/unCertificadoCliente.p12"));
KeyStore ksCliente = KeyStore.getInstance("PKCS12");
ksCliente.load(fileCertificadoCliente, "unaPassword".toCharArray());
fileCertificadoCliente.close();

// Creamos un manager de certificados con nuestro certificado de
// cliente
KeyManagerFactory kmf = KeyManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ksCliente, "unaPassword".toCharArray());

// Creamos un contexto SSL tanto con el manger de certificados de
// servidor en los que confiamos como con el manager de certificados de
// cliente de los que disponemos
SSLContext context = SSLContext.getInstance("TLS");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLSocketFactory sslSocketFactory = context.getSocketFactory();

// Abrimos la conexin y le pasamos el contexto SSL que hemos creado
URL url = new URL("https://un.servidor.que.requiere.certificado.cliente.com");
URLConnection conexion = url.openConnection();
((HttpsURLConnection) conexion).setSSLSocketFactory(sslSocketFactory);

// Ya podemos leer.
conexion.connect();
InputStream is = conexion.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
char[] buffer = new char[1000];
int leido;
while ((leido = br.read(buffer)) > 0) {
System.out.println(new String(buffer, 0, leido));
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (CertificateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
El cdigo es bsicamente igual al del ejemplo anterior, pero hemos aadido la carga del certificado
de cliente.
En un primero trozo de cdigo, cargamos en un KeyStore el certificado de cliente
unCertificadoCliente.p12
Como al contexto SSL tendremos que pasarle, adems del TrustManager anterior, un KeyManager
con la clave de cliente, primero obtenemos una fbrica de KeyManager (un KeyManagerFactory) al
que inicializamos con el KeyStore que es el certificado de cliente. Este KeyManagerFactory nos
permitir obtener el KeyManager que pasaremos, un poco ms abajo, como primer parmetro del
contexto SSL.
Ahora slo queda pasar el contexto SSL a la URLConnection, abrirla y leer de la forma habitual.
Un detalle nada ms. Un certificado de cliente p12 est en un formato PKCS12, por eso en el
KeyStore usamos un getInstance("PKCS12") en vez de un getDefaultType(), que corresponde a
"JKS" que es el formato por defecto que da keytool a los almacenes de certificados. Tambin
tenemos que pasar la clave que habitualmente protege estos certificados.

https usando java system properties
Podemos hacer este ltimo ejemplo sin necesidad de tanto cdigo. Nos bastara con configurar
todo usando las System Properties de java. El cdigo quedara tan sencillo como esto
package com.chuidiang.ejemplos;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class PruebaHTTPSTwoWayProperties {
public static void main(String[] args) {
try {
System.setProperty("javax.net.ssl.trustStore", "c:/unpat/.keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "unaPassword");
System.setProperty("javax.net.ssl.trustStoreType", "JKS");

System.setProperty("javax.net.ssl.keyStore", "c:/unpath/unCertificadoCliente.p12");
System.setProperty("javax.net.ssl.keyStorePassword", "unaPassword");
System.setProperty("javax.net.ssl.keyStoreType", "PKCS12");

// Abrimos la conexin y le pasamos el contexto SSL que hemos creado
URL url = new URL("https://un.servidor.que.requiere.certificado.cliente.com");
URLConnection conexion = url.openConnection();

// Ya podemos leer.
conexion.connect();
InputStream is = conexion.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
char[] buffer = new char[1000];
int leido;
while ((leido = br.read(buffer)) > 0) {
System.out.println(new String(buffer, 0, leido));
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
La diferencia es que estas propiedades afectaran a todo nuestro programa en java. Puede ser
efectivo si todas nuestras conexiones van a usar y admitir los mismos certificados. Sin embargo si
queremos que nuestro programa abra diferentes conexiones usando/admitiendo diferentes
conjuntos de certificados, debemos hacerlo con cdigo, ya que ah podemos pasar un SSLContext
especfico a cada conexin que abramos.

JavaBeans Component Design Conventions
JavaBeans component design conventions govern the properties of the class and govern the public methods
that give access to the properties.
A JavaBeans component property can be
Read/write, read-only, or write-only
Simple, which means it contains a single value, or indexed, which means it represents an
array of values
There is no requirement that a property be implemented by an instance variable; the property must simply be
accessible using public methods that conform to certain conventions:
For each readable property, the bean must have a method of the form
PropertyClass getProperty() { ... }
For each writable property, the bean must have a method of the form
setProperty(PropertyClass pc) { ... }
In addition to the property methods, a JavaBeans component must define a constructor that takes no
parameters.
The Duke's Bookstore application JSP pages enter.jsp, bookdetails.jsp, catalog.jsp, and
showcart.jsp use the database.BookDB and database.BookDetails JavaBeans components.
BookDB provides a JavaBeans component front end to the access object BookDBAO. Both beans are used
extensively by bean-oriented custom tags (see Custom Tags in JSP Pages). The JSP pages
showcart.jsp and cashier.jsp use cart.ShoppingCart to represent a user's shopping cart.
The JSP pages catalog.jsp, showcart.jsp, and cashier.jsp use the util.Currency
JavaBeans component to format currency in a locale-sensitive manner. The bean has two writable properties,
locale and amount, and one readable property, format. The format property does not correspond to
any instance variable, but returns a function of the locale and amount properties.
public class Currency {
private Locale locale;
private double amount;
public Currency() {
locale = null;
amount = 0.0;
}
public void setLocale(Locale l) {
locale = l;
}
public void setAmount(double a) {
amount = a;
}
public String getFormat() {
NumberFormat nf =
NumberFormat.getCurrencyInstance(locale);
return nf.format(amount);
}
}
Why Use a JavaBeans Component?
A JSP page can create and use any type of Java programming language object within a declaration or
scriptlet. The following scriptlet creates the bookstore shopping cart and stores it as a session attribute:
<%
ShoppingCart cart = (ShoppingCart)session.
getAttribute("cart");
// If the user has no cart, create a new one
if (cart == null) {
cart = new ShoppingCart();
session.setAttribute("cart", cart);
}
%>
If the shopping cart object conforms to JavaBeans conventions, JSP pages can use JSP elements to create
and access the object. For example, the Duke's Bookstore pages bookdetails.jsp, catalog.jsp,
and showcart.jsp replace the scriptlet with the much more concise JSP useBean element:
<jsp:useBean id="cart" class="cart.ShoppingCart"
scope="session"/>
Creating and Using a JavaBeans Component
You declare that your JSP page will use a JavaBeans component using either one of the following formats:
<jsp:useBean id="beanName"
class="fully_qualified_classname" scope="scope"/>
or
<jsp:useBean id="beanName"
class="fully_qualified_classname" scope="scope">
<jsp:setProperty .../>
</jsp:useBean>
The second format is used when you want to include jsp:setProperty statements, described in the next
section, for initializing bean properties.
The jsp:useBean element declares that the page will use a bean that is stored within and accessible from
the specified scope, which can be application, session, request, or page. If no such bean exists,
the statement creates the bean and stores it as an attribute of the scope object (see Using Scope Objects).
The value of the id attribute determines the name of the bean in the scope and the identifier used to reference
the bean in other JSP elements and scriptlets.

Note: In JSP Scripting Elements , we mentioned that you must import any classes and packages used by a
JSP page. This rule is slightly altered if the class is only referenced by useBean elements. In these cases,
you must only import the class if the class is in the unnamed package. For example, in What Is a JSP Page? ,
the page index.jsp imports the MyLocales class. However, in the Duke's Bookstore example, all classes
are contained in packages and thus are not explicitly imported.

The following element creates an instance of Currency if none exists, stores it as an attribute of the
session object, and makes the bean available throughout the session by the identifier currency:
<jsp:useBean id="currency" class="util.Currency"
scope="session"/>
Setting JavaBeans Component Properties
There are two ways to set JavaBeans component properties in a JSP page: with the jsp:setProperty
element or with a scriptlet
<% beanName.setPropName(value); %>
The syntax of the jsp:setProperty element depends on the source of the property value. Table 4-3
summarizes the various ways to set a property of a JavaBeans component using the jsp:setProperty
element.
Table 4-3 Setting JavaBeans Component Properties
Value Source Element Syntax
String constant
<jsp:setProperty name="beanName"
property="propName" value="string constant"/>
Request parameter
<jsp:setProperty name="beanName"
property="propName" param="paramName"/>
Request parameter name matches
bean property
<jsp:setProperty name="beanName"
property="propName"/>

<jsp:setProperty name="beanName"
property="*"/>
Expression
<jsp:setProperty name="beanName"
property="propName"
value="<%= expression %>"/>

1. beanName must be the same as that specified for the id attribute in
a useBean element.
2. There must be a setPropName method in the JavaBeans
component.
3. paramName must be a request parameter name.
A property set from a constant string or request parameter must have a type listed in Table 4-4. Since both a
constant and request parameter are strings, the Web container automatically converts the value to the
property's type; the conversion applied is shown in the table. String values can be used to assign values to
a property that has a PropertyEditor class. When that is the case, the setAsText(String) method
is used. A conversion failure arises if the method throws an IllegalArgumentException. The value
assigned to an indexed property must be an array, and the rules just described apply to the elements.
Table 4-4 Valid Value Assignments
Property Type Conversion on String Value
Bean Property Uses setAsText(string-literal)
boolean or Boolean As indicated in java.lang.Boolean.valueOf(String)
byte or Byte As indicated in java.lang.Byte.valueOf(String)
char or Character As indicated in java.lang.String.charAt(0)
double or Double As indicated in java.lang.Double.valueOf(String)
int or Integer As indicated in java.lang.Integer.valueOf(String)
float or Float As indicated in java.lang.Float.valueOf(String)
long or Long As indicated in java.lang.Long.valueOf(String)
short or Short As indicated in java.lang.Short.valueOf(String)
Object new String(string-literal)
You would use a runtime expression to set the value of a property whose type is a compound Java
programming language type. Recall from Expressions that a JSP expression is used to insert the value of a
scripting language expression, converted into a String, into the stream returned to the client. When used within
a setProperty element, an expression simply returns its value; no automatic conversion is performed. As a
consequence, the type returned from an expression must match or be castable to the type of the property.
The Duke's Bookstore application demonstrates how to use the setProperty element and a scriptlet to set
the current book for the database helper bean. For example, bookstore3/bookdetails.jsp uses the
form:
<jsp:setProperty name="bookDB" property="bookId"/>
whereas bookstore2/bookdetails.jsp uses the form:
<% bookDB.setBookId(bookId); %>
The following fragments from the page bookstore3/showcart.jsp illustrate how to initialize a currency
bean with a Locale object and amount determined by evaluating request-time expressions. Because the first
initialization is nested in a useBean element, it is only executed when the bean is created.
<jsp:useBean id="currency" class="util.Currency"
scope="session">
<jsp:setProperty name="currency" property="locale"
value="<%= request.getLocale() %>"/>
</jsp:useBean>
<jsp:setProperty name="currency" property="amount"
value="<%=cart.getTotal()%>"/>
Retrieving JavaBeans Component Properties
There are several ways to retrieve JavaBeans component properties. Two of the methods (the
jsp:getProperty element and an expression) convert the value of the property into a String and insert
the value into the current implicit out object:
<jsp:getProperty name="beanName" property="propName"/>
<%= beanName.getPropName() %>
For both methods, beanName must be the same as that specified for the id attribute in a useBean element,
and there must be a getPropName method in the JavaBeans component.
If you need to retrieve the value of a property without converting it and inserting it into the out object, you must
use a scriptlet:
<% Object o = beanName.getPropName(); %>
Note the differences between the expression and the scriptlet; the expression has an = after the opening %
and does not terminate with a semicolon, as does the scriptlet.
The Duke's Bookstore application demonstrates how to use both forms to retrieve the formatted currency from
the currency bean and insert it into the page. For example, bookstore3/showcart.jsp uses the form
<jsp:getProperty name="currency" property="format"/>
whereas bookstore2/showcart.jsp uses the form:
<%= currency.getFormat() %>
The Duke's Bookstore application page bookstore2/showcart.jsp uses the following scriptlet to
retrieve the number of books from the shopping cart bean and open a conditional insertion of text into the
output stream:
<%
// Print a summary of the shopping cart
int num = cart.getNumberOfItems();
if (num > 0) {
%>
Although scriptlets are very useful for dynamic processing, using custom tags (see Custom Tags in JSP
Pages) to access object properties and perform flow control is considered to be a better approach. For
example, bookstore3/showcart.jsp replaces the scriptlet with the following custom tags:
<bean:define id="num" name="cart" property="numberOfItems" />
<logic:greaterThan name="num" value="0" >
Figure 4-4 summarizes where various types of objects are stored and how those objects can be accessed from
a JSP page. Objects created by the jsp:useBean tag are stored as attributes of the scope objects and can
be accessed by jsp:[get|set]Property tags and in scriptlets and expressions. Objects created in
declarations and scriptlets are stored as variables of the JSP page's servlet class and can be accessed in
scriptlets and expressions.

Figure 4-4 Accessing Objects From a JSP Page