Esta edición se aplica a:
y a todos los releases y modificaciones posteriores hasta que se indique lo contrario en nuevas ediciones.
Realice el pedido de las publicaciones a través del representante de IBM o de la sucursal de IBM que presta servicio en su localidad.
En este apartado se describe la finalidad, la organización y los convenios de este documento, WebSphere Application Server Guía de programación de Edge Components.
Este manual describe las interfaces de programación de aplicaciones (API) que están disponibles para personalizar la familia Edge Components de WebSphere Application Server, Versión 6.1. Esta información está pensada para programadores que escriben aplicaciones de plug-ins y realizan otras personalizaciones. Puede que diseñadores de redes y administradores de sistemas también estén interesados en esta información como indicación de los tipos de personalización que son posibles.
La utilización de la información de este manual exige la comprensión de los procedimientos de programación con los lenguajes de programación Java o C, en función de la API que prevea utilizar. Los métodos y estructuras disponibles en cada interfaz expuesta se documentan, pero debe saber cómo construir una aplicación propia, compilarla para el sistema y probarla. Se proporciona código de ejemplo para algunas interfaces, pero sólo se proporcionan ejemplos para construir una aplicación propia.
Esta documentación utiliza los siguientes convenios tipográficos y de teclas.
Convenio | Significado |
---|---|
Negrita | Cuando se hace referencia a interfaces gráficas de usuario (las GUI), se indican en negrita menús, elementos de los menús, etiquetas, botones, iconos y carpetas. También puede utilizarse para enfatizar nombres de mandatos que, de lo contrario, podrían confundirse con el texto de alrededor. |
Monoespaciado | Indica texto que es necesario entrar en un indicador de mandatos. Además, el monoespaciado indica texto que aparece en la pantalla, ejemplos de código y extractos de archivos. |
Cursiva | Indica valores de variable que debe proporcionar el usuario (por ejemplo, el usuario facilitará el nombre de un archivo para NombreArchivo). La cursiva también indica énfasis y los títulos de manuales. |
Control-x | Donde x es el nombre de una tecla, indica una secuencia de Control-carácter. Por ejemplo, Control-c significa pulsar y mantener pulsada la tecla Control mientras se pulsa la tecla c. |
Intro | Se refiere a la tecla etiquetada con la palabra Intro o con la flecha hacia la izquierda. |
% | Representa el indicador de shell de mandatos de Linux y UNIX para un mandato que no requiere privilegios de root. |
# | Representa el indicador de shell de mandatos de Linux y UNIX de un mandato que requiere privilegios de root. |
C:\ | Representa el indicador de mandatos de Windows. |
Entrada de mandatos | Cuando se le indique que "entre" o "emita" un mandato, escriba el mandato y luego pulse Intro. Por ejemplo, la instrucción "Entre el mandato ls" significa que debe escribir ls en un indicador de mandatos y, después, pulsar Intro. |
[ ] | Encierran elementos opcionales en las descripciones de sintaxis. |
{ } | Encierran listas de las que debe elegirse un elemento en las descripciones de sintaxis. |
| | Separa elementos en una lista de opciones encerradas entre los signos { } (llaves) en las descripciones de sintaxis. |
... | Los puntos suspensivos que aparecen en las descripciones de sintaxis indican que es posible repetir el elemento anterior una o más veces. Los puntos suspensivos que aparecen en los ejemplos indican que se ha omitido información en el ejemplo para una mayor brevedad. |
Las características de accesibilidad ayudan al usuario que tiene discapacidades físicas, como por ejemplo una movilidad restringida o una visión limitada, a utilizar satisfactoriamente los productos de software. Éstas son las principales características de accesibilidad en WebSphere Application Server, Versión 6.1:
Sus comentarios son importantes para ayudarnos a proporcionar información de la más alta precisión y calidad. Si tiene algún comentario sobre este manual u otra documentación de la familia Edge Components de WebSphere Application Server,
Este manual trata las interfaces de programación de aplicaciones (API) que se proporcionan para la familia Edge Components de WebSphere Application Server. La familia Edge Components de WebSphere Application Server incluye Caching Proxy y Load Balancer. Se proporcionan varias interfaces que permiten a los administradores personalizar sus instalaciones, cambiar el modo en que Edge Components interactúan entre sí o habilitar la interacción con otros sistemas de software.
IMPORTANTE: Caching Proxy está disponible en todas las instalaciones de Edge Components, con las excepciones siguientes:
Las API de este documento abarcan varias categorías.
Caching Proxy tiene varias interfaces grabadas en su secuencia de proceso donde se pueden añadir o sustituir procesos personalizados para procesos estándar. Las personalizaciones que se pueden ejecutar son la modificación o el aumento de tareas como las siguientes:
Se llama a los programas de aplicación personalizados, que también se denominan plug-ins de Caching Proxy, en momentos predeterminados de la secuencia de proceso del servidor proxy.
La API de Caching Proxy se ha utilizado para implementar ciertas funciones del sistema. Por ejemplo el soporte de LDAP del servidor proxy se implementa como plug-in.
En el API de Caching Proxy se describe la interfaz detalladamente y se detallan los pasos para configurar el servidor proxy para utilizar programas de plug-ins.
Load Balancer se puede personalizar escribiendo sus propios asesores. Los asesores realizan la medición de carga real en los servidores. Con un asesor personalizado, puede utilizar un método propio y que sea relevante para el sistema a fin de medir la carga. Esto es especialmente importante si dispone de sistemas de servidor Web personalizados o de propiedad.
En el Asesores personalizados se proporciona información detallada sobre cómo escribir y utilizar asesores personalizados. Incluye código de asesores de ejemplo.
El código de ejemplo de estas API se incluye en el CD-ROM de Edge Components en el directorio samples. Hay disponibles ejemplos de código adicionales en el sitio Web de WebSphere Application Server, www.ibm.com/software/webservers/appserv/.
En este apartado se describe la interfaz de programación de aplicaciones (API) de Caching Proxy: qué es, por qué es útil y cómo funciona.
IMPORTANTE: Caching Proxy está disponible en todas las instalaciones de Edge Components, con las excepciones siguientes:
La API es una interfaz con Caching Proxy que permite ampliar las funciones básicas del servidor proxy. Puede escribir extensiones, o plug-ins, para realizar procesos personalizados, incluidos los ejemplos siguientes:
La API de Caching Proxy ofrece las ventajas siguientes:
Antes de escribir sus programas de plug-ins de Caching Proxy, tiene que comprender cómo funciona el servidor proxy. El comportamiento del servidor proxy se puede dividir en varios pasos de proceso distintos. Para cada uno de estos pasos, puede proporcionar funciones personalizadas propias mediante la API. Por ejemplo, si desea realizar alguna acción después de que se lea una petición de cliente, pero antes de llevar a cabo otro proceso. O quizá desea llevar a cabo rutinas especiales durante la autenticación y de nuevo después de que se envíe el archivo solicitado.
Con la API se proporciona una biblioteca de funciones predefinidas. Los programas de plug-ins pueden llamar a funciones predefinidas de la API para que interactúen con el proceso del servidor proxy (por ejemplo, para manipular peticiones, leer o grabar cabeceras de peticiones o grabar en las anotaciones cronológicas del servidor proxy). Estas funciones no deben confundirse con las funciones de plug-in que escriba, a las que llama el servidor proxy. Las funciones predefinidas se describen en el apartado Funciones y macros predefinidas.
Dará instrucciones al servidor proxy para que llame a las funciones de plug-in en los pasos adecuados mediante las directivas de la API de Caching Proxy correspondientes en el archivo de configuración del servidor. Estas directivas se describen en el apartado Directivas de configuración de Caching Proxy para pasos de la API.
Este documento incluye lo siguiente:
Puede utilizar estos componentes y procedimientos para escribir sus propios programas de plug-ins de Caching Proxy.
El funcionamiento básico del servidor proxy se puede dividir en pasos según el tipo de proceso que el servidor lleva a cabo durante cada fase. Cada paso incluye una coyuntura en la que una parte específica del programa se puede ejecutar. Al añadir directivas de la API al archivo de configuración de Caching Proxy (ibmproxy.conf), se indican las funciones de plug-in a las que se desea llamar durante un paso concreto. Puede llamar a varias funciones de plug-in durante un paso de proceso concreto si incluye más de una directiva para ese paso.
Algunos pasos forman parte del proceso de peticiones del servidor. En otras palabras, el servidor proxy ejecuta estos pasos cada vez que procesa una petición. Otros pasos se realizan de forma independiente del proceso de peticiones, es decir, el servidor ejecuta estos pasos independientemente de si se ha procesado o no una petición.
El programa compilado reside en un objeto compartido, por ejemplo un archivo DLL o .so, en función del sistema operativo. A medida que el servidor avanza por los pasos de proceso de peticiones, llama a las funciones de plug-in asociadas con cada paso hasta que una de las funciones indica que ha gestionado la petición. Si especifica más de una función de plug-in para un paso concreto, las funciones se llaman en el orden en el que aparecen sus directivas en el archivo de configuración.
Si una función de plug-in no gestiona la petición (no ha incluido una directiva de la API de Caching Proxy para ese paso o la función de plug-in de ese paso ha devuelto HTTP_NOACTION), el servidor lleva a cabo la acción por omisión para ese paso.
Nota: Esto es así para todos los pasos excepto el paso Service; el paso Service no tiene una acción por omisión.
En la Figura 1 se detallan los pasos del proceso del servidor proxy y se define el orden de proceso de los pasos relacionados con el proceso de peticiones.
Cuatro de los pasos del diagrama se ejecutan independientemente del proceso de las peticiones del cliente. Estos pasos están relacionados con la ejecución y el mantenimiento del servidor proxy. Son los siguientes:
En la lista siguiente se explica la finalidad de cada uno de los pasos detallados en la Figura 1. Tenga en cuenta que no se garantiza que se llame a todos los pasos para una petición concreta.
Lleva a cabo un proceso después de leer una petición pero antes de realizar cualquier otra acción.
Si este paso devuelve una indicación de que la petición se ha procesado (HTTP_OK), el servidor omite el resto de pasos del proceso de peticiones y realiza sólo los pasos Transmogrifier, Log y PostExit.
Utiliza los símbolos de seguridad almacenados para comprobar la vía de acceso física para protecciones, ACL y otros controles de acceso y genera las cabeceras de autenticación WWW obligatorias para la autenticación básica. Si escribe una función de plug-in propia para sustituir este paso, debe generar estas cabeceras personalmente.
Consulte el apartado Autenticación y autorización para obtener más información.
Decodifica, verifica y almacena símbolos de seguridad.
Consulte el apartado Autenticación y autorización para obtener más información.
Lleva a cabo el proceso después de la autorización y la localización del objeto, pero antes de que se dé respuesta a la petición.
Si este paso devuelve una indicación de que la petición se ha procesado (HTTP_OK), el servidor omite el resto de pasos del proceso de peticiones y realiza sólo los pasos Transmogrifier, Log y PostExit.
En sistemas AIX, es necesario un archivo de exportación (por ejemplo, libmyapp.exp) que enumere las funciones de plug-in y debe establecer un enlace con el archivo de importación de la API de Caching Proxy, libhttpdapi.exp.
En sistemas Linux, HP-UX y Solaris, debe establecer un enlace con las bibliotecas libhttpdapi y libc.
En sistemas Windows, necesita un archivo de definición de módulo (.def) que enumere las funciones de plug-in y debe establecer un enlace con HTTPDAPI.LIB.
Asegúrese de incluir HTAPI.h y de utilizar la macro HTTPD_LINKAGE en las definiciones de funciones. Esta macro garantiza que todas las funciones utilicen los mismos convenios de llamada.
Utilice los mandatos de compilación y enlace como directriz.
cc_r -c -qdbxextra -qcpluscmt foo.c
cc_r -bM:SRE -bnoentry -o libfoo.so foo.o -bI:libhttpdapi.exp -bE:foo.exp
Este mandato se muestra en dos líneas para poderlo leer.
cc -Ae -c +Z +DAportable
aCC +Z -mt -c +DAportable
gcc -c foo.c
ld -G -Bsymbolic -o libfoo.so foo.o -lhttpdapi -lc
cc -mt -Bsymbolic -c foo.c
cc -mt -Bsymbolic -G -o libfoo.so foo.o -lhttpdapi -lc
cl /c /MD /DWIN32 foo.c
link httpdapi.lib foo.obj /def:foo.def /out:foo.dll /dll
Para especificar exportaciones, utilice uno de estos métodos:
Siga la sintaxis que se describe en el apartado Prototipos de función de plug-in para escribir sus propias funciones de programa para los pasos de proceso de peticiones definidos.
Cada una de las funciones debe rellenar el parámetro de código de retorno con un valor que indique la acción que se ha llevado a cabo:
Los prototipos de función de cada paso de Caching Proxy muestran el formato que se debe utilizar y explica el tipo de proceso que pueden realizar. Tenga en cuenta que los nombres de función no están predefinidos. Debe asignar a las funciones nombres exclusivos y puede elegir convenios de nombres propios. Para que la asociación resulte más fácil, en este documento se utilizan nombres relacionados con los pasos de proceso del servidor.
En cada una de estas funciones de plug-in, son válidas algunas funciones predefinidas de la API. Otras funciones predefinidas no son válidas para todos los pasos. Las siguientes funciones predefinidas de la API son válidas cuando se llaman desde todas estas funciones de plug-in:
En las descripciones de prototipos de función se indican las funciones válidas o no válidas adicionales de la API.
El valor del parámetro handle enviado a las funciones se puede pasar como primer argumento a las funciones predefinidas. Las funciones predefinidas de la API se describen en el apartado Funciones y macros predefinidas.
void HTTPD_LINKAGE ServerInitFunction ( unsigned char *handle, unsigned long *major_version, unsigned long *minor_version, long *return_code )
A function defined for this step is called once when your module is loaded during server initialization. It is your opportunity to perform initialization before any requests have been accepted.
Although all server initialization functions are called, a error return code from a function in this step causes the server to ignore all other functions configured in the same module as the function that returned the error code. (That is, any other functions contained in the same shared object as the function that returned the error are not called.)
The version parameters contain the servidor proxy's version number; these are supplied by the Caching Proxy.
void HTTPD_LINKAGE PreExitFunction ( unsigned char *handle, long *return_code )
A function defined for this step is called for each request after the request has been read but before any processing has occurred. A plug-in at this step can be used to access the client's request before it is processed by the Caching Proxy.
Valid return codes for the preExit function are the following:
Other return codes must not be used.
If this function returns HTTP_OK, the servidor proxy assumes that the request has been handled. All subsequent request processing steps are bypassed, and only the response steps (Transmogrifier, Log, and PostExit) are performed.
All predefined API functions are valid during this step.
void HTTPD_LINKAGE MidnightFunction ( unsigned char *handle, long *return_code )
A function defined for this step runs daily at midnight and contains no request context. For example, it can be used to invoke a child process to analyze logs. (Note that extensive processing during this step can interfere with logging.)
void HTTPD_LINKAGE AuthenticationFunction ( unsigned char *handle, long *return_code )
A function defined for this step is called for each request based on the request's authentication scheme. This function can be used to customize verification of the security tokens that are sent with a request.
void HTTPD_LINKAGE NameTransFunction ( unsigned char *handle, long *return_code )
La función definida para este paso se llama para cada petición. Se puede especificar una plantilla de URL en la directiva del archivo de configuración si desea que se llame a la función de plug-in sólo para las peticiones que coincidan con la plantilla. El paso de conversión de nombres tiene lugar antes de que se procese la petición y proporciona un mecanismo para correlacionar URL con objetos, como nombres de archivo.
void HTTPD_LINKAGE AuthorizationFunction ( unsigned char *handle, long *return_code )
La función definida para este paso se llama para cada petición. Se puede especificar una plantilla de URL en la directiva del archivo de configuración si desea que se llame a la función de plug-in sólo para las peticiones que coincidan con la plantilla. El paso de autorización tiene lugar antes de que se procese la petición y se puede utilizar para verificar que el objeto identificado se pueda devolver al cliente. Si va a realizar una autenticación básica, debe generar las cabeceras WWW-Authenticate obligatorias.
void HTTPD_LINKAGE ObjTypeFunction ( unsigned char *handle, long *return_code )
La función definida para este paso se llama para cada petición. Se puede especificar una plantilla de URL en la directiva del archivo de configuración si desea que se llame a la función de plug-in sólo para las peticiones que coincidan con la plantilla. El paso de tipo de objeto tiene lugar antes de que se procese la petición y se puede utilizar para comprobar si el objeto existe y para realizar una configuración de tipo de objeto.
void HTTPD_LINKAGE PostAuthFunction ( unsigned char *handle, long *return_code )
La función definida para este paso se llama después de que se haya autorizado la petición pero antes de que tenga lugar un proceso. Si esta función devuelve HTTP_OK, el servidor proxy presupone que la petición se ha gestionado. Los pasos posteriores de petición se pasan por alto y sólo se llevan a cabo los pasos de respuesta (Transmogrifier, Log y PostExit).
Todas las funciones predefinidas de servidor son válidas durante este paso.
void HTTPD_LINKAGE ServiceFunction ( unsigned char *handle, long *return_code )
La función definida para este paso se llama para cada petición. Se puede especificar una plantilla de URL en la directiva del archivo de configuración si desea que se llame a la función de plug-in sólo para las peticiones que coincidan con la plantilla. El paso Service da respuesta a la petición, si no se ha dado respuesta en los pasos PreExit o PostAuthorization.
Todas las funciones predefinidas de servidor son válidas durante este paso.
Consulte la directiva Enable en la publicación WebSphere Application Server Caching Proxy Administration Guide para obtener información sobre la configuración de la función Service que se debe ejecutar según el método HTTP y no según el URL.
Para este paso, debe implementar las cuatro funciones siguientes. Los nombres de función no tienen que coincidir con estos nombres.
void * HTTPD_LINKAGE openFunction ( unsigned char *handle, long *return_code )
La función open realiza cualquier inicialización (como una asignación de almacenamiento intermedio) obligatoria para procesar los datos de esta secuencia de datos. Cualquier código de retorno que no sea HTTP_OK hace que este filtro termine anormalmente (no se llama a las funciones write y close). La función puede devolver un puntero void para que pueda asignar espacio para una estructura y que se le devuelva el puntero en el parámetro correlator de las funciones posteriores.
void HTTPD_LINKAGE writeFunction ( unsigned char *handle, unsigned char *data, /* datos de respuesta enviados por el servidor de origen */ unsigned long *length, /* longitud de los datos de respuesta */ void *correlator, /* puntero devuelto por la función 'open' */ long *return_code )
La función write procesa los datos y puede llamar a la función HTTPD_write() predefinida del servidor con los datos nuevos o cambiados. El plug-in no debe intentar liberar el almacenamiento intermedio que se le ha pasado ni esperar que el servidor libere el almacenamiento intermedio que reciba.
Si decide no cambiar los datos en el ámbito de la función write, aún puede llamar a la función HTTPD_write() en el ámbito de la función open, write o close a fin de pasar los datos de la respuesta al cliente. El argumento correlator es el puntero que apunta al almacenamiento intermedio de datos que se ha devuelto en la rutina open.
void HTTPD_LINKAGE closeFunction ( unsigned char *handle, void *correlator, long *return_code )
La función close realiza las acciones de limpieza (como desechar y liberar el almacenamiento intermedio de correlator) obligatorias para realizar el proceso de los datos para esta secuencia. El argumento correlator es el puntero que apunta al almacenamiento intermedio de datos que se ha devuelto en la rutina open.
void HTTPD_LINKAGE errorFunction ( unsigned char *handle, void *correlator, long *return_code )
La función error habilita la realización de acciones de limpieza, como desechar o liberar los datos en almacenamiento intermedio (o ambas acciones) antes de que se envíe una página de error. En este punto, se llama a las funciones open, write y close para procesar la página de error. El argumento correlator es el puntero que apunta al almacenamiento intermedio de datos que se ha devuelto en la rutina open.
Notas:
void HTTPD_LINKAGE GCAdvisorFunction ( unsigned char *handle, long *return_code )
La función definida para este paso se llama para cada archivo de la antememoria durante la recogida de basura. Esta función permite asesorar sobre los archivos que se conservan y los que se descartan. Para obtener más información, consulte las variables GC_*.
void HTTPD_LINKAGE ProxyAdvisorFunction ( unsigned char *handle, long *return_code )
Se invoca una función definida durante el servicio de cada petición de proxy. Por ejemplo, se puede utilizar para establecer la variable USE_PROXY.
void HTTPD_LINKAGE LogFunction ( unsigned char *handle, long *return_code )
La función definida para este paso se llama para cada petición después de que se haya procesado la petición y se haya cerrado la comunicación con el cliente. Se puede especificar una plantilla de URL en la directiva del archivo de configuración si desea que se llame a la función de plug-in sólo para las peticiones que coincidan con la plantilla. Se llama a esta función independientemente de la ejecución satisfactoria o no del proceso de peticiones. Si no desea que el plug-in de anotaciones cronológicas altere temporalmente el mecanismo de anotaciones cronológicas por omisión, establezca el código de retorno en HTTP_NOACTION, en lugar de HTTP_OK.
void HTTPD_LINKAGE ErrorFunction ( unsigned char *handle, long *return_code )
La función definida para este paso se llama para cada petición que falla. Se puede especificar una plantilla de URL en la directiva del archivo de configuración si desea que se llame a la función de plug-in sólo para las peticiones que hayan fallado y que coincidan con la plantilla. El paso Error le ofrece la oportunidad de personalizar la respuesta al error.
void HTTPD_LINKAGE PostExitFunction ( unsigned char *handle, long *return_code )
La función definida para este paso se llama para cada petición, independientemente de la ejecución satisfactoria o no de la petición. Este paso permite realizar tareas de limpieza para los recursos asignados por el plug-in a fin de procesar la petición.
void HTTPD_LINKAGE ServerTermFunction ( unsigned char *handle, long *return_code )
La función definida para este paso se llama cuando tiene lugar una conclusión normal del servidor. Permite limpiar los recursos asignados durante el paso Server Initialization. No llame a funciones HTTP_* en este paso (los resultados son imprevisibles). Si tiene más de una directiva de la API de Caching Proxy en el archivo de configuración para Server Termination, se les realizará una llamada.
Estos códigos de retorno siguen la especificación HTTP 1.1, RFC 2616, publicada por World Wide Web Consortium (www.w3.org/pub/WWW/Protocols/). Las funciones de plug-in deben devolver uno de estos valores.
Valor | Código de retorno |
0 | HTTP_NOACTION |
100 | HTTP_CONTINUE |
101 | HTTP_SWITCHING_PROTOCOLS |
200 | HTTP_OK |
201 | HTTP_CREATED |
202 | HTTP_ACCEPTED |
203 | HTTP_NON_AUTHORITATIVE |
204 | HTTP_NO_CONTENT |
205 | HTTP_RESET_CONTENT |
206 | HTTP_PARTIAL_CONTENT |
300 | HTTP_MULTIPLE_CHOICES |
301 | HTTP_MOVED_PERMANENTLY |
302 | HTTP_MOVED_TEMPORARILY |
302 | HTTP_FOUND |
303 | HTTP_SEE_OTHER |
304 | HTTP_NOT_MODIFIED |
305 | HTTP_USE_PROXY |
307 | HTTP_TEMPORARY_REDIRECT |
400 | HTTP_BAD_REQUEST |
401 | HTTP_UNAUTHORIZED |
403 | HTTP_FORBIDDEN |
404 | HTTP_NOT_FOUND |
405 | HTTP_METHOD_NOT_ALLOWED |
406 | HTTP_NOT_ACCEPTABLE |
407 | HTTP_PROXY_UNAUTHORIZED |
408 | HTTP_REQUEST_TIMEOUT |
409 | HTTP_CONFLICT |
410 | HTTP_GONE |
411 | HTTP_LENGTH_REQUIRED |
412 | HTTP_PRECONDITION_FAILED |
413 | HTTP_ENTITY_TOO_LARGE |
414 | HTTP_URI_TOO_LONG |
415 | HTTP_BAD_MEDIA_TYPE |
416 | HTTP_BAD_RANGE |
417 | HTTP_EXPECTATION_FAILED |
500 | HTTP_SERVER_ERROR |
501 | HTTP_NOT_IMPLEMENTED |
502 | HTTP_BAD_GATEWAY |
503 | HTTP_SERVICE_UNAVAILABLE |
504 | HTTP_GATEWAY_TIMEOUT |
505 | HTTP_BAD_VERSION |
Puede llamar a las funciones y las macros predefinidas del servidor desde funciones de plug-in propias. Debe utilizar sus nombres predefinidos y respetar el formato que se describe a continuación. En las descripciones de parámetros, la letra e indica un parámetro de entrada, la letra s indica un parámetro de salida y e/s indica que se utiliza un parámetro tanto para la entrada como para la salida.
Cada una de estas funciones devuelve uno de los códigos de retorno HTTPD, en función de si la petición se ha llevado a cabo de forma satisfactoria. Estos códigos se describen en el apartado Códigos de retorno de funciones y macros predefinidas.
Utilice el descriptor de contexto que se proporciona para el plug-in como primer parámetro cuando llame a estas funciones. De lo contrario, la función devuelve un código de error HTTPD_PARAMETER_ERROR. NULL no se acepta como descriptor de contexto válido.
void HTTPD_LINKAGE HTTPD_authenticate ( unsigned char *handle, /* e; descriptor de contexto */ long *return_code /* s; código de retorno */ )
void HTTPD_LINKAGE HTTPD_cacheable_url ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *url, /* e; URL que se debe comprobar */ unsigned char *req_method, /* e; método de petición del URL */ long *retval /* s; código de retorno */ )
El valor de retorno HTTPD_SUCCESS indica que el contenido del URL se puede almacenar en antememoria; HTTPD_FAILURE indica que el contenido no se puede almacenar en antememoria. HTTPD_INTERNAL_ERROR también es un código de retorno posible para esta función.
void HTTPD_LINKAGE HTTPD_close ( unsigned char *handle, /* e; descriptor de contexto */ long *return_code /* s; código de retorno */ )
void HTTPD_LINKAGE HTTPD_exec ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *name, /* e; nombre del script que debe ejecutarse */ unsigned long *name_length, /* e; longitud del nombre */ long *return_code /* s; código de retorno */ )
void HTTPD_LINKAGE HTTPD_extract ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *name, /* e; nombre de la variable que debe extraerse */ unsigned long *name_length, /* e; longitud del nombre */ unsigned char *value, /* s; almacenamiento intermedio en el que se debe colocar el valor */ unsigned long *value_length, /* e/s; tamaño de almacenamiento intermedio */ long *return_code /* s; código de retorno */ )
Si esta función devuelve el código HTTPD_BUFFER_TOO_SMALL, el tamaño del almacenamiento intermedio que ha solicitado no era lo suficientemente grande para el valor extraído. En tal caso, la función no utiliza el almacenamiento intermedio, pero actualiza el parámetro value_length con el tamaño del almacenamiento intermedio que necesite a fin de extraer satisfactoriamente este valor. Vuelva a intentar la extracción con un almacenamiento intermedio que tenga, como mínimo, el mismo tamaño que el valor de longitud_valor devuelto.
void HTTPD_LINKAGE HTTPD_file ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *name, /* e; nombre del archivo que debe enviarse */ unsigned long *name_length, /* e; longitud del nombre */ long *return_code /* s; código de retorno */ )
const unsigned char * /* s; valor de la variable */ HTTPD_LINKAGE httpd_getvar( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *name, /* e; nombre de la variable */ unsigned long *n /* e; número de índice de la matriz que contiene la cabecera */ )
El índice de la matriz que contiene la cabecera empieza por 0. Para obtener el primer elemento de la matriz, utilice el valor 0 para n; para obtener el quinto elemento, utilice el valor 4 para n.
void HTTPD_LINKAGE HTTPD_log_access ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *value, /* e; datos que se deben grabar */ unsigned long *value_length, /* e; longitud de los datos */ long *return_code /* s; código de retorno */ )
Tenga en cuenta que los símbolos de escape no son obligatorios cuando se graba el símbolo de porcentaje (%) en las anotaciones cronológicas de acceso del servidor.
void HTTPD_LINKAGE HTTPD_log_error ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *value, /* e; datos que se deben grabar */ unsigned long *value_length, /* e; longitud de los datos */ long *return_code /* s; código de retorno */ )
Tenga en cuenta que los símbolos de escape no son obligatorios cuando se graba el símbolo de porcentaje (%) en las anotaciones cronológicas de errores del servidor.
void HTTPD_LINKAGE HTTPD_log_event ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *value, /* e; datos que se deben grabar */ unsigned long *value_length, /* e; longitud de los datos */ long *return_code /* s; código de retorno */ )
Tenga en cuenta que los símbolos de escape no son obligatorios cuando se graba el símbolo de porcentaje (%) en las anotaciones cronológicas de sucesos del servidor.
void HTTPD_LINKAGE HTTPD_log_trace ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *value, /* e; datos que se deben grabar */ unsigned long *value_length, /* e; longitud de los datos */ long *return_code /* s; código de retorno */ )
Tenga en cuenta que los símbolos de escape no son obligatorios cuando se graba el símbolo de porcentaje (%) en las anotaciones cronológicas de rastreo del servidor.
void HTTPD_LINKAGE HTTPD_open ( unsigned char *handle, /* e; descriptor de contexto */ long *return_code /* s; código de retorno */ )
void HTTPD_LINKAGE HTTPD_proxy ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *url_name, /* e; URL de la petición de proxy */ unsigned long *name_length, /* e; longitud del URL */ void *request_body, /* e; cuerpo de la petición */ unsigned long *body_length, /* e; longitud del cuerpo */ long *return_code /* s; código de retorno */ )
void HTTPD_LINKAGE HTTPD_read ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *value, /* e; almacenamiento intermedio para datos */ unsigned long *value_length, /* e/s; tamaño de almacenamiento intermedio (longitud de datos) */ long *return_code /* s; código de retorno */ )
void HTTPD_LINKAGE HTTPD_restart ( long *return_code /* s; código de retorno */ )
Tenga en cuenta que también puede crear variables con esta función. Las variables que cree están sujetas a los convenios de los prefijos HTTP_ y PROXY_, que se describen en el apartado Variables. Si crea una variable que empieza por HTTP_, se envía como cabecera en la respuesta al cliente, sin el prefijo HTTP_. Por ejemplo, para establecer una cabecera Location, utilice HTTPD_set() con el nombre de variable HTTP_LOCATION. Las variables creadas con un prefijo PROXY_ se envían como cabeceras en la petición al servidor de contenido. Las variables creadas con un prefijo CGI_ se pasan a los programas de CGI.
Esta función es válida en todos los pasos; no obstante, no todas las variables son válidas en todos los pasos.
void HTTPD_LINKAGE HTTPD_set ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *name, /* e; nombre de la variable que se debe establecer */ unsigned long *name_length, /* e; longitud del nombre */ unsigned char *value, /* e; almacenamiento intermedio con valor */ unsigned long *value_length, /* e; longitud del valor */ long *return_code /* s; código de retorno */ )
long /* s; código de retorno */ HTTPD_LINKAGE httpd_setvar ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *name, /* e; nombre de la variable */ unsigned char *value, /* e; nuevo valor */ unsigned long *addHdr /* e; añadir cabecera o sustituirla */ )
El parámetro addHdr tiene cuatro valores posibles:
Estos valores se definen en HTAPI.h.
void HTTPD_LINKAGE httpd_variant_insert ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *URI, /* e; URI de este objeto */ unsigned char *dimension, /* e; dimensión de variant */ unsigned char *variant, /* e; valor de variant */ unsigned char *filename, /* e; archivo que contiene el objeto */ long *return_code /* s; código de retorno */ )
Notas:
Mozilla 4.0 (compatible; BatBrowser 94.1.2; Bat OS)
void HTTPD_LINKAGE httpd_variant_lookup ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *URI, /* URI de este objeto */ unsigned char *dimension, /* e; dimensión de variant */ unsigned char *variant, /* e; valor de variant */ long *return_code); /* s; código de retorno */
Si no establece el tipo de contenido antes de llamar a esta función por primera vez, el servidor presupone que va a enviar una secuencia de datos de CGI.
void HTTPD_LINKAGE HTTPD_write ( unsigned char *handle, /* e; descriptor de contexto */ unsigned char *value, /* e; datos que se deben enviar */ unsigned char *value_length, /* e; longitud de los datos */ long *return_code); /* s; código de retorno */
El servidor establecerá el parámetro de código de retorno en uno de estos valores, en función de si la ejecución de la petición es satisfactoria:
Valor | Código de estado | Explicación |
---|---|---|
-1 | HTTPD_UNSUPPORTED | La función no recibe soporte. |
0 | HTTPD_SUCCESS | La función se ha realizado satisfactoriamente y los campos de salida son válidos. |
1 | HTTPD_FAILURE | La función ha fallado. |
2 | HTTPD_INTERNAL_ERROR | Se ha encontrado un error interno y el proceso de esta petición no puede continuar. |
3 | HTTPD_PARAMETER_ERROR | Se han pasado uno o más parámetros no válidos. |
4 | HTTPD_STATE_CHECK | La función no es válida en este paso de proceso. |
5 | HTTPD_READ_ONLY | Sólo lo devuelve HTTPD_set y httpd_setvar. La variable es de sólo lectura y no la puede establecer el plug-in. |
6 | HTTPD_BUFFER_TOO_SMALL | Sólo lo devuelve HTTPD_set, httpd_setvar y HTTPD_read. El almacenamiento intermedio era demasiado pequeño. |
7 | HTTPD_AUTHENTICATE_FAILED | Sólo lo devuelve HTTPD_authenticate. La autenticación ha fallado. Examine las variables HTTP_RESPONSE y HTTP_REASON para obtener más información. |
8 | HTTPD_EOF | Sólo lo devuelve HTTPD_read. Indica el final del cuerpo de la petición. |
9 | HTTPD_ABORT_REQUEST | La petición ha terminado anormalmente porque el cliente ha proporcionado un código de entidad que no coincidía con la condición especificada por la petición. |
10 | HTTPD_REQUEST_SERVICED | Lo devuelve HTTPD_proxy. La función a la que se ha llamado ha dado respuesta a esta petición. |
11 | HTTPD_RESPONSE_ALREADY_COMPLETED | La función ha fallado porque ya se ha dado respuesta a esa petición. |
12 | HTTPD_WRITE_ONLY | La variable es de sólo escritura y no la puede leer el plug-in. |
Cada paso de este proceso de petición dispone de una directiva de configuración que se utiliza para indicar las funciones de plug-in que desee llamar y ejecutar durante ese paso. Puede añadir estas directivas al archivo de configuración del servidor (ibmproxy.conf) editándolo y actualizándolo manualmente o utilizando el formulario de proceso de petición de API de los formularios de configuración y administración de Caching Proxy.
Esto significa que el servidor procesa las directivas Service, NameTrans, Exec, Fail, Map, Pass, Proxy, ProxyWAS y Redirect en su secuencia dentro del archivo de configuración. Cuando el servidor correlaciona de forma satisfactoria un URL con un archivo, no lee ni procesa ninguna de estas directivas. (La directiva Map es una excepción. Consulte la publicación WebSphere Application Server Caching Proxy Administration Guide para obtener información exhaustiva acerca de las reglas de correlación del servidor proxy).
Estas directivas de archivo de configuración deben aparecer en el archivo ibmproxy.conf en una línea, sin espacios que no sean los especificados explícitamente aquí. Aunque aparecen saltos de línea por cuestiones de legibilidad en algunos de los ejemplos de sintaxis, no debe haber espacios en esos puntos en la directiva real.
Las variables de estas directivas tienen los siguientes significados:
La directiva Service exige un asterisco (*) después del nombre de función si desea tener acceso a la información de vía de acceso.
Para obtener más información, incluida la sintaxis, para estas directivas, consulte la publicación WebSphere Application Server Caching Proxy Administration Guide.
La API de Caching Proxy es compatible con versiones anteriores de ICAPI y GWAPI, desde la versión 4.6.1.
Siga estas directrices para establecer puertos para aplicaciones CGI escritas en C a fin de utilizar la API de Caching Proxy:
Al escribir programas de la API, puede utilizar las variables de Caching Proxy que proporcionan información acerca del cliente remoto y el sistema servidor.
Notas:
ACCEPT_RANGES BYTES CLIENT_ADDR 9.67.84.3
Esta variable se puede utilizar en los pasos PostAuthorization, PostExit, ProxyAdvisor o Log.
http://www.anynet.com/~userk/main.htm
Mon, 01 Mar 2002 19:41:17 GMT
Mon, 01 Mar 1998 19:41:17 GMT
d:\wwwhome\foo
/wwwhome/foo
application/x-www-form-urlencoded
7034
NAME=Eugene+T%2E+Fox&ADDR=etfox%7Cibm.net&INTEREST=xyz
http://www.company.com/homepage
application/x-www-form-urlencoded
En primer lugar, revisemos brevemente la terminología:
En la Figura 3 se detalla el proceso de autenticación y autorización del servidor proxy.
Como se muestra en la Figura 3, el inicio del proceso de autorización es el primer paso del proceso de autorización y autenticación del servidor.
En Caching Proxy, la autenticación es parte del proceso de autorización; sólo tiene lugar cuando se exige una autorización.
El servidor proxy sigue estos pasos al procesar una petición que exige autorización.
Si el plug-in de Caching Proxy proporciona su propio proceso de autorización, altera temporalmente la autorización y la autenticación de servidor por omisión. Por lo tanto, si tiene directivas de autorización en el archivo de configuración, las funciones de plug-in asociadas con ellas deben gestionar también las autenticaciones necesarias. Se proporciona la función HTTPD_authenticate() predefinida para que la utilice.
Estos son los tres modos de proporcionar autenticación en los plug-ins de autorización:
Cuando se ejecuta el paso Authorization, realiza la función de plug-in de autorización, que, por su parte, llama a la función de plug-in de autenticación.
Cuando se ejecuta el paso Authorization, lleva a cabo la función de plug-in de autorización, que, por su parte, llama a la autenticación de servidor por omisión.
Cuando se ejecuta el paso Authorization, realiza la función de plug-in de autorización y las autenticaciones que incluya.
Si el plug-in de Caching Proxy no proporciona un proceso de autorización propia, aún puede proporcionar una autenticación personalizada utilizando el método siguiente:
Cuando se ejecuta el paso Authorization, realiza la autorización de servidor por omisión, que, por su parte, llama a la función de plug-in de autenticación.
Recuerde los puntos siguientes:
Utilice el almacenamiento de variants en antememoria para guardar en antememoria los datos que se hayan modificado del documento original (el URI). Caching Proxy gestiona los variants generados por la API. Los variants son distintas versiones de un documento base.
Por lo general, cuando los servidores de origen envían variants, no pueden identificarse como tales. Caching Proxy sólo da soporte a variants creados por plug-ins (por ejemplo, conversión de páginas de código). Si un plug-in crea un variant según criterios que no están en la cabecera HTTP, debe incluir una función de paso PreExit o PostAuthorization para crear una seudocabecera a fin de que Caching Proxy puede identificar correctamente el variant existente.
Por ejemplo, utilice el programa de la API de Transmogrifier para modificar los datos que los usuarios soliciten según el valor de la cabecera User-Agent que el navegador envíe. En la función close, guarde el contenido modificado en un archivo o especifique un longitud de almacenamiento intermedio y pase el almacenamiento intermedio como argumento de datos. A continuación, utilice las funciones de almacenamiento de variants en antememoria httpd_variant_insert() y httpd_variant_lookup() para colocar el contenido en la antememoria.
Para ayudarle a empezar a utilizar funciones de la API de Caching Proxy propias, observe los programas de ejemplo que se proporcionan en el directorio samples del CD-ROM de instalación de Edge Components. . Hay información adicional disponible en el sitio Web de WebSphere Application Server, www.ibm.com/software/webservers/appserv/.
En este apartado se describe cómo escribir asesores personalizados para Load Balancer.
Los asesores son agentes de software que funcionan dentro de Load Balancer para proporcionar información acerca de la carga en un servidor determinado. Existe un asesor distinto para cada protocolo estándar (HTTP, SSL y otros). Periódicamente, el código base de Load Balancer realiza un ciclo de asesor durante el que evalúa de forma individual el estado de todos los servidores de su configuración.
Al escribir asesores propios para Load Balancer, puede personalizar cómo se determina la carga de las máquinas de servidor.
En sistemas Windows: Cuando utilice una instalación Load Balancer para IPv4 e IPv6, si utiliza el protocolo IPv6 en la máquina y desea utilizar asesores deberá modificar el archivo protocol que se encuentra en el directorio C:\windows\system32\drivers\etc\.
Para IPv6, inserte la siguiente línea en el archivo protocol:
ipv6-icmp 58 IPv6-ICMP # Protocolo de mensajes de control de interfaz IPv6
Por lo general, los asesores sirven para habilitar el equilibrio de carga de la manera siguiente.
Los asesores estándar que se proporcionan con Load Balancer incluyen asesores para las funciones siguientes. Hay información detallada disponible sobre estos asesores en la publicación WebSphere Application Server Load Balancer Administration Guide.
Para dar soporte a los protocolos de propiedad para los que no se proporcionan asesores estándar, debe escribir asesores personalizados.
Un asesor personalizado es un pequeña porción de código Java, proporcionada como archivo de clases, a la que llama el código base de Load Balancer para determinar la carga en un servidor. El código base proporciona todos los servicios administrativos necesarios, incluidos el inicio y la detención de una instancia del asesor personalizado, con estados e informes, registro de la información de historial en un archivo de anotaciones cronológicas y notificación de los resultados del asesor al componente de gestor.
Cuando el código base de Load Balancer llama a un asesor personalizado, tienen lugar los pasos siguientes:
Se pueden diseñar asesores personalizados para interactuar con Load Balancer en modalidad normal o modalidad de sustitución.
La elección de la modalidad de funcionamiento se especifica en el archivo del asesor personalizado como parámetro en el método constructor. Cada asesor sólo funcionan en una de estas modalidades, en función de su diseño.
En modalidad normal, el asesor personalizado intercambia datos con el servidor y el código del asesor base controla el tiempo del intercambio y calcula el valor de carga. El código base notifica, a continuación, este valor de carga al gestor. El asesor personalizado devuelve el valor cero para indicar que la operación ha sido satisfactoria o -1 para indicar que se ha producido un error.
Para especificar la modalidad normal, establezca el distintivo de sustitución del constructor en false.
En modalidad de sustitución, el código base no realiza ninguna medición de tiempo. El código del asesor personalizado realiza las operaciones que se especifiquen, según sus requisitos exclusivos y, a continuación, devuelve un número de carga real. El código base acepta el número de carga y lo notifica, sin alterar, al gestor. Para obtener resultados óptimos, normalice los números de carga entre 10 y 1000, donde 10 representa un servidor rápido y 1000 representa un servidor lento.
Para especificar una modalidad de sustitución, establezca el distintivo replace del constructor en true.
Los nombres de archivo de asesor personalizado deben tener el formato ADV_nombre.java, donde nombre es el nombre que elija para el asesor. El nombre completo debe empezar por el prefijo ADV_ en mayúsculas y los caracteres posteriores deben ser en minúscula. El requisito de minúsculas garantiza que el mandato para ejecutar el asesor no sea sensible a mayúsculas y minúsculas.
Según las convenciones Java, el nombre de la clase definida en el archivo debe coincidir con el nombre del archivo.
Los asesores personalizados se deben escribir en lenguaje Java y se deben compilar con un compilador Java que esté instalado en la máquina de desarrollo. Durante la compilación, se hace referencia a los archivos siguientes:
La variable de entorno classpath debe apuntar tanto al archivo de asesor personalizado como al archivo de clases base durante la compilación. Un mandato de compilación puede tener el formato siguiente:
javac -classpath /opt/ibm/edge/lb/servers/lib/ibmnd.jar ADV_nombre.java
En este ejemplo se utiliza la vía de acceso de instalación de Linux y UNIX por omisión. El archivo de asesor se denomina ADV_nombre.java y el archivo de asesor se almacena en el directorio actual.
La salida de la compilación es un archivo de clases, por ejemplo ADV_nombre.class. Antes de iniciar el asesor, copie el archivo de clases al directorio vía_acceso_instalación/servers/lib/CustomAdvisors/.
Para ejecutar el asesor personalizado, debe copiar en primer lugar el archivo de clases del asesor en el subdirectorio lib/CustomAdvisors/ de la máquina de Load Balancer. Por ejemplo, para un asesor personalizado denominado miping, la vía de acceso del archivo es vía_acceso_instalación/servers/lib/CustomAdvisors/ADV_miping.class.
Configure Load Balancer, inicie su función de gestor y ejecute el mandato para iniciar el asesor personalizado. El asesor personalizado se especifica por su nombre, excluyendo el prefijo ADV_ y la extensión de archivo:
dscontrol advisor start miping número_puerto
El número de puerto especificado en el mandato es el puerto en el que el asesor abrirá una conexión con el servidor de destino.
Como todos los asesores, un asesor personalizado amplía las funciones de la clase base del asesor, que se denomina ADV_Base. La base del asesor realiza la mayor parte de las funciones del asesor, como volver a notificar las cargas al gestor para que las utilice en el algoritmo de peso del gestor. La base del asesor también realiza operaciones de conexión y cierre de socket y proporciona métodos de envío y recepción para que el asesor las utilice. El asesor sólo se utiliza para enviar y recibir datos en el puerto especificado del servidor que se está investigando. Los métodos TCP que se proporcionan en la base del asesor se temporizan para calcular la carga. Un distintivo dentro del constructor de la base del asesor sobrescribe la carga existente con la nueva carga que devuelve el asesor, si se desea.
Los asesores tienen los siguientes métodos de clase base:
Los detalles sobre estas rutinas obligatorias aparecen más adelante en este apartado.
Se llama a asesores personalizados después de buscar asesores nativos o estándar. Si Load Balancer no encuentra un asesor especificado en la lista de asesores estándar, consulta la lista de asesores personalizados. Hay información adicional disponible sobre la utilización de asesores en la publicación WebSphere Application Server Load Balancer Administration Guide.
Recuerde los requisitos siguientes para los nombres y las vías de acceso de los asesores personalizados.
void ADV_Base Constructor ( string sName; string sVersion; int iDefaultPort; int iInterval; string sDefaultLogFileName; boolean replace )
void ADV_AdvisorInitialize()
Este método se proporciona para realizar cualquier inicialización que pueda ser obligatoria para el asesor personalizado. Se llama a este método después de que se inicie el módulo base del asesor.
En muchos casos, incluidos los asesores estándar, este método no se utiliza y su código consta sólo de una sentencia return. Este método se puede utilizar para llamar al método suppressBaseOpeningSocket, que sólo es válido desde este método.
int getLoad( int iConnectTime; ADV_Thread *caller )
Los métodos, o funciones, que se describen en los apartados siguientes, se pueden llamar desde asesores personalizados. El código base del asesor da soporte a estos métodos.
Algunas de estas llamadas a funciones se pueden realizar directamente, por ejemplo, nombre_función(), pero otras exigen el prefijo caller. Caller representa la instancia de asesor base que da soporte al asesor base que se va a ejecutar.
La función ADVLOG permite que un asesor personalizado grabe un mensaje de texto en el archivo de anotaciones cronológicas base del asesor. El formato es:
void ADVLOG (int logLevel, string message)
La función getAdvisorName devuelve una serie Java con la parte de sufijo del nombre del asesor personalizado. Por ejemplo, para un asesor denominado ADV_cdload.java, esta función devuelve el valor cdload.
Esta función no adopta ningún parámetro.
Tenga en cuenta que no es posible que este valor cambie durante la creación de una instancia de un asesor.
La función getAdviseOnPort devuelve el número de puerto en el que se está ejecutando el asesor personalizado que realiza la llamada. El valor de retorno es un entero Java (int) y la función no adopta ningún parámetro.
Tenga en cuenta que no es posible que este valor cambie durante la creación de una instancia de un asesor.
La función getCurrentServer devuelve la dirección IP del servidor actual. El valor de retorno es una serie Java en formato de dirección IP, por ejemplo, 128.0.72.139.
Normalmente, esta dirección cambia cada vez que se llama al asesor personalizado porque el código base del asesor consulta todas las máquinas de servidor en serie.
Esta función no adopta ningún parámetro.
La función getCurrentCluster devuelve la dirección IP del clúster de servidores actual. El valor de retorno es una serie Java en formato de dirección IP, por ejemplo, 128.0.72.139.
Normalmente, esta dirección cambia cada vez que se llama al asesor personalizado porque el código base del asesor consulta todas los clústeres de servidores en serie.
Esta función no adopta ningún parámetro.
La función getInterval devuelve un intervalo de asesor, es decir, el número de segundos entre ciclos de asesor. Este valor es igual al valor por omisión establecido en el constructor del asesor personalizado, a menos que se haya modificado el valor durante la ejecución mediante el mandato dscontrol.
El valor de retorno es un entero Java (int). La función no adopta ningún parámetro.
La función getLatestLoad permite que un asesor personalizado obtenga el valor de carga más reciente para un objeto de servidor determinado. El código base del asesor y el daemon de gestor mantienen los valores de carga en tablas internas.
int caller.getLatestLoad (string cluster_IP, int port, string server_IP)
Los tres argumentos juntos definen un objeto de servidor.
El valor de retorno es un entero.
Esta llamada a función es útil si desea que el comportamiento de un protocolo o un puerto dependa del comportamiento de otro. Por ejemplo, puede utilizar esta llamada a función en un asesor personalizado que haya inhabilitado un servidor de aplicaciones concreto si el servidor Telnet de esa misma máquina se había inhabilitado.
La función receive obtiene información de la conexión de socket.
caller.receive(stringbuffer *response)
El parámetro response es un almacenamiento intermedio de series en el que se colocan los datos recuperados. Además, la función devuelve un valor entero con el significado siguiente:
La función send utiliza la conexión de socket establecida para enviar un paquete de datos al servidor, con el puerto especificado.
caller.send(string command)
El parámetro command es una serie que contiene los datos que se deben enviar al servidor. La función devuelve un valor entero con el significado siguiente:
La llamada a la función suppressBaseOpeningSocket permite que un asesor personalizado especifique si el código de asesor base abre un socket TCP para el servidor en nombre del asesor personalizado. Si el asesor no utiliza una comunicación directa con el servidor para determinar su estado, puede que no sea necesario abrir el socket.
La llamada a función sólo se puede emitir una vez y debe emitirse desde la rutina ADV_AdvisorInitialize.
La función no adopta ningún parámetro.
En los ejemplos siguientes se muestra cómo se pueden implementar asesores personalizados.
Este código fuente de ejemplo es similar al asesor HTTP de Load Balancer. Funciona de la manera siguiente:
El asesor funciona en modalidad normal, por lo que la medición de la carga se basa en el tiempo transcurrido en milisegundos para realizar las operaciones de apertura, envío, recepción y cierre de socket.
package CustomAdvisors; import com.ibm.internet.lb.advisors.*; public class ADV_sample extends ADV_Base implements ADV_MethodInterface { static final String ADV_NAME ="Sample"; static final int ADV_DEF_ADV_ON_PORT = 80; static final int ADV_DEF_INTERVAL = 7; static final string ADV_SEND_REQUEST = "HEAD / HTTP/1.0\r\nAccept: */*\r\nUser-Agent: " + "IBM_Load_Balancer_HTTP_Advisor\r\n\r\n"; //-------- // Constructor public ADV_sample() { super(ADV_NAME, "3.0.0.0-03.31.00", ADV_DEF_ADV_ON_PORT, ADV_DEF_INTERVAL, "", false); super.setAdvisor( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { return; // normalmente una rutina vacía } //-------- // getLoad public int getLoad(int iConnectTime, ADV_Thread caller) { int iRc; int iLoad = ADV_HOST_INACCESSIBLE; // inicializa para inaccesible iRc = caller.send(ADV_SEND_REQUEST); // envía la petición HTTP al // servidor if (0 <= iRc) { // si el envío es satisfactorio StringBuffer sbReceiveData = new StringBuffer(""); // asigna un almacenamiento // intermedio para la // respuesta iRc = caller.receive(sbReceiveData); // recibe el resultado // analiza el resultado aquí si es necesario if (0 <= iRc) { // si la recepción es satisfactoria iLoad = 0; // devuelve 0 si es satisfactoria } // (la base ignora el valor de carga } // del asesor en modalidad normal) return iLoad; } }
Este ejemplo ilustra la supresión del socket estándar que ha abierto la base del asesor. En lugar de esto, este asesor abre un socket Java de secuencia lateral para consultar a un servidor. Este procedimiento puede ser útil para los servidores que utilicen un puerto distinto al del tráfico de cliente normal para escuchar una consulta de asesor.
En este ejemplo, un servidor escucha en el puerto 11999 y, cuando se le solicita, devuelve un valor de carga con un entero hexadecimal "4". Este ejemplo se ejecuta en modalidad de sustitución, es decir, el último parámetro del constructor del asesor se establece en true y el código base del asesor utiliza el valor de carga devuelto en lugar del tiempo transcurrido.
Observe la llamada a supressBaseOpeningSocket() en la rutina de inicialización. La supresión del socket base no es obligatoria cuando no se envíen datos. Por ejemplo, puede que desee abrir el socket para asegurarse de que el asesor puede ponerse en contacto con el servidor. Examine las necesidades de la aplicación con detenimiento antes de realizar la elección.
package CustomAdvisors; import java.io.*; import java.net.*; import java.util.*; import java.util.Date; import com.ibm.internet.lb.advisors.*; import com.ibm.internet.lb.common.*; import com.ibm.internet.lb.server.SRV_ConfigServer; public class ADV_sidea extends ADV_Base implements ADV_MethodInterface { static final String ADV_NAME = "sidea"; static final int ADV_DEF_ADV_ON_PORT = 12345; static final int ADV_DEF_INTERVAL = 7; // crea una matriz de bytes con el mensaje de petición de carga static final byte[] abHealth = {(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x04}; public ADV_sidea() { super(ADV_NAME, "3.0.0.0-03.31.00", ADV_DEF_ADV_ON_PORT, ADV_DEF_INTERVAL, "", true); // el parámetro de modalidad de sustitución es true super.setAdvisor( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { suppressBaseOpeningSocket(); // indica al código base que no abra el // socket estándar return; } //-------- // getLoad public int getLoad(int iConnectTime, ADV_Thread caller) { int iRc; int iLoad = ADV_HOST_INACCESSIBLE; // -1 int iControlPort = 11999; // puerto en el que se debe comunicar con el servidor string sServer = caller.getCurrentServer(); // dirección del servidor que se // debe consultar try { socket soServer = new Socket(sServer, iControlPort); // abre el socket para // el servidor DataInputStream disServer = new DataInputStream( soServer.getInputStream()); DataOutputStream dosServer = new DataOutputStream( soServer.getOutputStream()); int iRecvTimeout = 10000; // tiempo de espera establecido (en milisegundos) // para recibir datos soServer.setSoTimeout(iRecvTimeout); dosServer.writeInt(4); // envía un mensaje al servidor dosServer.flush(); iLoad = disServer.readByte(); // recibe la respuesta del servidor } catch (exception e) { system.out.println("Caught exception " + e); } return iLoad; // devuelve la carga notificada desde el servidor } }
Este ejemplo de asesor personalizado es una demostración de la posibilidad de detectar una anomalía en un puerto de un servidor según su propio estado y el estado de un daemon de servidor distinto que se ejecute en otro puerto de la misma máquina de servidor. Por ejemplo, si el daemon HTTP en el puerto 80 deja de responder, puede que también desee detener el direccionamiento de tráfico al daemon SSL en el puerto 443.
Este asesor es más agresivo que los asesores estándar, porque considera que cualquier servidor que no envía una respuesta ha dejado de funcionar y lo marca como sin funcionamiento. Los asesores estándar consideran que los servidores que no responden son muy lentos. Este asesor marca un servidor como que no está en funcionamiento tanto para el puerto HTTP como para el puerto SSL si uno de los dos puertos no responde.
Para utilizar este asesor personalizado, el administrador inicia dos instancias del asesor: una en el puerto HTTP y otra en el puerto SSL. El asesor crea instancias de dos tablas hash globales estáticas, una para HTTP y una para SSL. Cada asesor intenta comunicar con su daemon de servidor y almacena el resultado de este suceso en su tabla hash. El valor que cada asesor devuelve a la clase de asesor base depende tanto de la capacidad de comunicar con su propio daemon de servidor como de la capacidad del asesor asociado para comunicarse con su daemon.
Se utilizan los siguientes métodos personalizados.
Se detectan las siguientes condiciones de error.
Este ejemplo se ha escrito para enlazar los puertos 80 para HTTP y 443 para SSL, pero se puede adaptar a cualquier combinación de puertos.
package CustomAdvisors; import java.io.*; import java.net.*; import java.util.*; import java.util.Date; import com.ibm.internet.lb.advisors.*; import com.ibm.internet.lb.common.*; import com.ibm.internet.lb.manager.*; import com.ibm.internet.lb.server.SRV_ConfigServer; //-------- // Define el elemento de tabla de las tablas hash utilizadas en este // asesor personalizado class ADV_nte implements Cloneable { private string sCluster; private int iPort; private string sServer; private int iLoad; private Date dTimestamp; //-------- // constructor public ADV_nte(string sClusterIn, int iPortIn, string sServerIn, int iLoadIn) { sCluster = sClusterIn; iPort = iPortIn; sServer = sServerIn; iLoad = iLoadIn; dTimestamp = new Date(); } //-------- // comprueba si este elemento es actual o ha caducado public boolean isCurrent(ADV_twop oThis) { boolean bCurrent; int iLifetimeMs = 3 * 1000 * oThis.getInterval(); // establece tiempo de vida // como 3 ciclos de asesor Date dNow = new Date(); Date dExpires = new Date(dTimestamp.getTime() + iLifetimeMs); if (dNow.after(dExpires)) { bCurrent = false; } else { bCurrent = true; } return bCurrent; } //-------- // objeto(s) usuario de valor public int getLoadValue() { return iLoad; } //-------- // clona (evita la corrupción entre hebras) public synchronized Object Clone() { try { return super.clone(); } catch (cloneNotSupportedException e) { return null; } } } //-------- // define el asesor personalizado public class ADV_twop extends ADV_Base implements ADV_MethodInterface, ADV_AdvisorVersionInterface { static final int ADV_TWOP_PORT_HTTP = 80; static final int ADV_TWOP_PORT_SSL = 443; //-------- // define las tablas para mantener información de historial específica de puertos static HashTable htTwopHTTP = new Hashtable(); static HashTable htTwopSSL = new Hashtable(); static final String ADV_TWOP_NAME = "twop"; static final int ADV_TWOP_DEF_ADV_ON_PORT = 80; static final int ADV_TWOP_DEF_INTERVAL = 7; static final string ADV_HTTP_REQUEST_STRING = "HEAD / HTTP/1.0\r\nAccept: */*\r\nUser-Agent: " + "IBM_LB_Custom_Advisor\r\n\r\n"; //-------- // crea una matriz de bytes con el mensaje de saludo del cliente SSL public static final byte[] abClientHello = { (byte)0x80, (byte)0x1c, (byte)0x01, // saludo del cliente (byte)0x03, (byte)0x00, // versión SSL (byte)0x00, (byte)0x03, // longitud de especificación de cifrado (bytes) (byte)0x00, (byte)0x00, // longitud de ID de sesión (bytes) (byte)0x00, (byte)0x10, // longitud de datos de desafío (bytes) (byte)0x00, (byte)0x00, (byte)0x03, // especificación de cifrado (byte)0x1A, (byte)0xFC, (byte)0xE5, (byte)Ox20, // datos de desafío (byte)0xFD, (byte)0x3A, (byte)0x3C, (byte)0x18, (byte)0xAB, (byte)0x67, (byte)0xB0, (byte)0x52, (byte)0xB1, (byte)0x1D, (byte)0x55, (byte)0x44, (byte)0x0D, (byte)0x0A }; //-------- // constructor public ADV_twop() { super(ADV_TWOP_NAME, VERSION, ADV_TWOP_DEF_ADV_ON_PORT, ADV_TWOP_DEF_INTERVAL, "", false); // false = Load Balancer temporiza la respuesta setAdvisor ( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { return; } //-------- // rutinas de acceso PUT y GET sincronizadas para las tablas hash synchronized ADV_nte getNte(Hashtable ht, String sName, String sHashKey) { ADV_nte nte = (ADV_nte)(ht.get(sHashKey)); if (null != nte) { nte = (ADV_nte)nte.clone(); } return nte; } synchronized void putNte(Hashtable ht, String sName, String sHashKey, ADV_nte nte) { ht.put(sHashKey,nte); return; } //-------- // getLoadHTTP - determina la carga HTTP según la respuesta del servidor int getLoadHTTP(int iConnectTime, ADV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iRc = caller.send(ADV_HTTP_REQUEST_STRING); // envía un mensaje de petición // al servidor if (0 <= iRc) { // ¿ha devuelto una anomalía la petición? StringBuffer sbReceiveData = new StringBuffer("") // asigna un almacenamiento // intermedio para la // respuesta iRc = caller.receive(sbReceiveData); // obtener respuesta del servidor if (0 <= iRc) { // ¿ha devuelto una anomalía la recepción? if (0 < sbReceiveData.length()) { // ¿hay datos? iLoad = SUCCESS; // ignora los datos recuperados y // devuelve un código de ejecución satisfactoria } } } return iLoad; } //-------- // getLoadSSL() - determina la carga de SSL según la respuesta del servidor int getLoadSSL(int iConnectTime, ASV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iSocket = caller.getAdvisorSocket(); // envía una petición hexadecimal // al servidor CMNByteArrayWrapper cbawClientHello = new CMNByteArrayWrapper( abClientHello); int iRc = SRV_ConfigServer.socketapi.sendBytes(iSocket, cbawClientHello); if (0 <= iRc) { // ¿ha devuelto una anomalía la petición? StringBuffer sbReceiveData = new StringBuffer(""); // asigna un almacenamiento // intermedio para la // respuesta iRc = caller.receive(sbReceiveData); // obtiene una respuesta del // servidor if (0 <= iRc) { // ¿ha devuelto una anomalía la recepción? if (0 < sbReceiveData.length()) { // ¿hay datos? iLoad = SUCCESS; // ignora los datos recuperados y devuelve un código // de ejecución satisfactoria } } } return iLoad; } //-------- // getLoad - fusiona los resultados de los métodos HTTP y SSL public int getLoad(int iConnectTime, ADV_Thread caller) { int iLoadHTTP; int iLoadSSL; int iLoad; int iRc; String sCluster = caller.getCurrentCluster(); // dirección de clúster actual int iPort = getAdviseOnPort(); String sServer = caller.getCurrentServer(); String sHashKey = sCluster = ":" + sServer; // clave de tabla hash if (ADV_TWOP_PORT_HTTP == iPort) { // gestiona un servidor HTTP iLoadHTTP = getLoadHTTP(iConnectTime, caller); // obtiene la carga de HTTP ADV_nte nteHTTP = newADV_nte(sCluster, iPort, sServer, iLoadHTTP); putNte(htTwopHTTP, "HTTP", sHashKey, nteHTTP); // guarda la información // de SSL ADV_nte nteSSL = getNte(htTwopSSL, "SSL", sHashKey); // obtiene información // de SSL if (null != nteSSL) { if (true == nteSSL.isCurrent(this)) { // comprueba la indicación // de la hora if (ADV_HOST_INACCESSIBLE != nteSSL.getLoadValue()) { // ¿funciona // SSL? iLoad = iLoadHTTP; } else { // SSL no funciona, por lo que marca el servidor HTTP como // sin funcionamiento iLoad= ADV_HOST_INACCESSIBLE; } } else { // la información de SSL ha caducado, por lo que marca el // servidor HTTP como sin funcionamiento iLoad = ADV_HOST_INACCESSIBLE; } } else { // no hay información de carga acerca de SSL, se informa de // los resultados de getLoadHTTP() iLoad = iLoadHTTP; } } else if (ADV_TWOP_PORT_SSL == iPort) { // gestiona un servidor SSL iLoadSSL = getLoadSSL(iConnectTime, caller); // obtiene la carga de SSL ADV_nte nteSSL = new ADV_nte(sCluster, iPort, sServer, iLoadSSL); putNte(htTwopSSL, "SSL", sHashKey, nteSSL); // guarda la información de // carga de SSL. ADV_nte nteHTTP = getNte(htTwopHTTP, "SSL", sHashKey); // obtiene información // de HTTP if (null != nteHTTP) { if (true == nteHTTP.isCurrent(this)) { // comprueba la indicación // de la hora if (ADV_HOST_INACCESSIBLE != nteHTTP.getLoadValue()) { // ¿funciona // HTTP? iLoad = iLoadSSL; } else { // el servidor HTTP no funciona, por lo que marca SSL como // sin funcionamiento iLoad = ADV_HOST_INACCESSIBLE; } } else { // información caducada de HTTP, por lo que marca SSL como // sin funcionamiento iLoad = ADV_HOST_INACCESSIBLE; } } else { // no hay información de carga acerca de HTTP, se informa de // los resultados de getLoadSSL() iLoad = iLoadSSL; } } //-------- // manejador de errores else { iLoad = ADV_HOST_INACCESSIBLE; } return iLoad; } }
Se incluye un asesor personalizado de ejemplo para WebSphere Application Server en el directorio vía_acceso_instalación/servers/samples/CustomAdvisors/. En este documento no se duplica el código completo.
El asesor completo sólo es un poco más complejo que el del ejemplo. Añade una rutina de análisis especializada que es más compacta que la del ejemplo de StringTokenizer mostrado anteriormente.
La parte más compleja del código de ejemplo está en el servlet Java. Entre otros métodos, el servlet contiene dos métodos que exige la especificación de servlet, init() y service(), y un método run(), que exige la clase Java.lang.thread.
Los fragmentos relevantes del código del servlet aparecen a continuación.
... public void init(ServletConfig config) throws ServletException { super.init(config); ... _checker = new Thread(this); _checker.start(); } public void run() { setStatus(GOOD); while (true) { if (!getKeepRunning()) return; setStatus(figureLoad()); setLastUpdate(new java.util.Date()); try { _checker.sleep(_interval * 1000); } catch (Exception ignore) { ; } } } public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { ServletOutputStream out = null; try { out = res.getOutputStream(); } catch (Exception e) { ... } ... res.setContentType("text/x-application-LBAdvisor"); out.println(getStatusString()); out.println(getLastUpdate().toString()); out.flush(); return; } ...
Tanto si utiliza una llamada estándar a una parte existente del servidor de aplicaciones como si añade una nueva pieza de código al equivalente del asesor personalizado del lado del servidor, es posible que desee examinar los valores de carga devueltos y cambiar el funcionamiento del servidor. La clase Java StringTokenizer y sus métodos asociados hacen que esta investigación sea sencilla.
El contenido de un mandato HTTP típico puede ser GET /index.html HTTP/1.0.
Una respuesta típica a este mandato puede ser la siguiente:
HTTP/1.1 200 OK Date: Mon, 20 November 2000 14:09:57 GMT Server: Apache/1.3.12 (Linux and UNIX) Content-Location: index.html.en Vary: negotiate TCN: choice Last-Modified: Fri, 20 Oct 2000 15:58:35 GMT ETag: "14f3e5-1a8-39f06bab;39f06a02" Accept-Ranges: bytes Content-Length: 424 Connection: close Content-Type: text/html Content-Language: en <!DOCTYPE HTML PUBLIC "-//w3c//DTD HTML 3.2 Final//EN"> <HTML><HEAD><TITLE>Test Page</TITLE></HEAD> <BODY><H1>Apache server</H1> <HR> <P><P>This Web server is running Apache 1.3.12. <P><HR> <P><IMG SRC="apache_pb.gif" ALT=""> </BODY></HTML>
Los elementos de interés están contenidos en la primera línea, específicamente el código de retorno HTTP.
La especificación HTTP clasifica los códigos de retornos que se pueden resumir de la manera siguiente:
Si debe saber exactamente los códigos que el servidor puede devolver, puede que el código no tenga que ser tan detallado como en este ejemplo. No obstante, recuerde que al limitar los códigos de retorno que detecte también puede limitar la futura flexibilidad del programa.
El ejemplo siguiente es un programa Java autónomo que contiene un cliente HTTP mínimo. El ejemplo invoca un analizador simple general para examinar respuestas HTTP.
import java.io.*; import java.util.*; import java.net.*; public class ParseTest { static final int iPort = 80; static final String sServer = "www.ibm.com"; static final String sQuery = "GET /index.html HTTP/1.0\r\n\r\n"; static final String sHTTP10 = "HTTP/1.0"; static final String sHTTP11 = "HTTP/1.1"; public static void main(String[] Arg) { String sHTTPVersion = null; String sHTTPReturnCode = null; String sResponse = null; int iRc = 0; BufferedReader brIn = null; PrintWriter psOut = null; Socket soServer= null; StringBuffer sbText = new StringBuffer(40); try { soServer = new Socket(sServer, iPort); brIn = new BufferedReader(new InputStreamReader( soServer.getInputStream())); psOut = new PrintWriter(soServer.getOutputStream()); psOut.println(sQuery); psOut.flush(); sResponse = brIn.readLine(); try { soServer.close(); } catch (Exception sc) {;} } catch (Exception swr) {;} StringTokenizer st = new StringTokenizer(sResponse, " "); if (true == st.hasMoreTokens()) { sHTTPVersion = st.nextToken(); if (sHTTPVersion.equals(sHTTP110) || sHTTPVersion.equals(sHTTP11)) { System.out.println("HTTP Version: " + sHTTPVersion); } else { System.out.println("Invalid HTTP Version: " + sHTTPVersion); } } else { System.out.println("Nothing was returned"); return; } if (true == st.hasMoreTokens()) { sHTTPReturnCode = st.nextToken(); try { iRc = Integer.parseInt(sHTTPReturnCode); } catch (NumberFormatException ne) {;} switch (iRc) { case(200): System.out.println("HTTP Response code: OK, " + iRc); break; case(400): case(401): case(402): case(403): case(404): System.out.println("HTTP Response code: Client Error, " + iRc); break; case(500): case(501): case(502): case(503): System.out.println("HTTP Response code: Server Error, " + iRc); break; default: System.out.println("HTTP Response code: Unknown, " + iRc); break; } } if (true == st.hasMoreTokens()) { while (true == st.hasMoreTokens()) { sbText.append(st.nextToken()); sbText.append(" "); } System.out.println("HTTP Response phrase: " + sbText.toString()); } } }