Initial commit

master
Miguel Coronado 12 years ago
commit 0017e5efda

1
.gitignore vendored

@ -0,0 +1 @@
build.properties

@ -0,0 +1,19 @@
/*
Jason Project
-- create on March 19, 2012
*/
MAS web40sojason {
infrastructure: Centralised
environment: es.upm.dit.gsi.sojason.SOEnvironment
agents:
userAgent;
travelAgent;
commonSenseAgent;
nluAgent;
aslSourcePath: "src/asl";
}

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!--
This file was generated by Jason 1.3.6a
http://jason.sf.net
March 20, 2012 - 16:30:55
-->
<project name ="web40sojason"
basedir=".."
default="run">
<property name="mas2j.project.file" value="Web40SOJason.mas2j"/>
<property name="debug" value=""/> <!-- use "-debug" to run in debug mode -->
<property name="build.dir" value="${basedir}/bin/classes" />
<property name="jasonJar" value="/home/miguel/trabajo/Jason-1.3.6a/lib/jason.jar"/>
<path id="project.classpath">
<pathelement location="${basedir}"/>
<pathelement location="${build.dir}"/>
<pathelement location="${jasonJar}"/>
<fileset dir="${basedir}/lib" > <include name="*.jar" /> </fileset>
</path>
<!-- tasks the user can override in his/her c-build.xml script -->
<target name="user-init">
</target>
<target name="user-end">
</target>
<target name="init">
<mkdir dir="${build.dir}" />
<antcall target="user-init" />
</target>
<target name="compile" depends="init">
<condition property="srcdir" value="${basedir}/src/java" else="${basedir}" >
<available file="${basedir}/src/java" />
</condition>
<javac srcdir="${srcdir}" destdir="${build.dir}" debug="true" optimize="true" includeantruntime="false" >
<classpath refid="project.classpath"/>
</javac>
</target>
<target name="jar" depends="compile">
<delete file="${ant.project.name}.jar" />
<copy file="${jasonJar}" tofile="${ant.project.name}.jar" />
<copy file="${mas2j.project.file}" tofile="default.mas2j" />
<jar update="yes" jarfile="${ant.project.name}.jar" >
<fileset dir="${basedir}">
<include name="**/*.asl" />
<include name="**/*.mas2j" />
</fileset>
<fileset dir="${build.dir}">
<include name="**/*.class" />
</fileset>
</jar>
<delete file="default.mas2j" />
</target>
<target name="jnlp" depends="jar" >
<mkdir dir="${basedir}/${ant.project.name}-jws"/>
<java classname="jason.infra.centralised.CreateJNLP"
failonerror="true" fork="yes" dir="${basedir}/${ant.project.name}-jws" >
<classpath refid="project.classpath"/>
<arg line="${ant.project.name} ${mas2j.project.file}"/>
</java>
<copy todir="${basedir}/${ant.project.name}-jws" failonerror="no">
<fileset dir="${basedir}/lib" includes="**/*.jar" />
<fileset dir="${basedir}" includes="${ant.project.name}.jar" />
<fileset dir="/home/miguel/trabajo/Jason-1.3.6a/src/images" includes="Jason-GMoreau-Icon.jpg" />
</copy>
<signjar jar="${basedir}/${ant.project.name}-jws/${ant.project.name}.jar" alias="jason"
storepass="rbjhja" keypass="rbjhja" keystore="/home/miguel/trabajo/Jason-1.3.6a/src/jasonKeystore" />
<echo message="**" />
<echo message="** Java Web Start application created in directory ${ant.project.name}-jws" />
<echo message="** Update the codebase (in the second line of the .jnlp file)" />
<echo message="** with the URL where you will upload the application." />
<echo message="**" />
</target>
<target name="run" depends="compile" >
<echo message="Running project ${ant.project.name}" />
<java classname="jason.infra.centralised.RunCentralisedMAS"
failonerror="true" fork="yes" dir="${basedir}" >
<classpath refid="project.classpath"/>
<arg line="${mas2j.project.file} ${debug} "/>
<!-- jvmarg line="-Xmx500M -Xss8M"/ -->
</java>
<antcall target="user-end" />
</target>
<target name="clean" >
<delete failonerror="no" includeEmptyDirs="true" verbose="true">
<fileset dir="${basedir}" includes="**/*.class"/>
</delete>
</target>
</project>

