• No results found

El API Servlet tiene un método getParameter en la clase HttpServletRequest que devuelve el valor GET o POST para el nombre suministrado.

La petición HTTP GET maneja parejas de nombre/valor como parte de la URL. El método getParameter analiza la URL pasada, recupera las parejas

name=value determinadas por el caracter (&), y devuelve el valor.

La petición HTTP POST lle el nombre de las parejas nombre/valor desde el stream de entrada desde el cliente. El método getParameter analiza en el stream de entrada las parejas de nombre/valor.

El método getParameter funciona vien para servlet sencillos, pero si necesitamos recuperar los parámetros POST en el orden enque fueron situados en la página wev o manejar posts multi-parte, podemos escribir nuestro propio para analizar el stram de entrada.

El siguiente ejemplo devuelve los parámetros POST en el orden en que fueron recibidos desde la página Web. Normalmento, los parámetros son almacenados en un Hashtable que no mantiene el orden de secuencia de los elementos

almacenados. El ejemplo mantiene una referencia a cada pareja nombre/valoren un vector que puede ser ser analizado para devolver valores en el orden en que fueron recibidos por el servidor.

package auction; import java.io.*; import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class PostServlet extends HttpServlet { private Vector paramOrder;

private Hashtable parameters;

public void init(ServletConfig config) throws ServletException {

super.init(config); }

public void service(HttpServletRequest request, HttpServletResponse response)

throws IOException {

response.setContentType("text/html"); PrintWriter out = response.getWriter(); if(request.getMethod().equals("POST") && request.getContentType().equals( "application/x-www-form-urlencoded")) { parameters=parsePostData( request.getContentLength(), request.getInputStream()); } for(int i=0;i<paramOrder.size();i++) { String name=(String)paramOrder.elementAt(i);

String value=getParameter(( String)paramOrder.elementAt(i)); out.println("name="+name+" value="+value); } out.println("</body></html>"); out.close(); }

private Hashtable parsePostData(int length, ServletInputStream instream) {

String valArray[] = null; int inputLen, offset;

byte[] postedBytes = null; boolean dataRemaining=true; String postedBody;

Hashtable ht = new Hashtable(); paramOrder= new Vector(10);

StringBuffer sb = new StringBuffer(); if (length <=0) {

return null; }

postedBytes = new byte[length]; try {

offset = 0;

while(dataRemaining) {

inputLen = instream.read (postedBytes, offset,

length - offset); if (inputLen <= 0) {

throw new IOException ("read error"); } offset += inputLen; if((length-offset) ==0) { dataRemaining=false; } } } catch (IOException e) { System.out.println("Exception ="+e); return null; }

postedBody = new String (postedBytes); StringTokenizer st =

String key=null; String val=null;

while (st.hasMoreTokens()) {

String pair = (String)st.nextToken(); int pos = pair.indexOf('=');

if (pos == -1) {

throw new IllegalArgumentException(); } try { key = java.net.URLDecoder.decode( pair.substring(0, pos)); val = java.net.URLDecoder.decode( pair.substring(pos+1, pair.length())); } catch (Exception e) {

throw new IllegalArgumentException(); }

if (ht.containsKey(key)) {

String oldVals[] = (String []) ht.get(key); valArray = new String[oldVals.length + 1]; for (int i = 0; i < oldVals.length; i++) { valArray[i] = oldVals[i];

}

valArray[oldVals.length] = val; } else {

valArray = new String[1]; valArray[0] = val; } ht.put(key, valArray); paramOrder.addElement(key); } return ht; }

public String getParameter(String name) {

String vals[] = (String []) parameters.get(name); if (vals == null) {

return null; }

String vallist = vals[0];

for (int i = 1; i < vals.length; i++) { vallist = vallist + "," + vals[i]; }

} }

Para saber si una petición es POST o GET, llamados al método getMethod de la clase HttpServletRequest. Para determinar el formato de los datos que están siendo posteados, llamamos al método getContentType de la clase

HttpServletRequest. Para sencillas páginas HTML, el tipo devuelto por está

llamada será application/x-www-form-urlencoded.

Si necesitamos crear un post con más de una parte como el creado por el siguiente formulario HTML, el servler necesitará ller el stream de entrada desde el post para alcanzar las secciones individuales. Cada sección se dstingue por un límite definido en la cabecera post.

<FORM ACTION="/PostMultiServlet"

METHOD="POST" ENCTYPE="multipart/form-data"> <INPUT TYPE="TEXT" NAME="desc" value="">

<INPUT TYPE="FILE" NAME="filecontents" value=""> <INPUT TYPE="SUBMIT" VALUE="Submit" NAME="Submit"> </FORM>

El siguiente ejemplo extrae una descripción y un fichero desde los navegadores del cliente. Lee el stream de entrada buscando una línea que corresponda con un

string de límite, lee el contenido de la línea y lueo lee los datos asociados con esa parte. El fichero suvido se muestra simplemente, pero también puede ser escrito en disco: package auction; import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*;

