Skip to content

Commit

Permalink
Merge pull request #1729 from laurentg/scripting
Browse files Browse the repository at this point in the history
OTP Scripting prototype
  • Loading branch information
abyrd committed Feb 3, 2015
2 parents dd40daa + 7477524 commit 8ea5520
Show file tree
Hide file tree
Showing 24 changed files with 1,433 additions and 4 deletions.
22 changes: 22 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,11 @@
<artifactId>jersey-server</artifactId>
<version>2.13</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.13</version>
</dependency>
<!-- Deploy Jersey apps in stand-alone Grizzly server instead of a servlet container. -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
Expand Down Expand Up @@ -619,6 +624,23 @@
<version>4.7.1</version>
</dependency>

<!-- Support for OTP scripting -->
<dependency>
<groupId>bsf</groupId>
<artifactId>bsf</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.3.8</version>
</dependency>
<dependency>
<groupId>org.python</groupId>
<artifactId>jython</artifactId>
<version>2.5.3</version>
</dependency>

</dependencies>

</project>
21 changes: 21 additions & 0 deletions src/client/scripting.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!doctype html>

<html lang="en">
<head>
<meta charset="utf-8">
<title>OTP Scripting</title>
</head>
<h1>OTP Simple Scripting Client</h1>
<p>
Select a script file to run and click 'Run script'.
Check-out OTP server log to see console output and progress.
To automate this process, you can use <em>curl</em>: <code>curl --form "scriptfile=@myscript.py" localhost:8080/opt/scripting/run</code>.
</p>
<body>
<form enctype='multipart/form-data' action="/otp/scripting/run"
method="post">
<input name="scriptfile" type="file" /> <input type="submit"
value="Run script" />
</form>
</body>
</html>
15 changes: 15 additions & 0 deletions src/main/java/org/opentripplanner/analyst/core/Sample.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,21 @@ public long eval(ShortestPathTree spt) {
return (m0 < m1) ? m0 : m1;
}

public double evalWalkDistance(ShortestPathTree spt) {
State s0 = spt.getState(v0);
State s1 = spt.getState(v1);
double m0 = Double.NaN;
double m1 = Double.NaN;
// TODO When using distance instead of t0/t1 times
// the computation will be made simpler.
double walkSpeed = spt.getOptions().walkSpeed;
if (s0 != null)
m0 = (s0.getWalkDistance() + t0 * walkSpeed);
if (s1 != null)
m1 = (s1.getWalkDistance() + t1 * walkSpeed);
return (m0 < m1) ? m0 : m1;
}

/* DUPLICATES code in sampleSet.eval(). should be deduplicated using a common function of vertices/dists. */
public long eval(TimeSurface surf) {
int m0 = Integer.MAX_VALUE;
Expand Down
71 changes: 71 additions & 0 deletions src/main/java/org/opentripplanner/api/resource/ScriptResource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* This program is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */

package org.opentripplanner.api.resource;

import java.io.InputStream;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import org.apache.commons.io.IOUtils;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.opentripplanner.api.common.RoutingResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Charsets;

/**
* Run an uploaded script. This is unsafe, enable it with care.
*
* TODO Enable role-based permissions.
*
* @author laurent
*/
// @RolesAllowed({ "SCRIPTING" })
@Path("/scripting")
public class ScriptResource extends RoutingResource {

@SuppressWarnings("unused")
private static final Logger LOG = LoggerFactory.getLogger(ScriptResource.class);

@POST
@Path("/run")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(@FormDataParam("scriptfile") InputStream uploadedInputStream,
@FormDataParam("scriptfile") FormDataContentDisposition fileDetail) {

try {
if (!otpServer.scriptingService.enableScriptingWebService)
return Response.status(Status.FORBIDDEN)
.entity("Scripting web-service is desactivated for security reasons.\n")
.build();

String scriptContent = IOUtils.toString(uploadedInputStream, Charsets.UTF_8.name());
Object retval = otpServer.scriptingService.runScript(fileDetail.getFileName(),
scriptContent);
return Response.ok().entity(retval).build();

} catch (Exception e) {
return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.toString())
.type(MediaType.TEXT_PLAIN).build();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;

/**
Expand Down
109 changes: 109 additions & 0 deletions src/main/java/org/opentripplanner/scripting/api/OtpsCsvOutput.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/* This program is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */

package org.opentripplanner.scripting.api;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.csvreader.CsvWriter;
import com.google.common.base.Charsets;

/**
* This class allow one to generate easily tabular data and save it as a CSV file.
*
* For example, in python:
* <pre>
* csv = otp.createCSVOutput()
* csv.setHeader( [ 'lat', 'lon', 'total' ] )
* csv.addRow( [ 45.123, 5.789, 42 ] )
* csv.addRow( [ 45.124, 5.792, 34 ] )
* csv.save('mydata.csv')
* </pre>
*
* TODO Rename this class to "TabularOutput" and allow for saving in various format.
*
* @author laurent
*/
public class OtpsCsvOutput {

private List<List<String>> data = new ArrayList<>();

private String[] headers;

protected OtpsCsvOutput() {
}

/**
* Set the (optional) column header names. If this is not set, no header will be generated.
*
* @param headers An array of string, each entry is the name of the corresponding column header,
* in order.
*/
public void setHeader(Object[] headers) {
this.headers = new String[headers.length];
for (int i = 0; i < headers.length; i++) {
this.headers[i] = headers[i].toString();
}
}

/**
* Add a new row to the data.
*
* @param row An array of objects. The order and size of the array should correspond to the
* header. The default toString method of each object will be called to get the actual
* data to output; so any type of object can be provided (string, numbers...)
*/
public void addRow(Object[] row) {
List<String> strs = new ArrayList<>(row.length);
for (int i = 0; i < row.length; i++) {
strs.add(row[i] == null ? "" : row[i].toString());
}
data.add(strs);
}

/**
* Save the data to a file.
* @param file The name of the file to save the data to.
* @throws IOException In case something bad happens (IO exception)
*/
public void save(String file) throws IOException {
CsvWriter csvWriter = new CsvWriter(file, ',', Charsets.UTF_8);
if (headers != null)
csvWriter.writeRecord(headers);
for (List<String> row : data) {
csvWriter.writeRecord(row.toArray(new String[row.size()]));
}
csvWriter.close();
}

/**
* @return The CSV data as a string. It can be used for example as the script return value.
* @see OtpsEntryPoint.setRetval()
* @throws IOException
*/
public String asText() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
CsvWriter csvWriter = new CsvWriter(baos, ',', Charsets.UTF_8);
if (headers != null)
csvWriter.writeRecord(headers);
for (List<String> row : data) {
csvWriter.writeRecord(row.toArray(new String[row.size()]));
}
csvWriter.close();
return new String(baos.toByteArray(), Charsets.UTF_8);
}

}

0 comments on commit 8ea5520

Please sign in to comment.