@ -0,0 +1,152 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>Renfe city codes</comment>
<entry key="ciudad real">37200</entry>
<entry key="bilbao">13200 </entry>
<entry key="almeria">56312</entry>
<entry key="lisboa">LISBO</entry>
<entry key="león">15100</entry>
<entry key="bardonecchia">83005</entry>
<entry key="puerto santa maría">51400</entry>
<entry key="a coruña">31412 </entry>
<entry key="monforte de lemos">20300</entry>
<entry key="pontevedra">23004</entry>
<entry key="albacete">60911 </entry>
<entry key="berna">85031</entry>
<entry key="valdepeñas">50102</entry>
<entry key="benicassim">65318</entry>
<entry key="málaga">54413</entry>
<entry key="linares-baeza">50300</entry>
<entry key="tarragona">82100</entry>
<entry key="teruel">67200</entry>
<entry key="cartagena">61307</entry>
<entry key="cádiz">51405</entry>
<entry key="jaen">03100</entry>
<entry key="cuenca">CUENC</entry>
<entry key="turín">83002</entry>
<entry key="córdoba">50500</entry>
<entry key="entroncamento">94428</entry>
<entry key="burgos rosa de lima">11014 </entry>
<entry key="alacant">60911</entry>
<entry key="marvao-beira">94401</entry>
<entry key="malaga">54413</entry>
<entry key="sahagún">15009</entry>
<entry key="gasteiz">11208</entry>
<entry key="ginebra">85444</entry>
<entry key="cordoba">50500</entry>
<entry key="irún">11600</entry>
<entry key="ferrol">21010</entry>
<entry key="santander">14223</entry>
<entry key="toledo">92102</entry>
<entry key="caceres">35400</entry>
<entry key="cáceres">35400</entry>
<entry key="lugo">20309</entry>
<entry key="friburgo">85410</entry>
<entry key="la coruña">31412</entry>
<entry key="utiel">03213</entry>
<entry key="zaragoza">ZARAG</entry>
<entry key="burgos">11014 </entry>
<entry key="figueres">04307</entry>
<entry key="salamanca">SALAM</entry>
<entry key="elda-petrer">60905</entry>
<entry key="alicante">60911</entry>
<entry key="oviedo">15211</entry>
<entry key="mérida">37500</entry>
<entry key="lorca">06006</entry>
<entry key="bern">85031</entry>
<entry key="puente genil">PTE G</entry>
<entry key="milano">83111</entry>
<entry key="beira">94401</entry>
<entry key="abrantes">94707</entry>
<entry key="barcelona">BARCE </entry>
<entry key="almería">56312</entry>
<entry key="valencia">VALEN</entry>
<entry key="castello">65300</entry>
<entry key="figueres vilafant">04307</entry>
<entry key="gandia">69110</entry>
<entry key="requena">03213</entry>
<entry key="badajoz">37606 </entry>
<entry key="cadiz">51405</entry>
<entry key="castellon">65300</entry>
<entry key="zurich">85200</entry>
<entry key="jaén">03100</entry>
<entry key="orleans-les aubrais">87004</entry>
<entry key="valladolid">10600</entry>
<entry key="blois">87546 </entry>
<entry key="lleida">78400</entry>
<entry key="gijon">GIJON</entry>
<entry key="algeciras">55020 </entry>
<entry key="vigo">Guixar=22308</entry>
<entry key="logroño">81100</entry>
<entry key="monzon-rio cinca">78301</entry>
<entry key="merida">37500</entry>
<entry key="paris austerlitz">87011</entry>
<entry key="reus">71400</entry>
<entry key="fribourg">85410</entry>
<entry key="san sebastián">11511</entry>
<entry key="tudela de navarra">81202</entry>
<entry key="milán">83111</entry>
<entry key="palencia">14100</entry>
<entry key="málaga maría zambrano">54413</entry>
<entry key="coruña">31412</entry>
<entry key="bilbao-abando">13200 </entry>
<entry key="lorca-sutullena">06006</entry>
<entry key="paris">87011</entry>
<entry key="madrid">MADRI</entry>
<entry key="monzón-río cinca">78301</entry>
<entry key="guadalajara">GUADA</entry>
<entry key="xàtiva">64100</entry>
<entry key="murcia">61200</entry>
<entry key="navalmoral de la mata">35206</entry>
<entry key="torino">83002</entry>
<entry key="segovia">SEGOV</entry>
<entry key="geneve">85444</entry>
<entry key="parís austerlitz">87011</entry>
<entry key="gandía">69110</entry>
<entry key="bobadilla">54400 </entry>
<entry key="orleans">87004</entry>
<entry key="leon">15100</entry>
<entry key="castellón">65300</entry>
<entry key="puerto santa maria">51400</entry>
<entry key="alcázar de san juan">60400 </entry>
<entry key="zamora">30200</entry>
<entry key="santiago de compostela">31400</entry>
<entry key="antequera">ANTEQ</entry>
<entry key="montpellier">87173</entry>
<entry key="donostia">11511</entry>
<entry key="pamplona">80100</entry>
<entry key="villena">60902</entry>
<entry key="orpesa">65304</entry>
<entry key="novara">83008</entry>
<entry key="avila">10400 </entry>
<entry key="iruña">80100</entry>
<entry key="granada">05000</entry>
<entry key="gijón">GIJON</entry>
<entry key="ourense">22100</entry>
<entry key="turin">83002</entry>
<entry key="soria">82100</entry>
<entry key="puertollano">37300</entry>
<entry key="oropesa">65304</entry>
<entry key="huesca">74200</entry>
<entry key="san sebastian">11511</entry>
<entry key="hendaya">11602</entry>
<entry key="milan">83111</entry>
<entry key="ponferrada">20200</entry>
<entry key="huelva">43019</entry>
<entry key="portbou">79315</entry>
<entry key="alcazar de san juan">60400 </entry>
<entry key="parís">87011</entry>
<entry key="malaga maria zambrano">54413</entry>
<entry key="vitoria">11208</entry>
<entry key="sahagun">15009</entry>
<entry key="miranda de ebro">11200</entry>
<entry key="irun">11600</entry>
<entry key="medina del campo">10500</entry>
<entry key="calatayud">70600</entry>
<entry key="girona">79300</entry>
<entry key="sevilla">51003</entry>
<entry key="jerez de la frontera">51300</entry>
<entry key="limoges">87034</entry>
<entry key="castelló">65300</entry>
</properties>

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -0,0 +1,8 @@
// Agent userAgent in project Web40
/* Initial beliefs and rules */
/* Initial goals */
/* Plans */

@ -0,0 +1,40 @@
// Agent nluAgent in project Web40SOJason
/* Initial beliefs and rules */
/* Initial goals */
/* Plans */
@in_msg
+user_msg(Msg, Query) : true
<- sendNLU(Query, Msg);
-user_msg(Msg, Query). // clear the memory
/* Tell the user agent what the NLU system understood */
+price(Terms, Price)[query(Query), domain(travel)] : true
<- .send(userAgent, tell, price(Terms, Price)[query(Query)], domain(travel));
.print("Percibido: price ",Terms, " ", Price ).
+date(Terms, Day, Month, Year)[query(Query), domain(travel)] : true
<- .send(userAgent, tell, date(Terms, Day, Month, Year)[query(Query), domain(travel)]);
.print("Percibido: date ",Terms, " ", Day, " ", Month, " ", Year).
+time(Terms, Hours, Minutes)[query(Query), domain(travel)] : true
<- .send(userAgent, tell, time(Terms, Hours, Minutes)[query(Query), domain(travel)]);
.print("Percibido: time ",Terms, " ", Hours, " ", Minutes).
+location(Terms, Place)[query(Query), domain(travel)] : true
<- .send(userAgent, tell, location(Terms, Place)[query(Query), domain(travel)]);
.print("Percibido: location ",Terms, " ", Place).
+type(Terms)[query(Query), domain(travel)] : true
<- .send(userAgent, tell, type(Terms)[query(Query), domain(travel)]);
.print("Percibido: type ",Terms).
@sendFindTravel
+done[query(Query), domain(Domain)] : true
<- .wait(1000); // wait until all other information is sent
.print("Percepcion completada");
.send(userAgent, achieve, find(Domain, Query)).

@ -0,0 +1,60 @@
// Agent travelAgent in project Web40
/* Initial beliefs and rules */
canFindTravel(Query)
:- location(from,_)[query(Query)] &
location(to,_)[query(Query)] &
date(departure,_,_,_)[query(Query)].
/* Initial goals */
contact(userAgent).
my_service(travel).
my_service(train).
/************** Plans *****************/
/* Introduce myself to the user agent */
@introduce_myself
+my_service(Domain)
: contact(Agent) & .my_name(Me)
<- .send(Agent, tell, service(Me, Domain)).
@introduction_rety
+my_service(Domain) : not contact(Agent)
<- -+my_service(Domain).
/* Find travel plans */
@findTravel1
+!find(travel, Query) : not canFindTravel(Query) & not delay(Query)
<- .print("Not enought data. Lets wait some time");
.wait(3000);
+delay(Query);
!find(travel, Query).
@findTravel2
+!find(travel, Query) : not canFindTravel(Query) & delay(Query)
<- -delay(Query);
.print("Not enought data. Lets ask!").
@findTravel3
+!find(travel, Query) : canFindTravel(Query)
<- ?location(to, To);
?location(from, From);
?date(departure, Day, Month, Year);
findTravel(From, To, Day, Month, Year);
.print("ok").
@findTravelFailureRety
-!find(travel, Query) : not error(Msg, Query)<- !findTravel(Query).
@findTravelFailureError
-!find(travel, Query) : error(Msg, Query)
<- .print("Problema al encontrar viajes:", Msg);
!findTravel(Query).
/* log results */
@log_the_journey
+journey(From, To, Departure, Arrival, Fares) : true
<- .print("Travel found: From ", From,"<", Departure, "> to ", To, "<", Arrival, "> for ", Fares).