public class PostMultiServlet extends HttpServlet { public void init(ServletConfig config)

throws ServletException { super.init(config);

}

public void service(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException { response.setContentType("text/html");

if (request.getMethod().equals("POST") && request.getContentType().startsWith( "multipart/form-data")) {

int index = request.getContentType().indexOf( "boundary=");

if (index < 0) {

System.out.println("can't find boundary type"); return; } String boundary = request.getContentType().substring( index+9); ServletInputStream instream = request.getInputStream(); byte[] tmpbuffer = new byte[8192];

int length=0;

String inputLine=null; boolean moreData=true;

//Skip until form data is reached length = instream.readLine( tmpbuffer, 0,

tmpbuffer.length);

inputLine = new String (tmpbuffer, 0, 0, length); while(inputLine.indexOf(boundary) >0 && moreData) { length = instream.readLine( tmpbuffer, 0, tmpbuffer.length);

inputLine = new String (tmpbuffer, 0, 0, length); if(inputLine !=null) System.out.println("input="+inputLine); if(length<0) { moreData=false; } } if(moreData) { length = instream.readLine(

tmpbuffer, 0,

tmpbuffer.length);

inputLine = new String (tmpbuffer, 0, 0, length); if(inputLine.indexOf("desc") >=0) { length = instream.readLine( tmpbuffer, 0, tmpbuffer.length);

inputLine = new String (tmpbuffer, 0, 0, length);

length = instream.readLine( tmpbuffer,

0,

tmpbuffer.length);

inputLine = new String (tmpbuffer, 0, 0, length); System.out.println("desc="+inputLine); } } while(inputLine.indexOf(boundary) >0 && moreData) { length = instream.readLine( tmpbuffer, 0, tmpbuffer.length);

inputLine = new String (tmpbuffer, 0, 0, length); } if(moreData) { length = instream.readLine( tmpbuffer, 0, tmpbuffer.length);

inputLine = new String (tmpbuffer, 0, 0, length); if(inputLine.indexOf("filename") >=0) { int startindex=inputLine.indexOf( "filename"); System.out.println("file name="+ inputLine.substring( startindex+10,

inputLine.indexOf("\"", startindex+10))); length = instream.readLine( tmpbuffer, 0, tmpbuffer.length);

inputLine = new String (tmpbuffer, 0, 0, length);

} }

byte fileBytes[]=new byte[50000]; int offset=0; if (moreData) { while(inputLine.indexOf(boundary) >0 && moreData) { length = instream.readLine( tmpbuffer, 0, tmpbuffer.length);

inputLine = new String (tmpbuffer, 0, 0, length); if(length>0 && ( inputLine.indexOf(boundary) <0)) { System.arraycopy( tmpbuffer, 0, fileBytes, offset, length); offset+=length; } else { moreData=false; } } }

// trim last two newline/return characters // before using data

for(int i=0;i<offset-2;i++) { System.out.print((char)fileBytes[i]); } } out.println("</body></html>"); out.close(); } }

Threads

Un servlet debe ser capaz de manejar múltipels peticiones concurrentes. Cualquier número de usuarios puede en un momento dado invocar al servlet, y mientras que el método init ejecuta siempre un único trehad, el método service es multi-thread para manejar múltiples peticiones.

Esto significa que cualquier campo estático o público accedido por el método

service deberían estár restringidos a accesos de un thread. el ejemplo de abajo

usa la palabra clave synchronized para restringir el acceso a un contador para que sólo pueda ser actualizado por un thread a la vez:

int counter

Boolean lock = new Boolean(true); synchronized(lock){

counter++; }

HTTPS

Muchos servidores, navegadores, y el java Plug-In tiene la posibilidad de soportar el protocolo HTTP seguro llamado HTTPS. Este similar al HTTP excepto en que los datos on tramitidos a través de una capa de socket seguro (SSL) en lugar de una conexión de socket normal. Los navegadores web escuchan peticiones HTTP en un puerto mientras escuchan las peticiones HTTPS en otro puerto.

Los datos encriptados que son enviados a través de la red incluyen chequeos para verificar si los dato se han modificado en el tránsito. SSL también autentifica el servidor web a sus clientes proporcionando un certificado de clave pública. en el SSL 3.0 el cliente también puede autentificarse a sí mismo con el servidor,

usxando de nuevo un certificado de clave pública.

La clave pública criptográfica (también llamada clave de encriptación asimétrerica) usa una pareja de claves pública y privada. Cualquier mensaje encriptado (hecho ininteligible) con la clave privada de la pareja sólo puede ser desencriptado con la correspondiente clave pública. Los certificados son sentencias firmadas

digitalmente generadas por un tercera parte conocidad como "Autoridad de Certificación" Certificate Authority. Esta Autorizar necesita asegurarse de que

nosotros somos quien decimos ser porque los clientes se creeran el certificado que reciban. Si es así, este certificado puede contener la clave pública de la pareja de clave pública/privada. El certificado está firmado por la clave privada de la

