Vamos a comenzar la creación del código fuente del un applet que satisfaga nuestras necesidades. Recordamos que Java utiliza la extensión .java para designar los ficheros fuente.
HolaMundo
A continuación está el código fuente del applet HolaMundo, que es la versión applet de la mínima aplicación Java que antes habíamos escrito. Guardar este código en un fichero fuente Java como HolaMundo.java.
//
// Applet HolaMundo de ejemplo
//
import java.awt.Graphics;
import java.applet.Applet;
public class HolaMundo extends Applet {
public void paint( Graphics g ) {
g.drawString( "Hola Mundo!",25,25 ) ;
}
}
Componentes básicos de un Applet
El lenguaje Java implementa un modelo de Programación Orientada a Objetos. Los objetos sirven de bloques centrales de construcción de los programas Java. De la misma forma que otros lenguajes de programación, Java tiene variables de estado y métodos.
Veamos como se descompone un applet en sus piezas/objetos:
/*
Sección de importaciones
*/
public class NombreDelNuevoApplet extends Applet {
/*
Aquí se declaran las variables de estado (public y private)
*/
/*
Los métodos para la interacción con los objetos se
declaran y definen aquí
*/
public void MetodoUno( parámetros ) {
/*
Aquí viene para cada método, el código Java que
desempeña la tarea.
Qué código se use depende del applet
*/
}
}
Para HolaMundo, se importan las dos clases que necesita. No hay variables de estado, y sólo se tiene que definir un método para que el applet tenga el comportamiento esperado.
Clases incluidas
El comando import carga otras clases dentro de nuestro código fuente. El importar una clase desde un paquete de Java hace que esa clase importada esté disponible para todo el código incluido en el fichero fuente Java que la importa. Por ejemplo, en el applet HolaMundo se importa la clase java.awt.Graphics, y podremos llamar a los métodos de esta clase desde cualquier método de nuestro programa que se encuentre en el fichero HolaMundo.java. Esta clase define una área gráfica y métodos para poder dibujar dentro de ella. La función paint() declara a g como un objeto de tipo Graphics; luego, paint() usa el método drawString() de la clase Graphics para generar su salida.
La clase Applet
Se puede crear una nueva clase, en este caso HolaMundo, extendiendo la clase básica de Java: Applet. De esta forma, se hereda todo lo necesario para crear un applet. Modificando determinados métodos del applet, podemos lograr que lleve a cabo las funciones que deseamos.
import java.applet.Applet;
. . .
public class HolaMundo extends Applet {
Métodos de Applet
La parte del applet a modificar es el método paint(). En la clase Applet, se llama al método paint() cada vez que el método arranca o necesita ser refrescado, pero no hace nada. En nuestro caso, lo que hacemos es:
public void paint( Graphics g ) {
g.drawString( "Hola Mundo!",25,25 );
}
De acuerdo a las normas de sobrecarga, se ejecutará este último paint() y no el paint() vacío de la clase Applet. Luego, aquí se ejecuta el método drawString(), que le dice al applet cómo debe aparecer un texto en el área de dibujo.
Otros métodos básicos para dibujar son:
drawLine( int x1,int y1,int x2,int y2 )
drawRect( int x,int y,int ancho,int alto )
drawOval( int x,int y,int ancho,int alto )
Tanto para drawRect() como para drawOval(), las coordenadas (x,y) son la esquina superior izquierda del rectángulo (para drawOval, el óvalo es encajado en el rectángulo que lo circunscribe).
Ahora que tenemos el código de nuestro applet básico y el fichero fuente Java que lo contiene, necesitamos compilarlo y obtener un fichero .class ejecutable. Se utiliza el compilador Java, javac, para realizar la tarea. El comando de compilación será:
%javac HolaMundo.java
Eso es todo. El compilador javac generará un fichero HolaMundo.class que podrá ser llamado desde cualquier navegador con soporte Java y, por tanto, capaz de ejecutar applets Java.
¿Qué tienen de especial HotJava, Microsoft Explorer o Netscape con respecto a otros navegadores? Con ellos se puede ver html básico y acceder a todo el texto, gráfico, sonido e hipertexto que se pueda ver con cualquier otro navegador. Pero además, pueden ejecutar applets, que no es html estándar. Ambos navegadores entienden código html que lleve la marca <APPLET>:
<APPLET CODE="SuCodigo.class" WIDTH=100 HEIGHT=50>
</APPLET>
Esta marca html llama al applet SuCodigo.class y establece su ancho y alto inicial. Cuando se acceda a la página Web donde se encuentre incluida la marca, se ejecutará el byte-code contenido en SuCodigo.class, obteniéndose el resultado de la ejecución del applet en la ventana del navegador, con soporte Java, que estemos utilizando.
El JDK, Kit de Desarrollo de Java, incluye el visor de applets básico, appletviewer, que puede utilizarse para la visualización rápida y prueba de nuestros applets, tal como se ha visto ya. La ejecución de un applet sobre appletviewer se realiza a través de la llamada:
%appletviewer fichero.html
En nuestro caso el fichero con el código html que ejecutará nuestro applet HolaMundo es HolaMundo.html que generará la salida que se mostraba en la sección sobre el Ejemplo de uso de appletviewer.
Dado que los applets están mayormente destinados a ejecutarse en navegadores Web, había que preparar el lenguaje HTML para soportar Java, o mejor, los applets. El esquema de marcas de HTML, y la evolución del estándar marcado por Netscape hicieron fácil la adición de una nueva marca que permitiera, una vez añadido el correspondiente código gestor en los navegadores, la ejecución de programas Java en ellos.
La sintaxis de las etiquetas <APPLET> y <PARAM> es la que se muestra a continuación y que iremos explicando en párrafos posteriores:
<APPLET CODE= WIDTH= HEIGTH= [CODEBASE=] [ALT=]
[NAME=] [ALIGN=] [VSPACE=] [HSPACE=]>
<PARAM NAME= VALUE= >
</APPLET>
CODE : Nombre de la clase principal
WIDTH : Anchura inicial
HEIGHT : Altura inicial
CODEBASE : URL base del applet
ALT : Texto alternativo
NAME : Nombre de la instancia
ALIGN : Justificación del applet
VSPACE : Espaciado vertical
HSPACE : Espaciado horizontal
Los applets se incluyen en las páginas Web a través de la marca <APPLET>, que para quien conozca html resultará muy similar a la marca <IMG>. Ambas necesitan la referencia a un fichero fuente que no forma parte de la página en que se encuentran embebidos. IMG hace esto a través de SRC=parámetro y APPLET lo hace a través CODE=parámetro. El parámetro de CODE indica al navegador dónde se encuentra el fichero con el código Java compilado .class. Es una localización relativa al documento fuente.
Por razones que no entiendo muy bien, pero posiblemente relacionadas con los packages y classpaths, si un applet reside en un directorio diferente del que contiene a la página en que se encuentra embebido, entonces no se indica un URL a esta localización, sino que se apunta al directorio del fichero .class utilizando el parámetro CODEBASE, aunque todavía se puede usar CODE para proporcionar el nombre del fichero .class.
Al igual que IMG, APPLET tiene una serie de parámetros que lo posicionan en la página. WIDTH y HEIGHT especifican el tamaño del rectángulo que contendrá al applet, se indican en pixels. ALIGN funciona igual que con IMG (en los navegadores que lo soportan), definiendo cómo se posiciona el rectángulo del applet con respecto a los otros elementos de la página. Los valores posibles a especificar son: LEFT, RIGHT, TOP, TEXTTOP, MIDDLE, ABSMIDDLE, BASELINE, BOTTOM y ABSBOTTOM. Y, finalmente, lo mismo que con IMG, se puede especificar un HSPACE y un VSPACE en pixels para indicar la cantidad de espacio vacío que habrá de separación entre el applet y el texto que le rodea.
APPLET tiene una marca ALT. La utilizaría un navegador que entendiese la marca APPLET, pero que por alguna razón, no pudiese ejecutarlo. Por ejemplo, si un applet necesita escribir en el disco duro de nuestro ordenador, pero en las características de seguridad tenemos bloqueada esa posibilidad, entonces el navegador presentaría el texto asociado a ALT.
ALT no es utilizado por los navegadores que no entienden la marca APPLET, por ello se ha definido la marca </APPLET>, que finaliza la descripción del applet. Un navegador con soporte Java ignorará todo el texto que haya entre las dos marcas< APPLET> y </APPLET>, sin embargo, un navegador que no soporte Java ignorará las marcas y presentará el texto que se encuentre entre ellas.
Los atributos que acompañan a la etiqueta <APPLET>, algunos son obligatorios y otros son opcionales. Todos los atributos, siguiendo la sintaxis de html, se especifican de la forma: atributo=valor. Los atributos obligatorios son:
CODE
Indica el fichero de clase ejecutable, que tiene la extensión .class. No se permite un URL absoluto, como ya se ha dicho, aunque sí puede ser relativo al atributo opcional CODEBASE.
WIDTH
Indica la anchura inicial que el navegador debe reservar para el applet en pixels.
HEIGHT
Indica la altura inicial en pixels. Un applet que disponga de una geometría fija no se verá redimensionado por estos atributos. Por ello, si los atributos definen una zona menor que la que el applet utiliza, únicamente se verá parte del mismo, como si se visualiza a través de una ventana, eso sí, sin ningún tipo de desplazamiento.
Los atributos opcionales que pueden acompañar a la marca APPLET comprenden los que se indican a continuación:
CODEBASE
Se emplea para utilizar el URL base del applet. En caso de no especificarse, se utilizará el mismo que tiene el documento.
ALT
Como ya se ha dicho, funciona exactamente igual que el ALT de la marca <IMG>, es decir, muestra un texto alternativo, en este caso al applet, en navegadores en modo texto o que entiendan la etiqueta APPLET pero no implementen una máquina virtual Java.
NAME
Otorga un nombre simbólico a esta instancia del applet en la página que puede ser empleado por otros applets de la misma página para localizarlo. Así, un applet puede ser cargado varias veces en la misma página tomando un nombre simbólico distinto en cada momento.
ALIGN
Se emplea para alinear el applet permitiendo al texto fluir a su alrededor. Puede tomas los siguientes valores: LEFT, RIGHT, TOP, TEXTTOP, MIDDLE, ABSMIDDLE, BASELINE, BOTTOM y ABSBOTTOM.
VSPACE
Indica el espaciado vertical entre el applet y el texto, en pixels. Sólo funciona cuando se ha indicado ALIGN = LEFT o RIGHT.
HSPACE
Funciona igual que el anterior pero indicando espaciamiento horizontal, en pixels. Sólo funciona cuando se ha indicado ALIGN = LEFT o RIGHT.
Es probable encontrar en algunas distribuciones otras etiquetas para la inclusión de applets, como <APP>. Esto se debe a que estamos ante la tercera revisión de la extensión de HTML para la incrustación de applets y ha sido adoptada como la definitiva. Por ello, cualquier otro medio corresponde a implementaciones obsoletas que han quedado descartadas.
El espacio que queda entre las marcas de apertura y cierre de la definición de un applet, se utiliza para el paso de parámetros al applet. Para ello se utiliza la marca PARAM en la página HTML para indicar los parámetros y el método getParameter() de la clase java.applet.Applet para leerlos en el código interno del applet. La construcción puede repetirse cuantas veces se quiera, una tras otra.
Los atributos que acompañan a la marca PARAM son los siguientes:
NAME
Nombre del parámetro que se desea pasar al applet.
VALUE
Valor que se desea transmitir en el parámetro que se ha indicado antes.
Texto HTML
Texto HTML que será interpretado por los navegadores que no entienden la marca APPLET en sustitución del applet mismo.
Para mostar esta posibilidad vamos a modificar nuestro applet básico HolaMundo para que pueda saludar a cualquiera. Lo que haremos será pasarle al applet el nombre de la persona a quien queremos saludar. Generamos el código para ello y lo guardamos en el fichero HolaTal.java
import java.awt.Graphics;
import java.applet.Applet;
public class HolaTal extends Applet {
String nombre;
public void init() {
nombre = getParameter( "Nombre" );
}
public void paint( Graphics g ) {
g.drawString( "Hola "+nombre+"!",25,25 );
}
}
Si compilamos el ejemplo obtendremos el fichero HolaTal.class que incluiremos en nuestra página Web. Vamos a generar el fichero HolaTal.html, en el que incluiremos nuestro applet, y que debería tener el siguiente contenido:
<HTML>
<APPLET CODE=HolaTal.class WIDTH=300 HEIGHT=100>
<PARAM NAME="Nombre" VALUE="Agustin">
</APPLET>
</HTML>
Por supuesto, que puedes sustituir mi nombre por el tuyo. Este cambio no afectará al código Java, no será necesario recompilarlo para que te salude a ti el applet.
Los parámetros no se limitan a uno solo. Se puede pasar al applet cualquier número de parámetros y siempre hay que indicar un nombre y un valor para cada uno de ellos.
El método getParameter() es fácil de entender. El único argumento que necesita es el nombre del parámetro cuyo valor queremos recuperar. Todos los parámetros se pasan como Strings, en caso de necesitar pasarle al applet un valor entero, se ha de pasar como String, recuperarlo como tal y luego convertirlo al tipo que deseemos. Tanto el argumento de NAME como el de VALUE deben ir colocados entre dobles comillas (") ya que son String.
El hecho de que las marcas <APPLET> y <PARAM> sean ignoradas por los navegadores que no entienden Java, es inteligentemente aprovechado a la hora de definir un contenido alternativo a ser mostrado en este último caso. Así la etiqueta es doble:
<APPLET atributos>
parámetros
contenido alternativo
</APPLET>
Nuestro fichero para mostrar el applet de ejemplo lo modificaremos para que pueda ser visualizado en cualquier navegador y en unos casos presente la información alternativa y en otros, ejcute nuestro applet:
<HTML>
<APPLET CODE=HolaTal.class WIDTH=300 HEIGHT=100>
<PARAM NAME="Nombre" VALUE="Agustin">
No verás lo bueno hasta que consigas un navegador
<I>Java Compatible</I>
</APPLET>
</HTML>
Ya de forma un poco más avanzada vamos a ver como también se pueden pasar varios parámetros en la llamada utilizando separadores, o lo que es lo mismo, separando mediante delimitadores los parámetros, es decir, tokenizando la cadena que contiene el valor del parámetro, por ejemplo:
<PARAM NAME=Nombre VALUE="Agustin|Antonio">
En este caso el separador es la barra vertical "|", que delimita los dos tokens, pero también podemos redefinirlo y utilizar cualquier otro símbolo como separador:
<PARAM NAME=Separador VALUE="#">
<PARAM NAME=Nombre VALUE="Agustin#Antonio">
Si ahora intentamos cambiar de color de fondo en que aparecen los textos en el applet, utilizando el mismo método, podríamos tener:
<PARAM NAME=Nombre VALUE="Agustin|Antonio">
<PARAM NAME=Color VALUE="green|red">
Es más, podríamos hacer que parpadeasen los mensajes en diferentes colores, cambiando el color de fondo y el del texto:
<PARAM NAME=Nombre1 VALUE="Agustin|green|yellow">
<PARAM NAME=Nombre2 VALUE="Antonio|red|white">
Para recoger los parámetros pasados en este último caso, bastaría con hacer un pequeño bucle de lectura de los parámetros que deseamos:
for( int i=1; ; i++ )
p = getParameter( "Nombre"+i );
if( p == null )
break;
. . .
}
incluso podríamos utilizar un fichero para pasar parámetros al applet. La llamada sería del mismo tipo:
<PARAM NAME=Fichero VALUE="FicheroDatos">
y el FicheroDatos debería tener un contenido, en este caso, que sería el siguiente:
Agustin
fondoColor=green
textoColor=yellow
fuente=Courier
fuenteTam=14
Antonio
fondoColor=red
textocolor=white
E incluso ese FicheroDatos, podríamos hacer que se encontrase en cualquier URL, de forma que utilizando el método getContent() podríamos recuperar el contenido del fichero que contiene los parámetros de funcionamiento del applet:
String getContent( String url ) {
URL url = new URL( null,url );
return( (String).url.getContent() );
}
Para recuperar los parámetros que están incluidos en la cadena que contiene el valor podemos utilizar dos métodos:
StringTokenizer( string,delimitadores )
treamTokenizer( streamentrada )
Así en la cadena Agustin|Antonio
si utilizamos el método:
StringTokenizer( cadena,"|" );
obtenemos el token Agustin, el delimitador "|" y el token Antonio. El código del método sería el que se muestra a continuación:
// Capturamos el parámetro
p = getParameter( "p" );
// Creamos el objeto StringTokenizer
st = new StringTokenizer( p,"|" );
// Creamos el almacenamiento
cads = new String[ st.countTokens() ];
// Separamos los tokens de la cadena del parámetro
for( i=0; i < cads.length; i++ )
cadenas[i] = st.nextToken();
En el caso de que utilicemos un fichero como verdadera entrada de parámetros al applet y el fichero se encuentre en una dirección URL, utilizamos el método StreamTokenizer() para obtener los tokens que contiene ese fichero:
// Creamos el objeto URL para acceder a él
url = new URL( "http://www.prueba.es/Fichero" );
// Creamos el canal de entrada
ce = url.openStream();
// Creamos el objeto StreamTokenizer
st = new StreamTokenizer( ce );
// Capturamos los tokens
st.nextToken();
Una de las cosas que se achacan a Java es la rapidez. El factor principal en la percepción que tiene el usuario de la velocidad y valor de los applets es el tiempo que tardan en cargarse todas las clases que componen el applet. Algunas veces tenemos que estar esperando más de un minuto para ver una triste animación, ni siquiera buena. Y, desafortunadamente, esta percepción de utilidad negativa puede recaer también sobre applets que realmente sí son útiles.
Para entender el porqué de la necesidad de un nuevo método de carga para acelerarla, necesitamos comprender porqué el método actual es lento. Normalmente un applet se compone de varias clases, es decir, varios ficheros .class. Por cada uno de estos ficheros .class, el cargador de clases debe abrir una conexión individual entre el navegador y el servidor donde reside el applet. Así, si un applet se compone de 20 ficheros .class, el navegador necesitará abrir 20 sockets para transmitir cada uno de los ficheros. La sobrecarga que representa cada una de estas conexiones es relativamente significante. Por ejemplo, cada conexión necesita un número de paquetes adicionales que incrementan el tráfico en la Red.
Me imagino que ya el lector habrá pensado la solución al problema: poner todos los ficheros en uno solo, con lo cual solamente sería necesaria una conexión para descargar todo el código del applet. Bien pensado. Esto es lo mismo que han pensado los dos grandes competidores en el terreno de los navegadores, Netscape y Microsoft.
Desafortunadamente, las soluciones que han implementado ambas compañías no son directamente compatibles. Microsoft, en su afán de marcar diferencia, crea su propio formato de ficheros CAB. La solución de Netscape es utilizar el archiconocido formato ZIP. Por suerte, nosotros podemos escribir nuestro código HTML de forma que maneje ambos formatos, en caso necesario. Esto es así porque podemos especificar cada uno de estos formatos de ficheros especiales en extensiones separadas de la marca <APPLET>.
No vamos a contar la creación de ficheros CAB; quien esté interesado puede consultar la documentación de Java que proporciona Microsoft con su SDK para Java, que es bastante exhaustiva al respecto. Una vez que disponemos de este fichero, podemos añadir un parámetro CABBASE a la marca <APPLET>:
<APPLET NAME="Hola" CODE="HolaMundo" WIDTH=50 HEIGHT=50 >
<PARAM NAME=CODEBASE VALUE="http://www.ejemplo.es/classes">
<PARAM NAME=CABBASE VALUE="hola.cab">
</APPLET>
El VALUE del parámetro CABBASE es el nombre del fichero CAB que contiene los ficheros .class que componen el conjunto de applet.
Crear un archivo ZIP para utilizarlo con Netscape es muy fácil. Se deben agrupar todos los ficheros .class necesarios en un solo fichero .zip. Lo único a tener en cuenta es que solamente hay que almacenar los ficheros .class en el archivo; es decir, no hay que comprimir.
Si se está utilizando pkzip, se haría:
Pkzip -e0 archivo.zip listaFicherosClass
El parámetro de la línea de comandos es el número cero, no la "O" mayúscula.
Para utilizar un fichero .zip hay que indicarlo en la marca ARCHIVE de la sección <APPLET>:
<APPLET NAME="Hola" CODE="HolaMundo" WIDTH=50 HEIGHT=50
CODEBASE VALUE="http://www.ejemplo.es/classes"
ARCHIVE="hola.zip">
</APPLET>
Pero hay más. Podemos crear ambos tipos de ficheros y hacer que tanto los usuarios de Netscape Navigator como los de Microsoft Internet Explorer puedan realizar descargas rápidas del código del applet. No hay que tener en cuenta los usuarios de otros navegadores, o de versiones antiguas de estos dos navegadores, porque ellos todavía podrán seguir cargando los ficheros a través del método lento habitual. Para compatibilizarlo todo, ponemos las piezas anteriores juntas:
<APPLET NAME="Hola" CODE="HolaMundo" WIDTH=50 HEIGHT=50
CODEBASE VALUE="http://www.ejemplo.es/classes"
ARCHIVE="hola.zip">
<PARAM NAME=CABBASE VALUE="hola.cab">
<PARAM NAME=CODEBASE VALUE="http://www.ejemplo.es/classes">
<PARAM NAME=CABBASE VALUE="hola.cab">
</APPLET>
Ahora que se puede hacer esto con ficheros .cab y .zip, JavaSoft ha definido un nuevo formato de ficheros, que incorporará en del JDK 1.1, para incluir juntos todos los ficheros de imágenes, sonido y class. JavaSoft llama a esto formato JAR (Java Archive). La marca <APPLET> de HTML se modificará para manejar este nuevo formato JAR a través del parámetro ARCHIVES. Y dejamos al lector el trabajo de poner los tres formatos juntos bajo el mismo paraguas de la marca <APPLET>.