Para generar el esqueleto del servicio se utilizan herramientas de

Anuncio
Instanciación de información de un portal web. Incidencias de
tráfico.
Uno de los servicios de tráfico que se han implementado es el servicio de
información de incidencias de tráfico de la DGT. Este servicio, pertenece al tipo de
servicios que poseen un formulario previo para que el cliente introduzca unos
parámetros para restringir la información de incidencias que el cliente quiere obtener del
servicio.
Figura 1: Servicio de información de incidencias de la DGT
La salida de este servicio es una página HTML que contiene una tabla con todas
las incidencias de tráfico existentes en ese momento, dados unos parámetros de entrada
por parte de un cliente. Para poder definir semánticamente cada una de las filas de la
tabla que representan una incidencia en una de las carreteras de la red de carreteras de
España, se decidió modificar el servicio de manera que la salida de éste pudiese ser
definida semánticamente como incidencias.
Figura 2: Portal web de información de incidencias de la DGT
Para poder hacerlo, se ha desarrollado un agente Wrapper preparado para acceder
al portal de la DGT, invocándolo para obtener todas las incidencias de cualquier tipo de
toda España. Con esta invocación obtenemos la tabla con todas las incidencias activas
en ese momento concreto, por lo que el Wrapper va accediendo a cada una de ellas, y
con la ayuda de la ontología de conceptos de tráfico, y más concretamente con la
especificación del concepto Incidente, se describen cada una de ellas como instancias de
este concepto.
A continuación podemos ver un extracto del código WebL implementado en el
agente:
...
try
//Acceso al portal de incidencias de la DGT
Home = PostURL("http://www.dgt.es/carreteras/rutasgraf.jsp",[.
criterio="global", inci="TODAS", tipo="inci", salida="texto",
textocampo="",textovalor="", textotipo="Todas",textofiltro="Toda
España",textocriterio="" .] )
catch E
on E.statuscode == 404 do PrintLn("page not found")
on E.type == "HttpError" do PrintLn("connection error")
on true do nil // catch everything else
end;
...
//Función para especificar las incidencias mediante lenguaje semántico
var nuevaincidencia =
fun(fecha,tipo,causas,poblacion,provincia,dia,mes,year,horainiM,horain
iH,nivel,carretera,pki,pkf,sentido,hacia)
"<sucesos:Incidente
rdf:ID='INCI_"+causas+"_"+carretera+"_"+pki+"_"+pkf+"_"+fecha+"_"+hora
iniH+"_"+horainiM+"'>\n
<rdfs:comment>Estado de las carreteras (Incidencias)</rdfs:comment>\n
...
end;
Una vez especificadas mediante lenguaje semántico formal todas las incidencias
que contiene la página web, las instancias se almacenan en un repositorio SesameSeBOR específico para este tipo de información.
Para poder ofrecer las mismas funcionalidades que las ofrecidas por el portal
(mismo tipo de requerimientos), se construyen las consultas correspondientes que
permiten acceder al repositorio, y las cuales devuelven los mismos resultados que
devolvería la página web. Para este servicio web, no se ha potenciado ningún parámetro
más de entrada que los definidos ya por el proveedor.
Para representar las incidencias, ya hemos indicado que se utiliza el concepto
Incidente de la ontología de conceptos de tráfico. Como ya se comentó en el capítulo 8,
este concepto ha sido desarrollado a partir del tipo de información que describe a una
incidencia en tráfico.
De cada incidente se muestra diferente información, que se puede observar porque
viene representada en cada columna de la tabla: tipo de incidencia, causas y
observaciones, provincia, población, fecha hora inicial, nivel, carretera, kilómetro
inicial, kilómetro final, sentido y hacia.
Para este tipo de servicio se han especificado tres tipos de consultas: para obtener
incidencias del tipo y provincia que especifique el usuario en su petición, consulta que
devuelve incidencias del tipo y dentro de la comunidad autónoma que se le especifique,
y una tercera que devuelve las incidencias del tipo que el usuario especifique que tiene
lugar en toda España.
La siguiente consulta es la del primer tipo, es decir, nos devuelve las incidencias
de la provincia y del tipo especificados por el cliente.
Select Incidencia
From {Incidencia} <rdf:type> {<ns8:Incidente>},
{Incidencia} <ns8:tieneProvincia> {A},
{Incidencia} <ns8:tipo> {B}
Where A = “URIdelaprovinciaqueespecificaelcliente”
and B = “URIdeltipoincidenciaqueespecificaelcliente”
Aprovechando este servicio, si se observa de nuevo el concepto Incidente que es la
información que se nos devuelve, se puede interactuar con diferentes ontologías
(conocimiento) para obtener más información sobre algunas de las propiedades que
definen un incidente. Por ejemplo, la propiedad carretera nos indica en que carretera o
vía concreta tiene lugar el incidente, siendo esta carretera (instancia) definida
semánticamente en su ontología correspondiente, es decir, en “Vias.daml”. Gracias a
esto, el servicio web o el cliente, podría volver a entrar en el repositorio donde se
mantiene tanto la información de las incidencias como las ontologías y conocimiento
que hacen uso de ellas, para poder interactuar con la información de la carretera en la
que ocurre una incidencia en concreto, y por ejemplo, obtener el tipo de carretera que
es, algún tipo de información sobre esta carretera y el tipo de vehículos que pueden
transitar por este tipo de carretera, como también cuales son los incidentes activos en
esa carretera:
Select Incidencia, Class, Comentario, Aux2
From {Incidencia} <rdf:type> {<sucesos:Incidente>},
{Incidencia} <sucesos:carretera> {carretera},
{carretera} <serql:directType> {Class},
{Class} <rdfs:comment> {Comentario},
{Class} <rdfs:subClassOf> {Aux},
{Aux} <daml:onProperty> {<vias:serTransitadaPor>},
{Aux} <daml:hasClass> {Aux2}
Where carretera = <vias:IDdelacarretera>
Otro tipo de consulta que se podría realizar es dada una incidencia, a través de la
propiedad carretera obtener el nombre de las comunidades autónomas por donde
transcurre y las posibles incidencias que ocurran en cualquier otra carretera dentro de
estas comunidades autónomas
select distinct Carretera, CA, Incidencia
from {Carretera} <vias:numero_Tramos> {Aux},
{Aux} <xsd:value> {tramos},
{Carretera} PredAux {Poblacion},
{Poblacion} <serql:directType> {<geografia:Poblacion>},
{Poblacion} <geografia:ser_parte_de> {Provincia},
{Provincia} <serql:directType> {<geografia:Provincia>},
{Provincia} <ns0:ser_parte_de> {CA},
{CA} <serql:directType> {<geografia:Comunidades_Autonomas>},
{CA} <geografia:estar_compuesta_por> {Provincia2},
{Incidencia} <sucesos:provincia> {Provincia2}
where Carretera = <vias:IDdelacarretera>
De esta manera, se puede comprobar que toda la información semántica de los
recursos descrita en diferentes ontologías, es accesible y solo necesitamos de un
lenguaje de consulta, un razonador y un repositorio que mantenga las ontologías y
permita interconectar los conocimientos.
Despliegue de un servicio web: Servicio de previsiones de tráfico
Para generar el esqueleto del servicio se utilizan herramientas de Apache AXIS
[Alm02].
El proceso básico para construir un servicio Web con Apache Axis es el siguiente:
1. Construcción de un interfaz de los métodos que deba implementar nuestro
servicio web y compilación junto con la clase que use dichos métodos.
2. Utilizar Java2WSDL para generar el archivo WSDL del interfaz anterior.
3. Utilizar WSDL2Java para generar los esqueletos del código necesario para
desplegar el servicio y los stubs para invocarlo.
4. Añadir al esqueleto lo necesario para completar el servicio web.
5. Desplegar el servicio.
Figura 10.3 Generación de código mediante AXIS
Para explicar el proceso de construcción de un servicio Web a continuación se detallan
los pasos seguidos para construir un servicio que devuelve las previsiones de tráfico
aportadas por la DGT en su Web para un día determinado.
1. Construcción de la interfaz, teniendo en cuenta los métodos del servicio así como los
parámetros y tipos que los componen y la clase que hará uso de esos métodos y la cual
será utilizada en el servicio Web.
En el siguiente código se puede apreciar la implementación de la interfaz
“ServicioPrevision” con el método “CalculaPrevision” que contiene tres parámetros, los
cuales constituyen la fecha usada como parámetro en la invocación.
package prevision;
public interface ServicioPrevision
{
public java.lang.String CalculaPrevision (int dia,int mes,int anyo);
}
Una vez construida la interfaz con el método pertinente, podemos proceder a la
implementación de la clase que utiliza dicho método, para que esta pueda ser utilizada
desde nuestro servicio web.
package prevision;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
import
org.openrdf.sesame.repository.remote.HTTPRepository;
org.openrdf.sesame.repository.SesameRepository;
org.openrdf.sesame.query.*;
org.openrdf.sesame.repository.remote.HTTPService;
org.openrdf.sesame.constants.*;
org.openrdf.sesame.admin.AdminListener;
org.openrdf.sesame.admin.AdminMsgCollector;
org.openrdf.sesame.Sesame;
org.openrdf.model.Resource;
org.openrdf.model.Value;
java.net.URI;
java.net.URL;
java.net.URLEncoder;
java.net.InetAddress;
java.net.Socket;
java.io.BufferedReader;
java.io.BufferedWriter;
java.io.OutputStreamWriter;
java.io.InputStreamReader;
java.io.*;
java.util.*;
public class ServicioPrevisionImpl
{
public String CalculaPrevision (int dia,int mes,int anyo)
{
/*
consulta SeRQL utilizada:
Select Prevision
From {Prevision} <rdf:type> {<ns8:Prevision>},
{Prevision} <ns8:FechadePrevision> {A},
{A} <time:year> {Y},
{A} <time:month> {M},
{A} <time:day> {D},
{Y} <rdf:value> {y},
{M} <rdf:value> {m},
{D} <rdf:value> {d}
Where d = "diaqpasaelcliente"^^<xsd:integer> and
m = "mesqpasaelcliente"^^<xsd:integer> and
y = "añoqpasaelcliente"^^<xsd:integer>
*/
String Salida=new String("Previsión obtenida: ");
System.out.println("Servicio Prevision_DGT");
//indico el parser xml que se debe usar, necesario para sesame
System.setProperty("org.xml.sax.driver", "org.apache.xerces.parsers.SAXParser");
SeBor misebor=new SeBor();
//obtengo un repositorio sebor plain
SesameRepository
mirepositorioplain=misebor.Conectar("http://localhost:8080/sesame/","testuser","opensesa
me","prevision-plain");
System.out.println("conectado a prevision-plain");
//obtengo un repositorio normal
SesameRepository
mirepositorio=misebor.Conectar("http://localhost:8080/sesame/","testuser","opensesame","
prevision");
//prevision y prevision-plain son los identificadores dados a los repositorios en la
config de sesame
System.out.println("conectado a prevision");
//ejemplo de consulta
//String consulta="Select X from {X} <service:presentedBy> {Y} ";
String consulta2=new String("");
consulta2+="Select Prevision, descripcion\n";
consulta2+="From {Prevision} <rdf:type> {<ns8:Prevision>},\n";
consulta2+="{Prevision} <ns8:fechadePrevision> {A},\n";
consulta2+="{Prevision} <ns8:descripcionPrevision> {descripcion},\n";
consulta2+="{A} <time:year> {Y},\n";
consulta2+="{A} <time:month> {M},\n";
consulta2+="{A} <time:day> {D},\n";
consulta2+="{Y} <rdf:value> {y},\n";
consulta2+="{M} <rdf:value> {m},\n";
consulta2+="{D} <rdf:value> {d}\n";
consulta2+="where d ="+"\""+ dia+"\"" +"\n";
consulta2+=" and m ="+"\""+ mes+"\"" +"\n";
consulta2+=" and y ="+"\""+anyo+"\"" +"\n";
consulta2+="using namespace\n";
consulta2+="rdfs = <!http://www.w3.org/2000/01/rdf-schema#>,\n";
consulta2+="service=<!http://www.DAML.org/services/DAMLs/0.9/Service.DAML#>,\n";
consulta2+="DAML = <!http://www.DAML.org/2001/03/DAML+oil#>,\n";
consulta2+="rdf = <!http://www.w3.org/1999/02/22-rdf-syntax-ns#>,\n";
consulta2+="ns8 = <!http://localhost/DAML_files/Sucesos.DAML#>,\n";
consulta2+="time = <!http://localhost/DAML_files/Time.DAML#>,\n";
consulta2+="bor = <!http://www.ontotext.com/otk/2002/07/bor#>,\n";
consulta2+="xsd = <!http://www.w3.org/2000/10/XMLSchema#>\n";
System.out.println("haciendo la consulta:\n");
System.out.println(consulta2);
System.out.println("resultado obtenido:");
QueryResultsTable
resultsTable=misebor.Preguntar_SERQL(consulta2,mirepositorio);
for (int row = 0; row < resultsTable.getRowCount(); row++)
{
for (int column = 0; column < resultsTable.getColumnCount(); column++)
{
Value value = resultsTable.getValue(row, column);
Salida+=value.toString()+"\n ";
}
}
System.out.println(Salida);
return (Salida);
}
}
En el código anterior se puede observar la creación de una clase llamada
ServicioPrevisionImpl, perteneciente al paquete prevision que contiene un método
llamado CalculaPrevision que recibe como parámetros 3 enteros, día, mes y año y
devuelve una cadena.
En la invocación del método es donde aparecerán diferencias según el tratamiento que
se le quiera dar al servicio. En nuestro caso y tras la elección de las diferentes
herramientas y lenguajes de consultas, lo cual ya fue justificado en capítulos anteriores,
se establece la composición de consultas SeRQL con los parámetros especificados y se
procede a la conexión con el repositorio Sesame+BOR para ejecutar la consulta dada y
obtener el resultado. En el ejemplo, la consulta devuelve las previsiones almacenadas
para un día determinado y la interacción con el repositorio se realiza con la clase Sebor
utilizada en el emparejador semántico.
2. Una vez compilados tanto el interfaz como la clase utilizamos la herramienta
Java2WSDL para generar el archivo WSDL que describe nuestro servicio web en
función de su interfaz.
La información que pasamos a Java2WSDL es la siguiente:





Nombre del archivo WSDL a generar (prevision.wsdl)
URL
que
tendrá
el
servicio
Web
(
http://localhost:8080/axis/services/servicioprevision )
Espacio de nombres de destino para el WSDL (urn:servicioprevision)
Mapeo entre el paquete Java y su espacio de nombres correspondiente
(servicioprevision=urn:servicioprevision)
La clase completamente cualificada (prevision.ServicioPrevision)
La línea de comandos para la llamada fue la siguiente:
java org.apache.axis.wsdl.Java2WSDL -o prevision.wsdl l"http://localhost:8080/axis/services/servicioprevision" -n urn:servicioprevision p"servicioprevision" urn:servicioprevision prevision.ServicioPrevision
Una vez ejecutado el programa obtenemos el archivo “prevision.wsdl” que define
nuestro servicio Web, y el cuál enlazará (previa adición de código) con el archivo
grounding de la descripción semántica del servicio.
3. En este punto se trata de coger como entrada el fichero “Wsdl” creado en el punto
anterior y generar el esqueleto básico del servicio Web y todo lo necesario para
desplegarlo. Para ello se usa la herramienta WSDL2Java.
Siguiendo con nuestro ejemplo generamos el código en el paquete prevision.ws para
mantenerlo separado del código original. La información dada a WSDL2Java fue la
siguiente:





Directorio base de salida (.)
Alcance del despliegue (aplicación, petición o sesión)
Solicitud de la generación del código del lado del cliente (no habría sido así si
sólo hubiésemos querido acceder a un servicio Web externo ya construido)
Paquete donde colocar el código (prevision.ws).
WSDL a utilizar (prevision.wsdl).
La línea de comandos para la llamada fue la siguiente:
java
org.apache.axis.wsdl.WSDL2Java -o . -d Session -s -p prevision.ws prevision.wsdl
Después de ejecutar WSDL2Java obtenemos los siguientes archivos en el directorio
prevision\ws :
ServicioprevisionSoapBindingImpl.java: código que implementa nuestro servicio
web, será el único archivo que tendremos que editar para que utilice la clase que
implementa lo que queremos que haga el servicio.
ServicioPrevision.java: Interfaz remota al sistema ServicioPrevision (extends remote y
métodos del ServicioPrevicion.java original, throw RemoteExceptions).
ServicioPrevisionService.java: Interfaz de servicio del servicio Web, ServiceLocator
lo implementa.
ServicioPrevisionServiceLocator.java: “Helper factory” para conseguir un manejador
del servicio.
ServicioprevisionSoapBindingSkeleton.java: Código del “skeleton” del lado del
servidor.
ServicioprevisionSoapBindingStub.java: Código del “stub” del lado del cliente que
encapsula accesos a él.
deploy.wsdd: Descriptor de desplegado que pasaremos al sistema Axis para que el
servicio web sea accesible.
undeploy.wsdd: Descriptor de desplegado para eliminar el servicio del sistema Axis.
4.Como se ha comentado anteriormente, al llegar a este punto lo que es necesario hacer
es modificar el archivo ServicioPrevisionSoapBindingImpl.java para que utilice la clase
ServicioPrevisionImpl.java para realizar la tarea que queremos que nuestro servicio web
haga. Las líneas añadidas están en negrita:
package prevision.ws;
import prevision.ServicioPrevisionImpl;
public class ServicioprevisionSoapBindingImpl implements prevision.ws.ServicioPrevision
{
ServicioPrevisionImpl servicioprevision=new ServicioPrevisionImpl();
public java.lang.String calculaPrevision(int in0, int in1, int in2) throws
java.rmi.RemoteException
{
return servicioprevision.CalculaPrevision(in0,in1,in2);
}
}
5. Para desplegar el servicio en Axis lo primero que hay que hacer es compilar el código
del servicio, por ejemplo desde la línea de comandos:
/* Compilación del código del servicio*/
javac prevision\ws*.java
/*Empaquetación del código y copiado en el classpath de Axis*/
jar cvf prevision.jar prevision/*.class prevision/ws/*.class
copy prevision.jar %TOMCAT_HOME%/Webapps/axis/WEB_INF/lib
/* Despliegue del servicio usando el descriptor de desplegado obtenido en el paso 3.
Uso de la herramienta cliente Admin de Axis */
java org.apache.axis.client.AdminClient deploy.wsdd
En este momento el servicio Web empieza a estar disponible.
Descargar