@ -0,0 +1,56 @@
// Agent userAgent in project Web40
/* Initial beliefs and rules */
new_query(Query) :- .random(R) & Query = (1000*R)+1.
!start.
/* Initial goals */
/******* Plans ***************************/
/* Wait for service introduction (temporal plan, to erase) */
+!start : true
<- .wait(1000);
+user_msg("I want to travel from Madrid to Cuenca in the morning that costs no more than 200€ and dinner in a romantic restaurant").
/* Ask the nlu agent */
+user_msg(Msg) : new_query(Query)
<- .send(nluAgent, tell, user_msg(Msg, Query) ).
/* Log the received data */
+price(Terms, Price)[query(Query), domain(Domain)] : true
<- .print("Percibido: price ",Terms, " ", Price );
+data(price(Terms), Query, Domain).
+date(Terms, Day, Month, Year)[query(Query), domain(Domain)] : true
<- .print("Percibido: date ",Terms, " ", Day, " ", Month, " ", Year);
+data(date(Terms, Day, Month, Year), Query, Domain).
+time(Terms, Hours, Minutes)[query(Query), domain(Domain)] : true
<- .print("Percibido: time ",Terms, " ", Hours, " ", Minutes);
+data(time(Terms, Hours, Minutes), Query, Domain).
+location(Terms, Place)[query(Query), domain(Domain)] : true
<- .print("Percibido: location ",Terms, " ", Place);
+data(location(Terms, Place), Query, Domain).
+type(Terms)[query(Query), domain(Domain)] : true
<- .print("Percibido: type ",Terms).
/* find travel */
/*@find_travel
+!find(travel, Query) : true
<- .println("lets find travel ", Query);
.findall(Name, service(Name, travel), List);
.send(List, achieve, find(travel, Query)).
*/
@do_search
+!find(Domain, Query) : true
<- .print("Perform find ", Domain, " ", Query);
.findall(Name, service(Name, Domain), AgList);
.findall(Atom[query(Query)], data(Atom, Query, Domain), DataList);
.send(AgList, tell, DataList);
.send(AgList, achieve, find(Domain, Query)).

@ -0,0 +1,87 @@
/**
*
*/
package es.upm.dit.gsi.jason.utils;
import jason.asSyntax.Literal;
import java.util.Collection;
import java.util.LinkedList;
/**
*
* Project: Web40SOJason
* Package: es.upm.dit.gsi.jason.utils
* Class: CollectionUtils
*
* @author Miguel Coronado (miguelcb@dit.upm.es)
* @version Mar 9, 2012
*
*/
public abstract class CollectionUtils {
/**
* This wraps a Literal in a collection
* @param literal The literal
* @return Collection containing the literal given
*/
public static Collection<Literal> wrapList(Literal literal) {
Collection<Literal> res = new LinkedList<Literal>();
res.add(literal);
return res;
}
/**
* This wraps a Literal in a collection
* @param literal The string that represents a literal
* @return Collection containing the literal given
*/
public static Collection<Literal> wrapList(String literal) {
Collection<Literal> res = new LinkedList<Literal>();
res.add(Literal.parseLiteral(literal));
return res;
}
/**
* This
* @param collection
* @return
*/
public static String[] toStringArray (Collection<? extends Object> collection){
String[] strArray = new String[collection.size()];
int index = 0;
for(Object obj : collection){
if(obj == null) {
strArray[index] = "null";
}
else {
strArray[index] = obj.toString();
}
index++;
}
return strArray;
}
/**
*
* @param items
* @return
*/
public static String[] toStringArray (Object[] items){
String[] strArray = new String[items.length];
for(int index = 0; index < items.length; index++){
Object obj = items[index];
if(obj == null){
strArray[index] = "null";
}
else{
strArray[index] = items[index].toString();
}
}
return strArray;
}
}

@ -0,0 +1,83 @@
package es.upm.dit.gsi.jason.utils;
/**
* This Utils class is used to validate string according to the Jason atom
* notation criteria, and transform an invalid notation into a valid one
* and vice versa.
*
* This is useful in some context where the agents need to interact with an
* uncontrollable environment such as the Web.
*
* In Jason notation, white-spaces are not allowed, neither, words that starts
* with capital letter.
*
* @author gsi.dit.upm.es
*
*/
public class NotationUtils {
/**
* @param toCheck
* @return
*/
public static boolean isValidAtom (String toCheck) {
String lowerCase = toCheck.toLowerCase();
return !toCheck.contains(" ") && !toCheck.contains(",") && toCheck.equals(lowerCase);
}
/**
*
* @param toCheck
* @return
*/
public static boolean isCompactable (String toCheck) {
return true;
}
/**
*
* @param str
* @return
*/
public static String compact(String str) {
if (isValidAtom (str)) {return str;}
if (!isCompactable(str)) {return null;}
str = str.replace("_", "___");
str = str.replace(" ", "_");
str = str.replace("ñ", "n");
return str.toLowerCase();
}
/**
*
* @param str
* @return
*/
public static String uncompact(String str) {
str = str.replace("___", "#");
str = str.replace("_", " ");
str = str.replace("#", " ");
return str;
}
/**
* <p>This removes the quotation mark from the string given. If that
* string has no quotation marks it returned trimmed.</p>
*
* <p>The quotation marks are only removed from the beginning and the
* end of the string, so any quotation mark inserted in the middle of
* the string will be kept.</p>
*
* @return the string without the quotation marks
*/
public static String removeQuotation (String str) {
String message = str.trim();
if(message.startsWith("\"")) message = message.substring(1);
if(message.endsWith("\"")) message = message.substring(0, message.length()-1);
return message;
}
}

@ -0,0 +1,94 @@
package es.upm.dit.gsi.sojason;
// Environment code for project Web40SOJason
import jason.asSyntax.Literal;
import jason.asSyntax.Structure;
import jason.asSyntax.Term;
import jason.environment.Environment;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
/**
* This represents a Software Oriented Environment.
* It overrides the getPercepts method so every time the agent perceives
* it checks the model to update the percepts for the particular agent.
*
* Project: Web40SOJason
* Package: es.upm.dit.gsi.sojason
* Class: SOEnvironment
*
* @author Miguel Coronado (miguelcb@dit.upm.es)
* @version Mar 9, 2012
*
*/
public class SOEnvironment extends Environment {
/** The logger */
private Logger logger = Logger.getLogger("Web40SOJason." + SOEnvironment.class.getName());
/** The model */
public Web40Model model;
/** Called before the MAS execution with the args informed in .mas2j */
@Override
public void init(String[] args) {
super.init(args);
try {
this.model = new Web40Model();
} catch (IOException e) {
addPercept(Literal.parseLiteral("error(\"Could not inatantiate the model\")"));
e.printStackTrace();
}
}
@Override
public boolean executeAction(String agName, Structure action) {
logger.info("executing: " + action + " (" + agName + ")");
// select the external action
boolean result = false;
String functor = action.getFunctor();
List<Term> terms = action.getTerms();
if (functor.equals("sendNLU")) {
result = this.model.sendNlu(agName, terms);
}
else if (functor.equals("findTravel")) {
result = this.model.findTravel(agName, terms);
return true;
}
else {
logger.info(action + " was not implemented.");
}
return result;
}
/** Called before the end of MAS execution */
@Override
public void stop() {
super.stop();
}
/** */
@Override
public List<Literal> getPercepts(String agName) {
updatePerceptsForAg(agName);
return super.getPercepts(agName);
}
/**
*
* @param agName
*/
public void updatePerceptsForAg (String agName) {
clearPercepts(agName);
Collection<Literal> literals = model.getDataFromInbox(agName);
for(Literal literal : literals){
addPercept(agName, literal);
}
}
}