Autoridad de Certificación, y muchos navegadores conocen las claves públicas la mayoría de las Autoridades de Certificación.

Mientras que la encriptaciónde clavepública es buena para propósitos de autentificación, no es tan rápida como la encriptación asimétrica y por eso el

protocolo SSL usa ambos tipos de claves en el ciclo de vida de una conexión SSL. El cliente y el servidor empiezan una transación HTTPS con una inicialización de conexión o fase de estrechamiento de manos.

Es en ese momento en el que el servidor es autentificado usando el certificado que el cliente ha recibido. El cliente usa la clave pública del servidor para encriptar los mensajes enviados al servidor. Después de que el cliente haya sido autentificado y el algoritmo de encriptación se ha puesto de acuerdo entre las dos partes, se usan unas nuevas claves de sesión simétrica para encriptar y desencriptar las

comunicaciones posteriores.

El algoritmo de encriptación puede ser uno de los más populares algoritmos como "Rivest Shamir and Adleman" (RSA) o "Data Encryption Standard" (DES). Cuando mayor sea el número de bits usados para crear la clave, mayores dificultades para poder romper las claves mediante la fuerza bruta.

HTTPS usando criptografía de clave pública y certificados nos permite proporcionar una gran privacidad a las aplicacioens que necesitan transaciones seguras. Los servidores, navegadores y Java Plug-In tienen sus propias configuraciones para permitir usar Comunicaciones SSL. En general, estos pasos requieren:

Obtener una clave privada y un certificado firmado digitalmente con la clave pública correspondente.

Instalar el certificado en una localización especificada por el software que estamos usando (servidor, navegador o Java Plug-In).

Activar las características SSL y especificar nuestros ficheros de certificado y de clave privada como se explica en nuestra documentación.

Siempre que activemos las características SSL de acuerdo con los requerimientos de la aplicación dependiendo del nivel de seguridad de necesitemos. Por ejemplo no necesitamos verificar la autenticidad de los clientes para navegar por los ítems de la subasta, pero sí querremos ecriptar la información de la tarjeta de crédido y otras informaciones suministradas cuando los compradores y vendedores se

registran para participar.

HTTPS puede ser usado para cualquier dato, no sólo ara páginas web HTTP. Los programas escritos en lenguaje Java pueden ser descaradoa a trravés de

conexiones HTTPS, y podemos abrir una conexión con un servidor HTTPS en el Java Plug-In. Para escribir un programa en Java que use SSL, este necesita una librería SSL y un conecimiento detallado del proceso de negociación HTTPS.

Nuestra librería SSL podría cubir los pasos necesarios ya que está información es restringida por el control de exportación de seguridad.

Tecnología JNI

La plataforma Java es relativamente nueva, lo que significa qie algunas veces podríamos necesitar integrar programas escritos en Java con servicios, programas o APIs existentes escritos en lenguajes distintos en Java. La plataforma Java

proporciona el Interfa Nativo Java (JNI) para ayudarnos con este tipo de integración.

El JNI define una convención de nombres y llamadas para que la Máquina Virtual Java1 pueda localizar e invocar a los métodos nativos. De hecho, JNI está

construido dentro de la máquina virtual Java, por lo que ésta puede llamar a sistemas locales para realizar entrada/salida, g´raficos, trabajos de red y operaciones de threads sobre el host del sistema operativo.

Este capítulo explica como usar JNI en programas escritos en Java para llamar a cualquier librería de la máquina local, llamar a métodos del lenguaje Java desde dentro del código nativo, y cómo crear y ejecutar un ejemplar de la JVM. Para mostrar cómo podemos hacer funcionar el JNI, los ejemplos de este capítulo incluyen integración de JNI con el API de bases de datos Xbase de C++. y cómo podemos llamar a una función matemática. Xbase tiene fuentes que podemos descargar.

Ejemplo JNI ●

Strings y Arrays ●

Otros Problemas de Programación ●

¿Tienes Prisa?

Esta tabla cotiene enlaces a los tópicos específicos.

Tópico Sección

Ejemplo JNI ● Sobre el Ejemplo

Generar el Fichero de Cabecera ●

Firma del Método ●

Implementar el Método Nativo ●

Compilar las Librerías Dinámicas o de Objetos Compartidos

Ejecutar el Ejemplo ●

Strings, Arrays, y Fields ● Pasar Strings Pasar Arrays ● Pinning Array ● Arrays de Objetos ● Arrays Multi-Dimensionales ● Acceder a Campos ● Otros Problemas de

Programación Problemas de Lenguaje

● Métodos Llamantes ● Acceder a Campos ● Threads y Sincronización ● Problemas de Memoria ● Invocación ● Adjuntar Threads ● _______

1 Cuando se usan en toda esta site, los términos, "Java virtual machine" o "JVM" significa una máquina virtual de la plataforma Java.

Ejemplos JNI

Esta sección presenta el programa de ejemplo ReadFile. Este ejemplo muestra cómo podemos usar JNI para invocar un método nativo que hace llamadas a funciones C para mapear en fichero en la memoria.