@ -0,0 +1,106 @@
/**
*
*/
package es.upm.dit.gsi.sojason;
import jason.asSyntax.Literal;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
*
*
* Project: Web40SOJason
* Package: es.upm.dit.gsi.sojason
* Class: SOModel
*
* @author Miguel Coronado (miguelcb@dit.upm.es)
* @version Mar 9, 2012
*
*/
abstract public class SOModel {
/**
* This contains the data that will be
*/
private Map<String, Set<Literal>> serviceDataInbox;
/**
* Constructor. Just initializes attributes.
*/
public SOModel(){
this.serviceDataInbox = Collections.synchronizedMap(new HashMap<String, Set<Literal>>());
}
/**
* <p>This puts data into the <code>serviceDataInbox</code> for a
* particular agent. The data loaded will be appended into the already
* existing data if any.</p>
*
* <p>The data from the <code>serviceDataInbox</code> is removed as
* described in the documentation of {@link #getDataFromInbox(String)}</p>
*
* @param agName The name of the agent.
* @param serviceData The service-data.
*/
public void setDataInbox (String agName, Collection<Literal> serviceData){
synchronized (serviceDataInbox) {
if (!this.serviceDataInbox.containsKey(agName)) {
Set<Literal> set = new HashSet<Literal>();
set.addAll(serviceData); // create a set and add all the collection
this.serviceDataInbox.put(agName, set);
return;
}
// There is no data in the inbox for the agent given
Set<Literal> set = this.serviceDataInbox.get(agName);
set.addAll(serviceData);
this.serviceDataInbox.put(agName, set);
}
}
/**
* <p>This provides a different way to call the method
* {@linkplain #setDataInbox(String, Collection)} with a single literal
* instead of a collection of literals.</p>
*
* @param agName the name of the agent.
* @param literal the literal.
*/
public void setDataInbox (String agName, Literal literal) {
Set <Literal> set = new HashSet<Literal>();
set.add(literal);
setDataInbox(agName, set);
}
/**
* <p>This gets from the <code>serviceDataInbox</code> the data stored for
* the agent given. It will remove the data from the inbox, so two consequent
* invocations of this method will return different results, actually, if no
* new data is put, the second invocation will return no data.</p>
*
* <p>So, it is important to point out this method empties the
* <code>serviceDataInbox</code>.</p>
*
* <p>This method never returns null to avoid null pointer</p>
*
* @param agName the name of the agent who data will be retrieved from
* the inbox
* @return The data retrieved
*/
public Collection<Literal> getDataFromInbox (String agName) {
if (!this.serviceDataInbox.containsKey(agName)){
return new HashSet<Literal>();
}
// return this.serviceDataInbox.get(agName);
return this.serviceDataInbox.remove(agName);
}
}

@ -0,0 +1,98 @@
package es.upm.dit.gsi.sojason;
import jason.asSyntax.Literal;
import jason.asSyntax.Term;
import java.io.IOException;
import java.util.Collection;
import java.util.logging.Logger;
import es.upm.dit.gsi.jason.utils.CollectionUtils;
import es.upm.dit.gsi.sojason.services.nlu.NLUConnector;
import es.upm.dit.gsi.sojason.services.travel.RenfeScrapper;
/**
*
*
* Project: Web40
* Package: es.upm.dit.gsi.qa
* Class: Web40Model
*
* @author Miguel Coronado (miguelcb@dit.upm.es)
* @version Feb 29, 2012
*
*/
public class Web40Model extends SOModel{
/** */
public final static String NLU_SERVICE_URL = "http://46.4.52.82:3333/nlu";
/** */
private NLUConnector nluConnector;
/** */
private RenfeScrapper renfeScrapper;
/** */
private Logger logger = Logger.getLogger("Web40SOJason." + Web40Model.class.getName());
/** Constructor
* @throws IOException */
public Web40Model () throws IOException {
super();
this.nluConnector = new NLUConnector(NLU_SERVICE_URL);
this.renfeScrapper = new RenfeScrapper();
}
/**
* This calls the NLU service
*
* Internally this modifies the model so it reports the agent
*
* @param agName the name of the agent that will be reported with the
* results of the call.
* @param terms The parameters
* @return
*/
public boolean sendNlu (String agName, Collection<Term> params) {
logger.info("Entering sendNLU...");
try{
String[] strParams = CollectionUtils.toStringArray(params);
Collection<Literal> serviceData = nluConnector.call(strParams);
if(serviceData == null){
logger.info("Could not complete action sendNLU: no service data found");
return false;
}
// put data into mailbox
this.setDataInbox(agName, serviceData);
}
catch (Exception e){
logger.info("Could not complete action sendNLU:" + e.getMessage());
return false;
}
logger.info("NLU call completed successfully");
return true;
}
/**
*
* @param agName
* @param terms
* @return
*/
public boolean findTravel (String agName, Collection<Term> params) {
try{
String[] strParams = CollectionUtils.toStringArray(params);
Collection<Literal> serviceData = renfeScrapper.call(strParams);
if(serviceData == null){ return false; }
// put data into mailbox
this.setDataInbox(agName, serviceData);
}
catch (Exception e){ return false; }
return true;
}
}

@ -0,0 +1,38 @@
/**
*
*/
package es.upm.dit.gsi.sojason.beans;
import jason.asSyntax.Literal;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import es.upm.dit.gsi.jason.utils.NotationUtils;
/**
* @author miguel
*
*/
public class ErrorReport extends HashMap<String, String> implements Perceptable {
/**
*
*/
private static final long serialVersionUID = 1L;
/* (non-Javadoc)
* @see es.upm.dit.gsi.qa.beans.Perceptable#toPercepts()
*/
public List<Literal> toPercepts() {
List<Literal> res = new LinkedList<Literal>();
for (String key : this.keySet()){
if(!NotationUtils.isCompactable(key)) continue;
res.add(Literal.parseLiteral("error(" + NotationUtils.compact(key) + ", \"" + get(key) + "\")"));
}
return res;
}
}

@ -0,0 +1,217 @@
/**
*
*/
package es.upm.dit.gsi.sojason.beans;
import jason.asSyntax.Literal;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import es.upm.dit.gsi.jason.utils.NotationUtils;
/**
* @author miguel
*
*/
public class Journey implements Perceptable{
/** The departure time of the journey */
private String departureTime;
/** The arrival time of the journey */
private String arrivalTime;
/**
* The duration of the journey. This is not simply the difference of the
* departure and arrival time because of timezone considerations.
*/
private String duration;
/** The origin */
private String origin;
/** The destination */
private String destination;
/** The fee map that contains the different available fee */
private Map<String, String> fares;
/**
* @return the departureTime
*/
public String getDepartureTime() {
return departureTime;
}
/**
* @param departureTime the departureTime to set
*/
public void setDepartureTime(String departureTime) {
this.departureTime = departureTime;
}
/**
* @return the arrivalTime
*/
public String getArrivalTime() {
return arrivalTime;
}
/**
* @param arrivalTime the arrivalTime to set
*/
public void setArrivalTime(String arrivalTime) {
this.arrivalTime = arrivalTime;
}
/**
* @return the duration
*/
public String getDuration() {
return duration;
}
/**
* @param duration the duration to set
*/
public void setDuration(String duration) {
this.duration = duration;
}
/**
* @return the oringin
*/
public String getOringin() {
return origin;
}
/**
* @param oringin the oringin to set
*/
public void setOrigin(String origin) {
this.origin = origin;
}
/**
* @return the destination
*/
public String getDestination() {
return destination;
}
/**
* @param destination the destination to set
*/
public void setDestination(String destination) {
this.destination = destination;
}
/**
* @return the fares
*/
public Map<String, String> getFares() {
return fares;
}
/**
* @param fares the fares to set
*/
public void setFares(Map<String, String> fares) {
this.fares = fares;
}
/** Textual representation of the journey. Use for debuging purposes inly.*/
public String toString() {
String toString = "From: ";
toString = toString.concat(origin);
toString = toString.concat(" (");
toString = toString.concat(departureTime);
toString = toString.concat(") to: ");
toString = toString.concat(destination);
toString = toString.concat(" (");
toString = toString.concat(arrivalTime);
toString = toString.concat(") in ");
toString = toString.concat(duration);
toString = toString.concat(" for ");
if(fares != null)
toString = toString.concat(fares.toString());
else
toString += null;
return toString;
}
/**
* journey(madrid, ciudad_real, 10.15, 11.5, [fare(turista, 22.5), fare(preferente, 35)]
* journey(madrid, ciudad_real, time(10,15), time(11,5), [fare(turista, 22.5), fare(preferente, 35)]
*
* @return
*/
public List<Literal> toPercepts() {
// if (this.fares.size() == 0){ return null; }
//
// String percept = "journey(";
// percept = percept.concat(this.origin);
// percept = percept.concat(", ");
// percept = percept.concat(this.destination);
// percept = percept.concat(", ");
// percept = percept.concat(this.departureTime);
// percept = percept.concat(", ");
// percept = percept.concat(this.arrivalTime);
//
// percept = percept.concat(", [");
// for(String fareName : fares.keySet()) {
// percept = percept.concat("fare(");
// percept = percept.concat(fareName);
// percept = percept.concat(", ");
// percept = percept.concat(fares.get(fareName));
// percept = percept.concat("), ");
// }
// percept = percept.substring(0, percept.lastIndexOf(","));
// percept = percept.concat("])");
//
// LinkedList<Literal> ret = new LinkedList<Literal>();
// ret.add(Literal.parseLiteral(percept));
//
// return ret;
if (this.fares.size() == 0){ return null; }
String percept = "journey(";
percept = percept.concat(NotationUtils.compact(this.origin));
percept = percept.concat(", ");
percept = percept.concat(NotationUtils.compact(this.destination));
percept = percept.concat(", time(");
String digits[] = this.departureTime.split("[\\x2E\\x3A]"); // [.:]
percept = percept.concat(digits[0]);
percept = percept.concat(", ");
percept = percept.concat(digits[1]);
percept = percept.concat("), time(");
digits = this.arrivalTime.split("[\\x2E\\x3A]"); // [.:]
percept = percept.concat(digits[0]);
percept = percept.concat(", ");
percept = percept.concat(digits[1]);
percept = percept.concat("), [");
for(String fareName : fares.keySet()) {
percept = percept.concat("fare(");
percept = percept.concat(NotationUtils.compact(fareName));
percept = percept.concat(", ");
percept = percept.concat(fares.get(fareName));
percept = percept.concat("), ");
}
percept = percept.substring(0, percept.lastIndexOf(","));
percept = percept.concat("])");
LinkedList<Literal> ret = new LinkedList<Literal>();
ret.add(Literal.parseLiteral(percept));
return ret;
}
}

@ -0,0 +1,347 @@
package es.upm.dit.gsi.sojason.beans;
import jason.asSyntax.Literal;
import java.util.LinkedList;
import java.util.List;
import es.upm.dit.gsi.jason.utils.NotationUtils;
import es.upm.dit.gsi.sojason.services.nlu.NLUModel;
public class NLUTravel implements Perceptable {
/** */
public final static String TRAVEL_DOMAIN = "travel";
/** The departure date. */
private String departureDate = null;
/** The return date. It may be null. */
private String returnDate = null;
/** The maximum price the user is willing to pay */
private double priceMin = -1;
/** The minimum price */
private double priceMax = -1;
/** The currency */
private String currency = null;
/** The departure location */
private String locationFrom = null;
/** The destination location */
private String locationTo = null;
/** The preferred departure Time */
private String departureTime = null;
/** the preferred return Time*/
private String returnTime = null;
/** the number of people is traveling */
private int number = 1;
/** */
private TravelType type = null;
/** */
private boolean scales = false;
/** The unique id for the dialog. It is used to group dialog entries */
private String queryId = null;
/**
* @return the departureDate
*/
public String getDepartureDate() {
return departureDate;
}
/**
* @param departureDate the departureDate to set
*/
public void setDepartureDate(String departureDate) {
this.departureDate = departureDate;
}
/**
* @return the returnDate
*/
public String getReturnDate() {
return returnDate;
}
/**
* @param returnDate the returnDate to set
*/
public void setReturnDate(String returnDate) {
this.returnDate = returnDate;
}
/**
* @return the priceMin
*/
public double getPriceMin() {
return priceMin;
}
/**
* @param priceMin the priceMin to set
*/
public void setPriceMin(double priceMin) {
this.priceMin = priceMin;
}
/**
* @param priceMax the priceMax to set
*/
public void setPriceMin(String priceMin) {
if (priceMin == null){ return; }
try{
this.priceMin = Double.parseDouble(priceMin);
}
catch (NumberFormatException nfe){
// Do nothing
}
}
/**
* @return the priceMax
*/
public double getPriceMax() {
return priceMax;
}
/**
* @param priceMax the priceMax to set
*/
public void setPriceMax(double priceMax) {
this.priceMax = priceMax;
}
/**
* @param priceMax the priceMax to set
*/
public void setPriceMax(String priceMax) {
if (priceMax == null){ return; }
try{
this.priceMax = Double.parseDouble(priceMax);
}
catch (NumberFormatException nfe){
// Do nothing
}
}
/**
* @return the currency
*/
public String getCurrency() {
return currency;
}
/**
* @param currency the currency to set
*/
public void setCurrency(String currency) {
this.currency = currency;
}
/**
* @return the locationFrom
*/
public String getLocationFrom() {
return locationFrom;
}
/**
* @param locationFrom the locationFrom to set
*/
public void setLocationFrom(String locationFrom) {
this.locationFrom = locationFrom;
}
/**
* @return the locationTo
*/
public String getLocationTo() {
return locationTo;
}
/**
* @param locationTo the locationTo to set
*/
public void setLocationTo(String locationTo) {
this.locationTo = locationTo;
}
/**
* @return the departureTime
*/
public String getDepartureTime() {
return departureTime;
}
/**
* @param departureTime the departureTime to set
*/
public void setDepartureTime(String departureTime) {
this.departureTime = departureTime;
}
/**
* @return the returnReturn
*/
public String getReturnTime() {
return returnTime;
}
/**
* @param returnReturn the returnReturn to set
*/
public void setReturnTime(String returnTime) {
this.returnTime = returnTime;
}
/**
* @return the type
*/
public TravelType getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(TravelType type) {
this.type = type;
}
/**
* @return the scales
*/
public boolean isScales() {
return scales;
}
/**
* @param scales the scales to set
*/
public void setScales(boolean scales) {
this.scales = scales;
}
/**
* @return the number
*/
public int getNumber() {
return number;
}
/**
* @param number the number to set
*/
public void setNumber(int number) {
this.number = number;
}
public void setNumber(String number){
if(number == null){ return; }
try{
this.number = Integer.parseInt(number);
}
catch(NumberFormatException nfe){
// Ok
}
}
/**
* @return the queryId
*/
public String getQueryId() {
return queryId;
}
/**
* @param queryId the queryId to set
*/
public void setQueryId(String queryId) {
this.queryId = queryId;
}
public String toString() {
String toString = queryId + number;
toString += "ticket(s) from: ";
toString += locationFrom;
toString += " to: ";
toString += locationTo;
toString += " the day ";
toString += departureDate;
toString += " at ";
toString += departureTime;
toString += " returning the day ";
toString += returnTime;
toString += " at ";
toString += returnTime;
toString += " for ";
toString += priceMax + "->" + priceMin;
toString += " ";
toString += currency;
return toString;
}
/**
*
*/
public List<Literal> toPercepts() {
List<Literal> list = new LinkedList<Literal>();
if(departureDate != null){
list.add(NLUModel.getLiteralDateDeparture(queryId, TRAVEL_DOMAIN, "03", "04", "2012"));
}
if(returnDate != null){
list.add(NLUModel.getLiteralDateReturn(queryId, TRAVEL_DOMAIN, "03", "04", "2012"));
}
if(departureTime != null){
list.add(NLUModel.getLiteralTimeDeparture(queryId, TRAVEL_DOMAIN, "09", "00"));
}
if(returnTime != null){
list.add(NLUModel.getLiteralTimeReturn(queryId, TRAVEL_DOMAIN, "09", "00"));
}
if(priceMax >= 0){
list.add(NLUModel.getLiteralPriceMax(queryId, TRAVEL_DOMAIN, priceMax));
}
if(priceMin >= 0){
list.add(NLUModel.getLiteralPriceMin(queryId, TRAVEL_DOMAIN, priceMin));
}
if(currency != null){
list.add(NLUModel.getLiteralCurrency(queryId, TRAVEL_DOMAIN, NotationUtils.compact(currency)));
}
if(locationFrom != null){
list.add(NLUModel.getLiteralLocationFrom(queryId, TRAVEL_DOMAIN, NotationUtils.compact(locationFrom)));
}
if(locationTo != null){
list.add(NLUModel.getLiteralLocationTo(queryId, TRAVEL_DOMAIN, NotationUtils.compact(locationTo)));
}
if(scales){
list.add(Literal.parseLiteral("scales[query(" + queryId + "), domain(" + TRAVEL_DOMAIN + ")]"));
}
else{
list.add(Literal.parseLiteral("~scales[query(" + queryId + "), domain(" + TRAVEL_DOMAIN + ")]"));
}
list.add(Literal.parseLiteral("done[query(" + queryId + "), domain(" + TRAVEL_DOMAIN + ")]"));
return list;
}
}

@ -0,0 +1,14 @@
package es.upm.dit.gsi.sojason.beans;
import jason.asSyntax.Literal;
import java.util.List;
/**
* @author miguel
*
*/
public interface Perceptable {
public List<Literal> toPercepts();
}

@ -0,0 +1,11 @@
package es.upm.dit.gsi.sojason.beans;
/**
* This defines the different means of transport.
* @author gsi.dit.upm.es
*/
public enum TravelType {
flight,
train,
coach
}

@ -0,0 +1,57 @@
/**
*
*/
package es.upm.dit.gsi.sojason.services;
import jason.asSyntax.Literal;
import java.util.Collection;
/**
* This interface defines a standard way to connect to a web service in
* the definition of an external action in Jason.
*
* Project: Web40SOJason
* Package: es.upm.dit.gsi.sojason.services
* Class: WebServiceConnector
*
* @author Miguel Coronado (miguelcb@dit.upm.es)
* @version Feb 27, 2012
*
*/
public interface WebServiceConnector {
/**
* This calls the service including in the request the parameters given.
* The URL of the service, the method to use and any other particularity
* of the transaction to connect to the service must be determined in the
* implementation of the method.
*
* @param params The list of parameters to include in the service
* request. Due to this is not a <code>Dictionary</code>
* the order of the parameters it is important and will be
* determined by the implementation of the extendee
* classes.
*/
public Collection<Literal> call(String... params);
/**
* This validates the set of parameters provided. Typically, this method
* should use some regex exprsesions to check whether a parameter is valid
* or not, due to the nature of the parameter cannot be checked because of
* the type of the parameters has been unified to String.
*
* @param params The list of parameters to validate
*/
public boolean validateParams(String... params);
/**
* This generates a set of error <code>Literal</code>s that describes the
* errors committed when trying to call the given service with the set of
* parameters given.
*
* @param params The list of parameters
*/
// public Set<Literal> checkForErrors(String... params);
}

@ -0,0 +1,163 @@
package es.upm.dit.gsi.sojason.services.nlu;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_CURRENCY_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_DATES_DEPART_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_DATES_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_DATES_RETURN_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_DOMAINS_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_FROM_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_TO_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_LOCATIONS_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_MAX_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_MIN_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_NUMBER_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_PRICE_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_TIME_DEPART_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_TIME_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_TIME_RETURN_NODENAME;
import static es.upm.dit.gsi.sojason.services.nlu.NLUModel.JSON_TRAVEL_NODENAME;
import jason.asSyntax.Literal;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Collection;
import java.util.logging.Logger;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import es.upm.dit.gsi.jason.utils.NotationUtils;
import es.upm.dit.gsi.sojason.Web40Model;
import es.upm.dit.gsi.sojason.beans.NLUTravel;
import es.upm.dit.gsi.sojason.services.WebServiceConnector;
/**
* Project: Web40SOJason
* Package: es.upm.dit.gsi.sojason.services.nlu
* Class: NLUConnector
*
* @author Miguel Coronado (miguelcb@dit.upm.es)
* @version Feb 27, 2012
*
*/
public class NLUConnector implements WebServiceConnector{
/** The url of the service */
private String serviceUrl;
/** */
private Logger logger = Logger.getLogger("Web40SOJason." + NLUConnector.class.getName());
/** Constructor */
public NLUConnector(String serviceUrl) {
this.serviceUrl = serviceUrl;
}
/**
*
*/
public Collection<Literal> call(String... params) {
/* Are parameters correct */
if (!validateParams(params)){
logger.info("Parameters are not valid:" + Arrays.toString(params));
return null;
}
try {
// Prepare the request
String urlRequest = prepareRequest(params[0], params[1]);
URL url = new URL(urlRequest);
URLConnection connection = url.openConnection();
connection.connect();
// Parse the data received (using Jackson lib)
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readValue(connection.getInputStream(), JsonNode.class); // src can be a File, URL, InputStream etc
JsonNode travelNode = rootNode.with(JSON_DOMAINS_NODENAME).get(JSON_TRAVEL_NODENAME);
NLUTravel travel = new NLUTravel();
travel.setDepartureDate(travelNode.with(JSON_DATES_NODENAME).get(JSON_DATES_DEPART_NODENAME).getTextValue());
travel.setReturnDate(travelNode.with(JSON_DATES_NODENAME).get(JSON_DATES_RETURN_NODENAME).getTextValue());
travel.setCurrency(travelNode.with(JSON_PRICE_NODENAME).get(JSON_CURRENCY_NODENAME).getTextValue());
travel.setPriceMax(travelNode.with(JSON_PRICE_NODENAME).get(JSON_MAX_NODENAME).getTextValue());
travel.setPriceMin(travelNode.with(JSON_PRICE_NODENAME).get(JSON_MIN_NODENAME).getTextValue());
travel.setLocationFrom(travelNode.with(JSON_LOCATIONS_NODENAME).get(JSON_FROM_NODENAME).getTextValue());
travel.setLocationTo(travelNode.with(JSON_LOCATIONS_NODENAME).get(JSON_TO_NODENAME).getTextValue());
travel.setNumber(travelNode.get(JSON_NUMBER_NODENAME).getTextValue());
travel.setReturnTime(travelNode.with(JSON_TIME_NODENAME).get(JSON_TIME_RETURN_NODENAME).getTextValue());
travel.setDepartureTime(travelNode.with(JSON_TIME_NODENAME).get(JSON_TIME_DEPART_NODENAME).getTextValue());
travel.setQueryId(params[0]);
// System.out.println(travel);
return travel.toPercepts();
} catch (MalformedURLException e) {
// return CollectionUtils.wrapList("error(malformed_url, \"The given url is not valid\")");
logger.info("MalformedURLException:" + e.getMessage()); return null;
} catch (UnsupportedEncodingException e) {
// return CollectionUtils.wrapList("error(undupported_encodig, \"The encoding given is not supported\")");
logger.info("UnsupportedEncodingException:" + e.getMessage()); return null;
} catch (IOException e) {
// return CollectionUtils.wrapList("error(io_exception, \"Someio exception ocurr\")");
logger.info("IOException:" + e.getMessage()); return null;
}
}
/**
* This generates a String used as http GET request to access the service
* including the parameters given by the user
*
* @param queryid
* @param message
* @return the url service string (utf-8 encoded)
* @throws UnsupportedEncodingException
*/
String prepareRequest(String queryid, String message) throws UnsupportedEncodingException {
String urlRequest = this.serviceUrl;
urlRequest = urlRequest.concat("?text=");
message = NotationUtils.removeQuotation(message);
urlRequest = urlRequest.concat(URLEncoder.encode(message, "utf-8"));
// urlRequest = urlRequest.concat(URLEncoder.encode("&query_id=", "utf-8"));
urlRequest = urlRequest.concat("&query_id=");
urlRequest = urlRequest.concat(URLEncoder.encode(queryid, "utf-8"));
logger.info(urlRequest);
return urlRequest ;
}
/**
* This validates the parameters received. The
* {@link NLUConnector#call(String...)} method expects to receive two
* parameters of the nature and characteristics described below:
*
* <ul>
* <li>The first parameter is que query id. It is an alphanumeric string
* which normally will contain numbers, but other non-digit characters
* are permitted. <b>No alphanumeric values are not allowed</b></li>
* <li></li>
* </ul>
*
*/
public boolean validateParams(String... params) {
if (params.length != 2){
return false;
}
// TODO: check other things
return true;
}
}

@ -0,0 +1,92 @@
package es.upm.dit.gsi.sojason.services.nlu;
import jason.asSyntax.Literal;
/**
*
*
* Project: Web40
* Package: es.upm.dit.gsi.qa.services.nlu
* Class:
*
* @author Miguel Coronado (miguelcb@dit.upm.es)
* @version Feb 28, 2012
*
*/
public class NLUModel {
public final static String JSON_DOMAINS_NODENAME = "domains";
public final static String JSON_TRAVEL_NODENAME = "travel";
public final static String JSON_DATES_NODENAME = "dates";
public final static String JSON_DATES_DEPART_NODENAME = "depart";
public final static String JSON_DATES_RETURN_NODENAME = "return";
public final static String JSON_PRICE_NODENAME = "price";
public final static String JSON_CURRENCY_NODENAME = "currency";
public final static String JSON_MAX_NODENAME = "max";
public final static String JSON_MIN_NODENAME = "min";
public final static String JSON_LOCATIONS_NODENAME = "locations";
public final static String JSON_FROM_NODENAME = "from";
public final static String JSON_TO_NODENAME = "to";
public final static String JSON_NUMBER_NODENAME = "number";
public final static String JSON_TIME_NODENAME = "time";
public final static String JSON_TIME_DEPART_NODENAME = "depart";
public final static String JSON_TIME_RETURN_NODENAME = "return";
public static Literal getLiteralPriceMin (String query, String domain, double price) {
return Literal.parseLiteral("price(min," + price + ")[query("+ query +"),domain("+ domain +")]");
}
public static Literal getLiteralPriceMax (String query, String domain, double price) {
return Literal.parseLiteral("price(max," + price + ")[query("+ query +"),domain("+ domain +")]");
}
public static Literal getLiteralCurrency (String query, String domain, String currency) {
return Literal.parseLiteral("currency(" + currency + ")[query("+ query +"),domain("+ domain +")]");
}
public static Literal getLiteralLocationFrom (String query, String domain, String place) {
return Literal.parseLiteral("location(from," + place + ")[query("+ query +"),domain("+ domain +")]");
}
public static Literal getLiteralLocationTo (String query, String domain, String place) {
return Literal.parseLiteral("location(to," + place + ")[query("+ query +"),domain("+ domain +")]");
}
public static Literal getLiteralDateDeparture (String query, String domain, String day, String month, String year) {
return Literal.parseLiteral("date(departure," + day + "," + month + "," + year + ")[query("+ query +"),domain("+ domain +")]");
}
public static Literal getLiteralDateReturn (String query, String domain, String day, String month, String year) {
return Literal.parseLiteral("date(return," + day + "," + month + "," + year + ")[query("+ query +"),domain("+ domain +")]");
}
public static Literal getLiteralTimeDeparture (String query, String domain, String hour, String min) {
return Literal.parseLiteral("time(departure," + hour + "," + min + ")[query("+ query +"),domain("+ domain +")]");
}
public static Literal getLiteralTimeReturn (String query, String domain, String hour, String min) {
return Literal.parseLiteral("time(return," + hour + "," + min + ")[query("+ query +"),domain("+ domain +")]");
}
public static Literal getLiteralType (String query, String domain, String type) {
return Literal.parseLiteral("type(" + type + ")[query("+ query +"),domain("+ domain +")]");
}
}

@ -0,0 +1,163 @@
package es.upm.dit.gsi.sojason.services.travel;
import jason.asSyntax.Literal;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import es.upm.dit.gsi.sojason.beans.Journey;
import es.upm.dit.gsi.sojason.beans.Perceptable;
import es.upm.dit.gsi.sojason.services.WebServiceConnector;
/**
*
* @author miguel
*
*/
public class RenfeScrapper implements WebServiceConnector {
/**
* It contains all the information about the <i>Renfe</i>
* web service URL convenion.
*/
RenfeServiceConvenion queryGenerator;
/**
* Constructor
* @throws IOException if there is any error while loading the station ids.
*/
public RenfeScrapper() throws IOException {
this.queryGenerator = new RenfeServiceConvenion();
}
public Collection<Literal> call(String... params) {
if(!validateParams(params)){
return null;
}
try {
List<Perceptable> schedule = getSchedule ( params[0].toString(),
params[1].toString(),
params[2].toString(),
params[3].toString(),
params[4].toString());
// prepare response
Collection<Literal> res = new LinkedList<Literal>();
for (Perceptable travel : schedule){
res.addAll(travel.toPercepts());
}
return res;
} catch (IOException e) {
// return CollectionUtils.wrapList("error(io_exception, \"Someio exception ocurr\")");
return null;
}
}
public boolean validateParams(String... params) {
if(params.length != 5){
return false;
}
return true;
}
/**
* TODO: filter by time
*
*
* @param origin
* @param destination
* @param day
* @param month
* @param year
* @return
* @throws IOException
*/
public List<Perceptable> getSchedule (String origin, String destination,
String day, String month, String year) throws IOException {
// The list with the journeys that matches the given criteria
List<Perceptable> retList = new LinkedList<Perceptable>();
// Get the html
String queryUrl = "";
try{
queryUrl = queryGenerator.generateQuery(origin, destination, day, month, year);
}
catch(IllegalArgumentException iae){
retList.add( queryGenerator.reportParamErrors(origin, destination, day, month, year) );
return retList;
}
Document doc = Jsoup.connect(queryUrl).get();
// Get the rows of the schedule table
Elements rows = doc.select("table#row > tbody > tr");
// Each row has the information of a different journey
for (Element row : rows) {
Elements cells = row.getElementsByTag("td");
if(cells.size() > 2){
// get and fill the journey information
Journey journey = new Journey();
journey.setOrigin(origin);
journey.setDestination(destination);
journey.setDepartureTime(cells.get(1).text());
journey.setArrivalTime(cells.get(2).text());
journey.setDuration(cells.get(3).text());
// the fee map for the particular journey
Map<String, String> feeMap = new HashMap<String,String>();
// get the fares
Elements feeRows = cells.get(4).select("tbody tr");
/* According to Renfe's website we select the following sublist */
int fromIndex = 1; // skip the header row
/* They present 2 set of fares (Internet and station) so we skip
* the header rows and divide by 2 to get the amount of fares to
* parse */
int toIndex = 1+(feeRows.size()-2)/2;
for(Element feeRow : feeRows.subList(fromIndex, toIndex)) {
Elements feeCells = feeRow.getElementsByTag("td");
// String feeName = feeCells.get(1).text().toLowerCase().replace(" ", "").replace(":", "").replace("ñ", "n");
String feeName = feeCells.get(1).text().replace(":", "");
String price = feeCells.get(2).text().replace(",", ".");
// Set the fee
feeMap.put(feeName, price);
}
// Set the fares
journey.setFares(feeMap);
retList.add(journey);
}
}
return retList;
}
/**
* try it
* @param args
* @throws IOException
*/
public static void main(String [] args) throws IOException{
RenfeScrapper rs = new RenfeScrapper();
List<Perceptable> list = rs.getSchedule ("Madrid", "ciudad real", "16", "04", "2012");
for(Perceptable journey : list){
System.out.println(journey);
}
}
}

@ -0,0 +1,210 @@
/**
*
*/
package es.upm.dit.gsi.sojason.services.travel;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.regex.Pattern;
import es.upm.dit.gsi.jason.utils.NotationUtils;
import es.upm.dit.gsi.sojason.beans.ErrorReport;
/**
* This class describes the
* @author gsi.dit.upm.es
* @version 1.0
*/
public class RenfeServiceConvenion {
public final static String SERVICE_URL = "http://horarios.renfe.com/HIRRenfeWeb/buscar.do";
public final static String ORIGIN_PARAM = "O";
public final static String DESTINATION_PARAM = "D";
public final static String YEAR_PARAM = "AF";
public final static String MONTH_PARAM = "MF";
public final static String DAY_PARAM = "DF";
public final static String DEFAULT_PATH_TO_CITY_CODES_FILE = "conf/cities.xml";
private Properties cityCodes;
/**
*
* @param cityCodesFile
* @throws IOException
*/
public RenfeServiceConvenion (File cityCodesFile) throws IOException {
this.cityCodes = new Properties();
this.cityCodes.loadFromXML(new FileInputStream(cityCodesFile));
}
/**
* Default constructor
* @throws IOException
*/
public RenfeServiceConvenion () throws IOException {
this(new File(DEFAULT_PATH_TO_CITY_CODES_FILE));
}
/**
*
* @param origin
* @param destination
* @param day
* @param month
* @param year
* @return
*/
public String generateQuery (String origin, String destination,
String day, String month, String year){
origin = NotationUtils.uncompact(origin);
destination = NotationUtils.uncompact(destination);
if(!validateParams(origin, destination, day, month, year)){
throw new IllegalArgumentException();
}
String res = SERVICE_URL;
res = res.concat("?");
res = res.concat(ORIGIN_PARAM);
res = res.concat("=");
res = res.concat(this.cityCodes.getProperty(origin.toLowerCase()));
res = res.concat("&");
res = res.concat(DESTINATION_PARAM);
res = res.concat("=");
res = res.concat(this.cityCodes.getProperty(destination.toLowerCase()));
res = res.concat("&");
res = res.concat(YEAR_PARAM);
res = res.concat("=");
res = res.concat(year);
res = res.concat("&");
res = res.concat(MONTH_PARAM);
res = res.concat("=");
res = res.concat(month);
res = res.concat("&");
res = res.concat(DAY_PARAM);
res = res.concat("=");
res = res.concat(day);
// 'concat' is faster than '+' operator
return res;
}
/**
*
* @param origin
* @param destination
* @param day
* @param month
* @param year
* @throws IllegalArgumentException
*/
protected boolean validateParams(String origin, String destination, String day,
String month, String year) {
if(!Pattern.matches("\\d{4}", year)){
return false;
}
if(!Pattern.matches("\\d{1,2}", month)){
return false;
}
if(!Pattern.matches("\\d{1,2}", day)){
return false;
}
int monthI = Integer.parseInt(month);
int dayI = Integer.parseInt(day);
int monthNumberOfDays[] = {31,29,31,30,31,30,31,31,30,31,30,31};
if(monthI < 1 || monthI > 12){
return false;
}
if(dayI < 1 || dayI > monthNumberOfDays[monthI-1]){
return false;
}
if(origin == null || !this.cityCodes.containsKey(origin.toLowerCase())) {
return false;
}
if(destination == null || !this.cityCodes.containsKey(destination.toLowerCase())) {
return false;
}
return true;
}
protected ErrorReport reportParamErrors (String origin, String destination, String day,
String month, String year) {
ErrorReport errors = new ErrorReport();
if(!Pattern.matches("\\d{4}", year)){
errors.put("year", "invalid format");
}
if(!Pattern.matches("\\d{1,2}", month)){
errors.put("month", "invalid format");
}
if(!Pattern.matches("\\d{1,2}", day)){
errors.put("day", "invalid format");
}
int monthI = Integer.parseInt(month);
int dayI = Integer.parseInt(day);
int monthNumberOfDays[] = {31,29,31,30,31,30,31,31,30,31,30,31};
if(monthI < 1 || monthI > 12){
errors.put("month", "out of range");
monthI = 1; // this lets check the day
}
if(dayI < 1 || dayI > monthNumberOfDays[monthI-1]){
errors.put("day", "out of range");
}
if(origin == null || !this.cityCodes.containsKey(origin.toLowerCase())) {
errors.put("origin", "no such location");
}
if(destination == null || !this.cityCodes.containsKey(destination.toLowerCase())) {
errors.put("destination", "no such location");
}
return errors;
}
/**
*
* @param arga
* @throws IOException
*/
public static void main(String [] arga) throws IOException{
// RenfeServiceConvenion rsc = new RenfeServiceConvenion();
// Properties newProperties = new Properties();
//
// for (Object key : rsc.cityCodes.keySet() ){
// String keyStr = (String)key;
// keyStr = keyStr.toLowerCase();
// newProperties.put(keyStr, rsc.cityCodes.get(key));
// if (keyStr.contains("á") ||
// keyStr.contains("é") ||
// keyStr.contains("í") ||
// keyStr.contains("ó") ||
// keyStr.contains("ú")) {
//
// keyStr = keyStr.replace("á", "a").replace("é", "e").replace("í", "i").replace("ó", "o").replace("ú", "u");
// newProperties.put(keyStr, rsc.cityCodes.get(key));
// }
// }
//
// newProperties.storeToXML(new FileOutputStream(DEFAULT_PATH_TO_CITY_CODES_FILE), "comment");
RenfeServiceConvenion rsc = new RenfeServiceConvenion();
String res = rsc.generateQuery("Madrid", "Ciudad Real", "15", "02", "2012");
System.out.println(res);
}
}
Loading…
Cancel
Save