Reformat whole codebase using Android Studio
This commit is contained in:
parent
d5322667d5
commit
c15913c1ab
161 changed files with 15124 additions and 18537 deletions
|
|
@ -7,52 +7,39 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Area
|
||||
{
|
||||
private List<Polygon> poslist = new ArrayList<Polygon>();
|
||||
private List<Polygon> neglist = new ArrayList<Polygon>();
|
||||
public class Area {
|
||||
private List<Polygon> poslist = new ArrayList<Polygon>();
|
||||
private List<Polygon> neglist = new ArrayList<Polygon>();
|
||||
|
||||
public static void main( String[] args ) throws IOException
|
||||
{
|
||||
Area a = new Area( new File( args[0] ) );
|
||||
|
||||
System.out.println( args[1] + " is in " + args[0] + "=" + a.isInArea( Long.parseLong( args[1] ) ) );
|
||||
public static void main(String[] args) throws IOException {
|
||||
Area a = new Area(new File(args[0]));
|
||||
|
||||
System.out.println(args[1] + " is in " + args[0] + "=" + a.isInArea(Long.parseLong(args[1])));
|
||||
}
|
||||
|
||||
public Area( File f ) throws IOException
|
||||
{
|
||||
BufferedReader br = new BufferedReader( new FileReader( f ) );
|
||||
|
||||
public Area(File f) throws IOException {
|
||||
BufferedReader br = new BufferedReader(new FileReader(f));
|
||||
br.readLine();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
|
||||
for (; ; ) {
|
||||
String head = br.readLine();
|
||||
if ( head == null || "END".equals( head ) )
|
||||
{
|
||||
if (head == null || "END".equals(head)) {
|
||||
break;
|
||||
}
|
||||
Polygon pol = new Polygon( br );
|
||||
if ( head.startsWith( "!" ) )
|
||||
{
|
||||
neglist.add( pol );
|
||||
}
|
||||
else
|
||||
{
|
||||
poslist.add( pol );
|
||||
Polygon pol = new Polygon(br);
|
||||
if (head.startsWith("!")) {
|
||||
neglist.add(pol);
|
||||
} else {
|
||||
poslist.add(pol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isInArea( long id )
|
||||
{
|
||||
for( int i=0; i<poslist.size(); i++)
|
||||
{
|
||||
if ( poslist.get(i).isInPolygon( id ) )
|
||||
{
|
||||
for( int j=0; j<neglist.size(); j++)
|
||||
{
|
||||
if ( neglist.get(j).isInPolygon( id ) )
|
||||
{
|
||||
|
||||
public boolean isInArea(long id) {
|
||||
for (int i = 0; i < poslist.size(); i++) {
|
||||
if (poslist.get(i).isInPolygon(id)) {
|
||||
for (int j = 0; j < neglist.size(); j++) {
|
||||
if (neglist.get(j).isInPolygon(id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -62,12 +49,9 @@ public class Area
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean isInBoundingBox( long id )
|
||||
{
|
||||
for( int i=0; i<poslist.size(); i++)
|
||||
{
|
||||
if ( poslist.get(i).isInBoundingBox( id ) )
|
||||
{
|
||||
public boolean isInBoundingBox(long id) {
|
||||
for (int i = 0; i < poslist.size(); i++) {
|
||||
if (poslist.get(i).isInBoundingBox(id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,167 +1,144 @@
|
|||
package btools.server;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.io.File;
|
||||
|
||||
import btools.router.OsmNodeNamed;
|
||||
import btools.router.OsmTrack;
|
||||
import btools.router.RoutingContext;
|
||||
import btools.router.RoutingEngine;
|
||||
import btools.router.SearchBoundary;
|
||||
|
||||
public class BRouter
|
||||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
if ( args.length == 2) // cgi-input-mode
|
||||
{
|
||||
try
|
||||
{
|
||||
String queryString = args[1];
|
||||
int sepIdx = queryString.indexOf( '=' );
|
||||
if ( sepIdx >= 0 ) queryString = queryString.substring( sepIdx + 1 );
|
||||
queryString = URLDecoder.decode( queryString, "ISO-8859-1" );
|
||||
int ntokens = 1;
|
||||
for( int ic = 0; ic<queryString.length(); ic++ )
|
||||
{
|
||||
if ( queryString.charAt(ic) == '_' ) ntokens++;
|
||||
}
|
||||
String[] a2 = new String[ntokens + 1];
|
||||
int idx = 1;
|
||||
int pos = 0;
|
||||
for(;;)
|
||||
{
|
||||
int p = queryString.indexOf( '_', pos );
|
||||
if ( p < 0 )
|
||||
{
|
||||
a2[idx++] = queryString.substring( pos );
|
||||
break;
|
||||
}
|
||||
a2[idx++] = queryString.substring( pos, p );
|
||||
pos = p+1;
|
||||
}
|
||||
|
||||
// cgi-header
|
||||
System.out.println( "Content-type: text/plain" );
|
||||
System.out.println();
|
||||
OsmNodeNamed from = readPosition( a2, 1, "from" );
|
||||
OsmNodeNamed to = readPosition( a2, 3, "to" );
|
||||
|
||||
|
||||
int airDistance = from.calcDistance( to );
|
||||
|
||||
String airDistanceLimit = System.getProperty( "airDistanceLimit" );
|
||||
if ( airDistanceLimit != null )
|
||||
{
|
||||
int maxKm = Integer.parseInt( airDistanceLimit );
|
||||
if ( airDistance > maxKm * 1000 )
|
||||
{
|
||||
System.out.println( "airDistance " + (airDistance/1000) + "km exceeds limit for online router (" + maxKm + "km)" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
long maxRunningTime = 60000; // the cgi gets a 1 Minute timeout
|
||||
String sMaxRunningTime = System.getProperty( "maxRunningTime" );
|
||||
if ( sMaxRunningTime != null )
|
||||
{
|
||||
maxRunningTime = Integer.parseInt( sMaxRunningTime ) * 1000;
|
||||
}
|
||||
|
||||
List<OsmNodeNamed> wplist = new ArrayList<OsmNodeNamed>();
|
||||
wplist.add( from );
|
||||
wplist.add( to );
|
||||
|
||||
RoutingEngine re = new RoutingEngine( null, null, new File (args[0]), wplist, readRoutingContext(a2) );
|
||||
re.doRun( maxRunningTime );
|
||||
if ( re.getErrorMessage() != null )
|
||||
{
|
||||
System.out.println( re.getErrorMessage() );
|
||||
}
|
||||
}
|
||||
catch( Throwable e )
|
||||
{
|
||||
System.out.println( "unexpected exception: " + e );
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
System.out.println("BRouter "+ OsmTrack.version + " / " + OsmTrack.versionDate);
|
||||
if ( args.length < 6 )
|
||||
{
|
||||
System.out.println("Find routes in an OSM map");
|
||||
System.out.println("usage: java -jar brouter.jar <segmentdir> <lon-from> <lat-from> <lon-to> <lat-to> <profile>");
|
||||
return;
|
||||
}
|
||||
List<OsmNodeNamed> wplist = new ArrayList<OsmNodeNamed>();
|
||||
wplist.add( readPosition( args, 1, "from" ) );
|
||||
RoutingEngine re = null;
|
||||
if ( "seed".equals( args[3] ) )
|
||||
{
|
||||
int searchRadius = Integer.parseInt( args[4] ); // if = 0 search a 5x5 square
|
||||
|
||||
String filename = SearchBoundary.getFileName( wplist.get(0) );
|
||||
DataOutputStream dos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( "traffic/" + filename ) ) );
|
||||
|
||||
for( int direction = 0; direction < 8; direction++ )
|
||||
{
|
||||
RoutingContext rc = readRoutingContext(args);
|
||||
SearchBoundary boundary = new SearchBoundary( wplist.get(0), searchRadius, direction/2 );
|
||||
rc.trafficOutputStream = dos;
|
||||
rc.inverseDirection = (direction & 1 ) != 0;
|
||||
re = new RoutingEngine( "mytrack", "mylog", new File ( args[0] ), wplist, rc );
|
||||
re.boundary = boundary;
|
||||
re.airDistanceCostFactor = rc.trafficDirectionFactor;
|
||||
rc.countTraffic = true;
|
||||
re.doSearch();
|
||||
if ( re.getErrorMessage() != null )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
dos.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
wplist.add( readPosition( args, 3, "to" ) );
|
||||
RoutingContext rc = readRoutingContext(args);
|
||||
re = new RoutingEngine( "mytrack", "mylog", new File ( args[0] ), wplist, rc );
|
||||
re.doRun( 0 );
|
||||
|
||||
}
|
||||
if ( re.getErrorMessage() != null )
|
||||
{
|
||||
System.out.println( re.getErrorMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static OsmNodeNamed readPosition( String[] args, int idx, String name )
|
||||
{
|
||||
OsmNodeNamed n = new OsmNodeNamed();
|
||||
n.name = name;
|
||||
n.ilon = (int)( ( Double.parseDouble( args[idx ] ) + 180. ) *1000000. + 0.5);
|
||||
n.ilat = (int)( ( Double.parseDouble( args[idx+1] ) + 90. ) *1000000. + 0.5);
|
||||
return n;
|
||||
}
|
||||
|
||||
private static RoutingContext readRoutingContext( String[] args )
|
||||
{
|
||||
RoutingContext c = new RoutingContext();
|
||||
if ( args.length > 5 )
|
||||
{
|
||||
c.localFunction = args[5];
|
||||
if ( args.length > 6 )
|
||||
{
|
||||
c.setAlternativeIdx( Integer.parseInt( args[6] ) );
|
||||
}
|
||||
}
|
||||
c.memoryclass = (int) ( Runtime.getRuntime().maxMemory() / 1024 / 1024 );
|
||||
// c.startDirection= Integer.valueOf( 150 );
|
||||
return c;
|
||||
}
|
||||
}
|
||||
package btools.server;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.io.File;
|
||||
|
||||
import btools.router.OsmNodeNamed;
|
||||
import btools.router.OsmTrack;
|
||||
import btools.router.RoutingContext;
|
||||
import btools.router.RoutingEngine;
|
||||
import btools.router.SearchBoundary;
|
||||
|
||||
public class BRouter {
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length == 2) // cgi-input-mode
|
||||
{
|
||||
try {
|
||||
String queryString = args[1];
|
||||
int sepIdx = queryString.indexOf('=');
|
||||
if (sepIdx >= 0) queryString = queryString.substring(sepIdx + 1);
|
||||
queryString = URLDecoder.decode(queryString, "ISO-8859-1");
|
||||
int ntokens = 1;
|
||||
for (int ic = 0; ic < queryString.length(); ic++) {
|
||||
if (queryString.charAt(ic) == '_') ntokens++;
|
||||
}
|
||||
String[] a2 = new String[ntokens + 1];
|
||||
int idx = 1;
|
||||
int pos = 0;
|
||||
for (; ; ) {
|
||||
int p = queryString.indexOf('_', pos);
|
||||
if (p < 0) {
|
||||
a2[idx++] = queryString.substring(pos);
|
||||
break;
|
||||
}
|
||||
a2[idx++] = queryString.substring(pos, p);
|
||||
pos = p + 1;
|
||||
}
|
||||
|
||||
// cgi-header
|
||||
System.out.println("Content-type: text/plain");
|
||||
System.out.println();
|
||||
OsmNodeNamed from = readPosition(a2, 1, "from");
|
||||
OsmNodeNamed to = readPosition(a2, 3, "to");
|
||||
|
||||
|
||||
int airDistance = from.calcDistance(to);
|
||||
|
||||
String airDistanceLimit = System.getProperty("airDistanceLimit");
|
||||
if (airDistanceLimit != null) {
|
||||
int maxKm = Integer.parseInt(airDistanceLimit);
|
||||
if (airDistance > maxKm * 1000) {
|
||||
System.out.println("airDistance " + (airDistance / 1000) + "km exceeds limit for online router (" + maxKm + "km)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
long maxRunningTime = 60000; // the cgi gets a 1 Minute timeout
|
||||
String sMaxRunningTime = System.getProperty("maxRunningTime");
|
||||
if (sMaxRunningTime != null) {
|
||||
maxRunningTime = Integer.parseInt(sMaxRunningTime) * 1000;
|
||||
}
|
||||
|
||||
List<OsmNodeNamed> wplist = new ArrayList<OsmNodeNamed>();
|
||||
wplist.add(from);
|
||||
wplist.add(to);
|
||||
|
||||
RoutingEngine re = new RoutingEngine(null, null, new File(args[0]), wplist, readRoutingContext(a2));
|
||||
re.doRun(maxRunningTime);
|
||||
if (re.getErrorMessage() != null) {
|
||||
System.out.println(re.getErrorMessage());
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
System.out.println("unexpected exception: " + e);
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
System.out.println("BRouter " + OsmTrack.version + " / " + OsmTrack.versionDate);
|
||||
if (args.length < 6) {
|
||||
System.out.println("Find routes in an OSM map");
|
||||
System.out.println("usage: java -jar brouter.jar <segmentdir> <lon-from> <lat-from> <lon-to> <lat-to> <profile>");
|
||||
return;
|
||||
}
|
||||
List<OsmNodeNamed> wplist = new ArrayList<OsmNodeNamed>();
|
||||
wplist.add(readPosition(args, 1, "from"));
|
||||
RoutingEngine re = null;
|
||||
if ("seed".equals(args[3])) {
|
||||
int searchRadius = Integer.parseInt(args[4]); // if = 0 search a 5x5 square
|
||||
|
||||
String filename = SearchBoundary.getFileName(wplist.get(0));
|
||||
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("traffic/" + filename)));
|
||||
|
||||
for (int direction = 0; direction < 8; direction++) {
|
||||
RoutingContext rc = readRoutingContext(args);
|
||||
SearchBoundary boundary = new SearchBoundary(wplist.get(0), searchRadius, direction / 2);
|
||||
rc.trafficOutputStream = dos;
|
||||
rc.inverseDirection = (direction & 1) != 0;
|
||||
re = new RoutingEngine("mytrack", "mylog", new File(args[0]), wplist, rc);
|
||||
re.boundary = boundary;
|
||||
re.airDistanceCostFactor = rc.trafficDirectionFactor;
|
||||
rc.countTraffic = true;
|
||||
re.doSearch();
|
||||
if (re.getErrorMessage() != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
dos.close();
|
||||
} else {
|
||||
wplist.add(readPosition(args, 3, "to"));
|
||||
RoutingContext rc = readRoutingContext(args);
|
||||
re = new RoutingEngine("mytrack", "mylog", new File(args[0]), wplist, rc);
|
||||
re.doRun(0);
|
||||
|
||||
}
|
||||
if (re.getErrorMessage() != null) {
|
||||
System.out.println(re.getErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static OsmNodeNamed readPosition(String[] args, int idx, String name) {
|
||||
OsmNodeNamed n = new OsmNodeNamed();
|
||||
n.name = name;
|
||||
n.ilon = (int) ((Double.parseDouble(args[idx]) + 180.) * 1000000. + 0.5);
|
||||
n.ilat = (int) ((Double.parseDouble(args[idx + 1]) + 90.) * 1000000. + 0.5);
|
||||
return n;
|
||||
}
|
||||
|
||||
private static RoutingContext readRoutingContext(String[] args) {
|
||||
RoutingContext c = new RoutingContext();
|
||||
if (args.length > 5) {
|
||||
c.localFunction = args[5];
|
||||
if (args.length > 6) {
|
||||
c.setAlternativeIdx(Integer.parseInt(args[6]));
|
||||
}
|
||||
}
|
||||
c.memoryclass = (int) (Runtime.getRuntime().maxMemory() / 1024 / 1024);
|
||||
// c.startDirection= Integer.valueOf( 150 );
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,111 +1,93 @@
|
|||
package btools.server;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.URLDecoder;
|
||||
|
||||
public class CgiUpload
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
_main(args);
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
System.out.println( "unexpected exception: " + e );
|
||||
}
|
||||
}
|
||||
|
||||
private static void _main(String[] args) throws Exception
|
||||
{
|
||||
String htmlTemplate = args[0];
|
||||
String customeProfileDir = args[1];
|
||||
|
||||
String id = "" + System.currentTimeMillis();
|
||||
|
||||
|
||||
// cgi-header
|
||||
System.out.println( "Content-type: text/html" );
|
||||
System.out.println();
|
||||
|
||||
// write the post message to a file
|
||||
BufferedWriter bw = new BufferedWriter(
|
||||
new OutputStreamWriter(
|
||||
new FileOutputStream( customeProfileDir + "/" + id + ".brf" ) ) );
|
||||
BufferedReader ir = new BufferedReader( new InputStreamReader( System.in ) );
|
||||
String postData = ir.readLine();
|
||||
String[] coordValues = new String[4];
|
||||
if( postData != null )
|
||||
{
|
||||
int coordsIdx = postData.indexOf( "coords=" );
|
||||
if ( coordsIdx >= 0)
|
||||
{
|
||||
int coordsEnd = postData.indexOf( '&' );
|
||||
if ( coordsEnd >= 0)
|
||||
{
|
||||
String coordsString = postData.substring( coordsIdx + 7, coordsEnd );
|
||||
postData = postData.substring( coordsEnd+1 );
|
||||
int pos = 0;
|
||||
for(int idx=0; idx<4; idx++)
|
||||
{
|
||||
int p = coordsString.indexOf( '_', pos );
|
||||
coordValues[idx] = coordsString.substring( pos, p );
|
||||
pos = p+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
int sepIdx = postData.indexOf( '=' );
|
||||
if ( sepIdx >= 0 ) postData = postData.substring( sepIdx + 1 );
|
||||
postData = URLDecoder.decode( postData, "ISO-8859-1" );
|
||||
bw.write( postData );
|
||||
}
|
||||
bw.close();
|
||||
|
||||
// echo the template with a custom select item
|
||||
BufferedReader br = new BufferedReader(
|
||||
new InputStreamReader(
|
||||
new FileInputStream( htmlTemplate ) ) );
|
||||
|
||||
for(;;)
|
||||
{
|
||||
String line = br.readLine();
|
||||
if ( line == null ) break;
|
||||
if ( line.indexOf( "<!-- sample profiles -->" ) >= 0 )
|
||||
{
|
||||
line = " <option value=\"../customprofiles/" + id + "\">custom</option>";
|
||||
}
|
||||
else if ( line.indexOf( "paste your profile here" ) >= 0 )
|
||||
{
|
||||
System.out.println( "<textarea type=\"text\" name=\"profile\" rows=30 cols=100>" );
|
||||
System.out.println( postData );
|
||||
line = "</textarea>";
|
||||
}
|
||||
else
|
||||
{
|
||||
line = replaceCoord( line, "lonfrom", coordValues[0] );
|
||||
line = replaceCoord( line, "latfrom", coordValues[1] );
|
||||
line = replaceCoord( line, "lonto", coordValues[2] );
|
||||
line = replaceCoord( line, "latto", coordValues[3] );
|
||||
}
|
||||
|
||||
System.out.println( line );
|
||||
}
|
||||
br.close();
|
||||
}
|
||||
|
||||
private static String replaceCoord( String line, String name, String value )
|
||||
{
|
||||
String inputTag = "<td><input type=\"text\" name=\"" + name + "\"";
|
||||
if ( line.indexOf( inputTag ) >= 0 )
|
||||
{
|
||||
return inputTag + " value=\"" + value + "\"></td>";
|
||||
}
|
||||
return line;
|
||||
}
|
||||
}
|
||||
package btools.server;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.URLDecoder;
|
||||
|
||||
public class CgiUpload {
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
_main(args);
|
||||
} catch (Exception e) {
|
||||
System.out.println("unexpected exception: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void _main(String[] args) throws Exception {
|
||||
String htmlTemplate = args[0];
|
||||
String customeProfileDir = args[1];
|
||||
|
||||
String id = "" + System.currentTimeMillis();
|
||||
|
||||
|
||||
// cgi-header
|
||||
System.out.println("Content-type: text/html");
|
||||
System.out.println();
|
||||
|
||||
// write the post message to a file
|
||||
BufferedWriter bw = new BufferedWriter(
|
||||
new OutputStreamWriter(
|
||||
new FileOutputStream(customeProfileDir + "/" + id + ".brf")));
|
||||
BufferedReader ir = new BufferedReader(new InputStreamReader(System.in));
|
||||
String postData = ir.readLine();
|
||||
String[] coordValues = new String[4];
|
||||
if (postData != null) {
|
||||
int coordsIdx = postData.indexOf("coords=");
|
||||
if (coordsIdx >= 0) {
|
||||
int coordsEnd = postData.indexOf('&');
|
||||
if (coordsEnd >= 0) {
|
||||
String coordsString = postData.substring(coordsIdx + 7, coordsEnd);
|
||||
postData = postData.substring(coordsEnd + 1);
|
||||
int pos = 0;
|
||||
for (int idx = 0; idx < 4; idx++) {
|
||||
int p = coordsString.indexOf('_', pos);
|
||||
coordValues[idx] = coordsString.substring(pos, p);
|
||||
pos = p + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
int sepIdx = postData.indexOf('=');
|
||||
if (sepIdx >= 0) postData = postData.substring(sepIdx + 1);
|
||||
postData = URLDecoder.decode(postData, "ISO-8859-1");
|
||||
bw.write(postData);
|
||||
}
|
||||
bw.close();
|
||||
|
||||
// echo the template with a custom select item
|
||||
BufferedReader br = new BufferedReader(
|
||||
new InputStreamReader(
|
||||
new FileInputStream(htmlTemplate)));
|
||||
|
||||
for (; ; ) {
|
||||
String line = br.readLine();
|
||||
if (line == null) break;
|
||||
if (line.indexOf("<!-- sample profiles -->") >= 0) {
|
||||
line = " <option value=\"../customprofiles/" + id + "\">custom</option>";
|
||||
} else if (line.indexOf("paste your profile here") >= 0) {
|
||||
System.out.println("<textarea type=\"text\" name=\"profile\" rows=30 cols=100>");
|
||||
System.out.println(postData);
|
||||
line = "</textarea>";
|
||||
} else {
|
||||
line = replaceCoord(line, "lonfrom", coordValues[0]);
|
||||
line = replaceCoord(line, "latfrom", coordValues[1]);
|
||||
line = replaceCoord(line, "lonto", coordValues[2]);
|
||||
line = replaceCoord(line, "latto", coordValues[3]);
|
||||
}
|
||||
|
||||
System.out.println(line);
|
||||
}
|
||||
br.close();
|
||||
}
|
||||
|
||||
private static String replaceCoord(String line, String name, String value) {
|
||||
String inputTag = "<td><input type=\"text\" name=\"" + name + "\"";
|
||||
if (line.indexOf(inputTag) >= 0) {
|
||||
return inputTag + " value=\"" + value + "\"></td>";
|
||||
}
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,50 +3,41 @@ package btools.server;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class IpAccessMonitor
|
||||
{
|
||||
public class IpAccessMonitor {
|
||||
private static Object sync = new Object();
|
||||
private static HashMap<String,Long> ipAccess = new HashMap<String,Long>();
|
||||
private static HashMap<String, Long> ipAccess = new HashMap<String, Long>();
|
||||
private static long MAX_IDLE = 900000; // 15 minutes
|
||||
private static long CLEANUP_INTERVAL = 10000; // 10 seconds
|
||||
private static long lastCleanup;
|
||||
|
||||
public static boolean touchIpAccess( String ip )
|
||||
{
|
||||
public static boolean touchIpAccess(String ip) {
|
||||
long t = System.currentTimeMillis();
|
||||
synchronized( sync )
|
||||
{
|
||||
Long lastTime = ipAccess.get( ip );
|
||||
ipAccess.put( ip, Long.valueOf( t ) );
|
||||
synchronized (sync) {
|
||||
Long lastTime = ipAccess.get(ip);
|
||||
ipAccess.put(ip, Long.valueOf(t));
|
||||
return lastTime == null || t - lastTime.longValue() > MAX_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getSessionCount()
|
||||
{
|
||||
public static int getSessionCount() {
|
||||
long t = System.currentTimeMillis();
|
||||
synchronized( sync )
|
||||
{
|
||||
if ( t - lastCleanup > CLEANUP_INTERVAL )
|
||||
{
|
||||
cleanup( t );
|
||||
synchronized (sync) {
|
||||
if (t - lastCleanup > CLEANUP_INTERVAL) {
|
||||
cleanup(t);
|
||||
lastCleanup = t;
|
||||
}
|
||||
return ipAccess.size();
|
||||
}
|
||||
}
|
||||
|
||||
private static void cleanup( long t )
|
||||
{
|
||||
HashMap<String,Long> newMap = new HashMap<String,Long>(ipAccess.size());
|
||||
for( Map.Entry<String,Long> e : ipAccess.entrySet() )
|
||||
{
|
||||
if ( t - e.getValue().longValue() <= MAX_IDLE )
|
||||
{
|
||||
newMap.put( e.getKey(), e.getValue() );
|
||||
|
||||
private static void cleanup(long t) {
|
||||
HashMap<String, Long> newMap = new HashMap<String, Long>(ipAccess.size());
|
||||
for (Map.Entry<String, Long> e : ipAccess.entrySet()) {
|
||||
if (t - e.getValue().longValue() <= MAX_IDLE) {
|
||||
newMap.put(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
ipAccess = newMap;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,44 +5,33 @@ import java.util.List;
|
|||
import btools.mapaccess.OsmNode;
|
||||
import btools.router.OsmNodeNamed;
|
||||
|
||||
public class NearRecentWps
|
||||
{
|
||||
public class NearRecentWps {
|
||||
private OsmNodeNamed[] recentWaypoints = new OsmNodeNamed[2000];
|
||||
private int nextRecentIndex = 0;
|
||||
|
||||
public void add( List<OsmNodeNamed> wplist )
|
||||
{
|
||||
synchronized( recentWaypoints )
|
||||
{
|
||||
for( OsmNodeNamed wp : wplist )
|
||||
{
|
||||
add( wp );
|
||||
public void add(List<OsmNodeNamed> wplist) {
|
||||
synchronized (recentWaypoints) {
|
||||
for (OsmNodeNamed wp : wplist) {
|
||||
add(wp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void add( OsmNodeNamed wp )
|
||||
{
|
||||
public void add(OsmNodeNamed wp) {
|
||||
recentWaypoints[nextRecentIndex++] = wp;
|
||||
if ( nextRecentIndex >= recentWaypoints.length )
|
||||
{
|
||||
if (nextRecentIndex >= recentWaypoints.length) {
|
||||
nextRecentIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int count( long id )
|
||||
{
|
||||
public int count(long id) {
|
||||
int cnt = 0;
|
||||
OsmNode n = new OsmNode( id );
|
||||
synchronized( recentWaypoints )
|
||||
{
|
||||
for ( int i=0; i<recentWaypoints.length; i++ )
|
||||
{
|
||||
OsmNode n = new OsmNode(id);
|
||||
synchronized (recentWaypoints) {
|
||||
for (int i = 0; i < recentWaypoints.length; i++) {
|
||||
OsmNodeNamed nn = recentWaypoints[i];
|
||||
if ( nn != null )
|
||||
{
|
||||
if ( nn.calcDistance( n ) < 4000 )
|
||||
{
|
||||
if (nn != null) {
|
||||
if (nn.calcDistance(n) < 4000) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
|
@ -51,21 +40,16 @@ public class NearRecentWps
|
|||
return cnt;
|
||||
}
|
||||
|
||||
public OsmNodeNamed closest( long id )
|
||||
{
|
||||
public OsmNodeNamed closest(long id) {
|
||||
int dmin = 0;
|
||||
OsmNodeNamed nc = null;
|
||||
OsmNode n = new OsmNode( id );
|
||||
synchronized( recentWaypoints )
|
||||
{
|
||||
for ( int i=0; i<recentWaypoints.length; i++ )
|
||||
{
|
||||
OsmNode n = new OsmNode(id);
|
||||
synchronized (recentWaypoints) {
|
||||
for (int i = 0; i < recentWaypoints.length; i++) {
|
||||
OsmNodeNamed nn = recentWaypoints[i];
|
||||
if ( nn != null )
|
||||
{
|
||||
int d = nn.calcDistance( n );
|
||||
if ( d < 4000 && ( nc == null || d < dmin ) )
|
||||
{
|
||||
if (nn != null) {
|
||||
int d = nn.calcDistance(n);
|
||||
if (d < 4000 && (nc == null || d < dmin)) {
|
||||
dmin = d;
|
||||
nc = nn;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class Polygon
|
||||
{
|
||||
public class Polygon {
|
||||
private int[] ax;
|
||||
private int[] ay;
|
||||
|
||||
|
|
@ -15,62 +14,53 @@ public class Polygon
|
|||
private int maxx = Integer.MIN_VALUE;
|
||||
private int maxy = Integer.MIN_VALUE;
|
||||
|
||||
public Polygon( BufferedReader br ) throws IOException
|
||||
{
|
||||
public Polygon(BufferedReader br) throws IOException {
|
||||
ArrayList<String> lines = new ArrayList<String>();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
|
||||
for (; ; ) {
|
||||
String line = br.readLine();
|
||||
if ( line == null || "END".equals( line ) )
|
||||
{
|
||||
if (line == null || "END".equals(line)) {
|
||||
break;
|
||||
}
|
||||
lines.add( line );
|
||||
lines.add(line);
|
||||
}
|
||||
int n = lines.size();
|
||||
ax = new int[n];
|
||||
ay = new int[n];
|
||||
for( int i=0; i<n; i++ )
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
String line = lines.get(i);
|
||||
StringTokenizer tk = new StringTokenizer( line );
|
||||
double lon = Double.parseDouble( tk.nextToken() );
|
||||
double lat = Double.parseDouble( tk.nextToken() );
|
||||
|
||||
int x = ax[i] = (int)(lon*1000000. + 180000000);
|
||||
int y = ay[i] = (int)(lat*1000000. + 90000000);
|
||||
|
||||
if ( x < minx ) minx = x;
|
||||
if ( y < miny ) miny = y;
|
||||
if ( x > maxx ) maxx = x;
|
||||
if ( y > maxy ) maxy = y;
|
||||
StringTokenizer tk = new StringTokenizer(line);
|
||||
double lon = Double.parseDouble(tk.nextToken());
|
||||
double lat = Double.parseDouble(tk.nextToken());
|
||||
|
||||
int x = ax[i] = (int) (lon * 1000000. + 180000000);
|
||||
int y = ay[i] = (int) (lat * 1000000. + 90000000);
|
||||
|
||||
if (x < minx) minx = x;
|
||||
if (y < miny) miny = y;
|
||||
if (x > maxx) maxx = x;
|
||||
if (y > maxy) maxy = y;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isInPolygon( long id )
|
||||
{
|
||||
int x = (int) ( id >> 32 );
|
||||
int y = (int) ( id & 0xffffffff );
|
||||
|
||||
if ( x < minx || x > maxx || y < miny || y > maxy )
|
||||
{
|
||||
public boolean isInPolygon(long id) {
|
||||
int x = (int) (id >> 32);
|
||||
int y = (int) (id & 0xffffffff);
|
||||
|
||||
if (x < minx || x > maxx || y < miny || y > maxy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int n = ax.length-1; // these are closed polygons
|
||||
int n = ax.length - 1; // these are closed polygons
|
||||
|
||||
boolean inside = false;
|
||||
int j = n - 1;
|
||||
for (int i = 0 ;i < n ; j = i++)
|
||||
{
|
||||
if ( (ay[i] > y) != (ay[j] > y) )
|
||||
{
|
||||
for (int i = 0; i < n; j = i++) {
|
||||
if ((ay[i] > y) != (ay[j] > y)) {
|
||||
long v = ax[j] - ax[i];
|
||||
v *= y - ay[i];
|
||||
v /= ay[j] - ay[i];
|
||||
if ( x <= v + ax[i])
|
||||
{
|
||||
if (x <= v + ax[i]) {
|
||||
inside = !inside;
|
||||
}
|
||||
}
|
||||
|
|
@ -78,10 +68,9 @@ public class Polygon
|
|||
return inside;
|
||||
}
|
||||
|
||||
public boolean isInBoundingBox( long id )
|
||||
{
|
||||
int x = (int) ( id >> 32 );
|
||||
int y = (int) ( id & 0xffffffff );
|
||||
public boolean isInBoundingBox(long id) {
|
||||
int x = (int) (id >> 32);
|
||||
int y = (int) (id & 0xffffffff);
|
||||
|
||||
return x >= minx && x <= maxx && y >= miny && y <= maxy;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,515 +1,444 @@
|
|||
package btools.server;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.Writer;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.URLDecoder;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import btools.router.OsmNodeNamed;
|
||||
import btools.router.OsmTrack;
|
||||
import btools.router.ProfileCache;
|
||||
import btools.router.RoutingContext;
|
||||
import btools.router.RoutingEngine;
|
||||
import btools.server.request.ProfileUploadHandler;
|
||||
import btools.server.request.RequestHandler;
|
||||
import btools.server.request.ServerHandler;
|
||||
import btools.util.StackSampler;
|
||||
|
||||
public class RouteServer extends Thread implements Comparable<RouteServer>
|
||||
{
|
||||
public static final String PROFILE_UPLOAD_URL = "/brouter/profile";
|
||||
static final String HTTP_STATUS_OK = "200 OK";
|
||||
static final String HTTP_STATUS_BAD_REQUEST = "400 Bad Request";
|
||||
static final String HTTP_STATUS_FORBIDDEN = "403 Forbidden";
|
||||
static final String HTTP_STATUS_NOT_FOUND = "404 Not Found";
|
||||
static final String HTTP_STATUS_INTERNAL_SERVER_ERROR = "500 Internal Server Error";
|
||||
|
||||
public ServiceContext serviceContext;
|
||||
|
||||
private Socket clientSocket = null;
|
||||
private RoutingEngine cr = null;
|
||||
private volatile boolean terminated;
|
||||
private long starttime;
|
||||
|
||||
private static Object threadPoolSync = new Object();
|
||||
private static boolean debug = Boolean.getBoolean( "debugThreadPool" );
|
||||
|
||||
public void stopRouter()
|
||||
{
|
||||
RoutingEngine e = cr;
|
||||
if ( e != null ) e.terminate();
|
||||
}
|
||||
|
||||
private static DateFormat tsFormat = new SimpleDateFormat( "dd.MM.yy HH:mm", new Locale( "en", "US" ) );
|
||||
|
||||
private static String formattedTimeStamp( long t )
|
||||
{
|
||||
synchronized( tsFormat )
|
||||
{
|
||||
return tsFormat.format( new Date( System.currentTimeMillis() ) );
|
||||
}
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
BufferedReader br = null;
|
||||
BufferedWriter bw = null;
|
||||
|
||||
// first line
|
||||
String getline = null;
|
||||
String sessionInfo = null;
|
||||
String sIp = null;
|
||||
|
||||
try
|
||||
{
|
||||
br = new BufferedReader( new InputStreamReader( clientSocket.getInputStream() , "UTF-8") );
|
||||
bw = new BufferedWriter( new OutputStreamWriter( clientSocket.getOutputStream(), "UTF-8" ) );
|
||||
|
||||
String agent = null;
|
||||
String encodings = null;
|
||||
String xff = null; // X-Forwarded-For
|
||||
String referer = null;
|
||||
|
||||
// more headers until first empty line
|
||||
for(;;)
|
||||
{
|
||||
// headers
|
||||
String line = br.readLine();
|
||||
if ( line == null )
|
||||
{
|
||||
writeHttpHeader(bw, HTTP_STATUS_BAD_REQUEST);
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
if ( line.length() == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ( getline == null )
|
||||
{
|
||||
getline = line;
|
||||
}
|
||||
line = line.toLowerCase();
|
||||
if ( line.startsWith( "user-agent: " ) )
|
||||
{
|
||||
agent = line.substring( "user-agent: ".length() );
|
||||
}
|
||||
if ( line.startsWith( "accept-encoding: " ) )
|
||||
{
|
||||
encodings = line.substring( "accept-encoding: ".length() );
|
||||
}
|
||||
if ( line.startsWith( "x-forwarded-for: " ) )
|
||||
{
|
||||
xff = line.substring( "x-forwarded-for: ".length() );
|
||||
}
|
||||
if ( line.startsWith( "Referer: " ) )
|
||||
{
|
||||
referer = line.substring( "Referer: ".length() );
|
||||
}
|
||||
if ( line.startsWith( "Referrer: " ) )
|
||||
{
|
||||
referer = line.substring( "Referrer: ".length() );
|
||||
}
|
||||
}
|
||||
|
||||
InetAddress ip = clientSocket.getInetAddress();
|
||||
sIp = xff == null ? (ip==null ? "null" : ip.toString() ) : xff;
|
||||
boolean newSession = IpAccessMonitor.touchIpAccess( sIp );
|
||||
sessionInfo = " new";
|
||||
if ( !newSession )
|
||||
{
|
||||
int sessionCount = IpAccessMonitor.getSessionCount();
|
||||
sessionInfo = " " + Math.min( sessionCount, 999 );
|
||||
sessionInfo = sessionInfo.substring( sessionInfo.length() - 4 );
|
||||
}
|
||||
|
||||
String excludedAgents = System.getProperty( "excludedAgents" );
|
||||
if ( agent != null && excludedAgents != null )
|
||||
{
|
||||
StringTokenizer tk = new StringTokenizer( excludedAgents, "," );
|
||||
while( tk.hasMoreTokens() )
|
||||
{
|
||||
if ( agent.indexOf( tk.nextToken() ) >= 0 )
|
||||
{
|
||||
writeHttpHeader( bw, HTTP_STATUS_FORBIDDEN );
|
||||
bw.write( "Bad agent: " + agent );
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( referer != null && referer.indexOf( "brouter.de/brouter-web" ) >= 0 )
|
||||
{
|
||||
if ( getline.indexOf( "%7C" ) >= 0 && getline.indexOf( "%2C" ) >= 0 )
|
||||
{
|
||||
writeHttpHeader( bw, HTTP_STATUS_FORBIDDEN );
|
||||
bw.write( "Spam? please stop" );
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( getline.startsWith("GET /favicon.ico") )
|
||||
{
|
||||
writeHttpHeader( bw, HTTP_STATUS_NOT_FOUND );
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
if ( getline.startsWith("GET /robots.txt") )
|
||||
{
|
||||
writeHttpHeader( bw, HTTP_STATUS_OK );
|
||||
bw.write( "User-agent: *\n" );
|
||||
bw.write( "Disallow: /\n" );
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
|
||||
String url = getline.split(" ")[1];
|
||||
HashMap<String,String> params = getUrlParams(url);
|
||||
|
||||
long maxRunningTime = getMaxRunningTime();
|
||||
|
||||
RequestHandler handler;
|
||||
if ( params.containsKey( "lonlats" ) && params.containsKey( "profile" ) )
|
||||
{
|
||||
handler = new ServerHandler( serviceContext, params );
|
||||
}
|
||||
else if ( url.startsWith( PROFILE_UPLOAD_URL ) )
|
||||
{
|
||||
if ( getline.startsWith("OPTIONS") )
|
||||
{
|
||||
// handle CORS preflight request (Safari)
|
||||
String corsHeaders = "Access-Control-Allow-Methods: GET, POST\n"
|
||||
+ "Access-Control-Allow-Headers: Content-Type\n";
|
||||
writeHttpHeader( bw, "text/plain", null, corsHeaders, HTTP_STATUS_OK );
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
writeHttpHeader(bw, "application/json", HTTP_STATUS_OK);
|
||||
|
||||
String profileId = null;
|
||||
if ( url.length() > PROFILE_UPLOAD_URL.length() + 1 )
|
||||
{
|
||||
// e.g. /brouter/profile/custom_1400767688382
|
||||
profileId = url.substring(PROFILE_UPLOAD_URL.length() + 1);
|
||||
}
|
||||
|
||||
ProfileUploadHandler uploadHandler = new ProfileUploadHandler( serviceContext );
|
||||
uploadHandler.handlePostRequest( profileId, br, bw );
|
||||
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ( url.startsWith( "/brouter/suspects" ) )
|
||||
{
|
||||
writeHttpHeader(bw, url.endsWith( ".json" ) ? "application/json" : "text/html", HTTP_STATUS_OK);
|
||||
SuspectManager.process( url, bw );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
writeHttpHeader( bw, HTTP_STATUS_NOT_FOUND );
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
RoutingContext rc = handler.readRoutingContext();
|
||||
List<OsmNodeNamed> wplist = handler.readWayPointList();
|
||||
|
||||
if ( wplist.size() < 10 )
|
||||
{
|
||||
SuspectManager.nearRecentWps.add( wplist );
|
||||
}
|
||||
for( Map.Entry<String,String> e : params.entrySet() )
|
||||
{
|
||||
if ( "timode".equals( e.getKey() ) )
|
||||
{
|
||||
rc.turnInstructionMode = Integer.parseInt( e.getValue() );
|
||||
}
|
||||
else if ( "heading".equals( e.getKey() ) )
|
||||
{
|
||||
rc.startDirection = Integer.valueOf( Integer.parseInt( e.getValue() ) );
|
||||
rc.forceUseStartDirection = true;
|
||||
}
|
||||
else if ( e.getKey().startsWith( "profile:" ) )
|
||||
{
|
||||
if ( rc.keyValues == null )
|
||||
{
|
||||
rc.keyValues = new HashMap<String,String>();
|
||||
}
|
||||
rc.keyValues.put( e.getKey().substring( 8 ), e.getValue() );
|
||||
}
|
||||
}
|
||||
cr = new RoutingEngine( null, null, serviceContext.segmentDir, wplist, rc );
|
||||
cr.quite = true;
|
||||
cr.doRun( maxRunningTime );
|
||||
|
||||
if ( cr.getErrorMessage() != null )
|
||||
{
|
||||
writeHttpHeader(bw, HTTP_STATUS_BAD_REQUEST);
|
||||
bw.write( cr.getErrorMessage() );
|
||||
bw.write( "\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
OsmTrack track = cr.getFoundTrack();
|
||||
|
||||
String headers = encodings == null || encodings.indexOf( "gzip" ) < 0 ? null : "Content-Encoding: gzip\n";
|
||||
writeHttpHeader(bw, handler.getMimeType(), handler.getFileName(), headers, HTTP_STATUS_OK );
|
||||
if ( track != null )
|
||||
{
|
||||
if ( headers != null ) // compressed
|
||||
{
|
||||
java.io.ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
Writer w = new OutputStreamWriter( new GZIPOutputStream( baos ), "UTF-8" );
|
||||
w.write( handler.formatTrack(track) );
|
||||
w.close();
|
||||
bw.flush();
|
||||
clientSocket.getOutputStream().write( baos.toByteArray() );
|
||||
}
|
||||
else
|
||||
{
|
||||
bw.write( handler.formatTrack(track) );
|
||||
}
|
||||
}
|
||||
}
|
||||
bw.flush();
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
try {
|
||||
writeHttpHeader(bw, HTTP_STATUS_INTERNAL_SERVER_ERROR);
|
||||
bw.flush();
|
||||
}
|
||||
catch (IOException _ignore){}
|
||||
System.out.println("RouteServer got exception (will continue): "+e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
cr = null;
|
||||
if ( br != null ) try { br.close(); } catch( Exception e ) {}
|
||||
if ( bw != null ) try { bw.close(); } catch( Exception e ) {}
|
||||
if ( clientSocket != null ) try { clientSocket.close(); } catch( Exception e ) {}
|
||||
terminated = true;
|
||||
synchronized( threadPoolSync )
|
||||
{
|
||||
threadPoolSync.notifyAll();
|
||||
}
|
||||
long t = System.currentTimeMillis();
|
||||
long ms = t - starttime;
|
||||
System.out.println( formattedTimeStamp(t) + sessionInfo + " ip=" + sIp + " ms=" + ms + " -> " + getline );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
System.out.println("BRouter " + OsmTrack.version + " / " + OsmTrack.versionDate);
|
||||
if ( args.length != 5 && args.length != 6)
|
||||
{
|
||||
System.out.println("serve BRouter protocol");
|
||||
System.out.println("usage: java RouteServer <segmentdir> <profiledir> <customprofiledir> <port> <maxthreads> [bindaddress]");
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceContext serviceContext = new ServiceContext();
|
||||
serviceContext.segmentDir = new File ( args[0] );
|
||||
serviceContext.profileDir = args[1];
|
||||
System.setProperty( "profileBaseDir", serviceContext.profileDir );
|
||||
String dirs = args[2];
|
||||
StringTokenizer tk = new StringTokenizer( dirs, "," );
|
||||
serviceContext.customProfileDir = tk.nextToken();
|
||||
serviceContext.sharedProfileDir = tk.hasMoreTokens() ? tk.nextToken() : serviceContext.customProfileDir;
|
||||
|
||||
int maxthreads = Integer.parseInt( args[4] );
|
||||
|
||||
ProfileCache.setSize( 2*maxthreads );
|
||||
|
||||
PriorityQueue<RouteServer> threadQueue = new PriorityQueue<RouteServer>();
|
||||
|
||||
ServerSocket serverSocket = args.length > 5 ? new ServerSocket(Integer.parseInt(args[3]),100,InetAddress.getByName(args[5])) : new ServerSocket(Integer.parseInt(args[3]));
|
||||
|
||||
// stacksample for performance profiling
|
||||
// ( caution: start stacksampler only after successfully creating the server socket
|
||||
// because that thread prevents the process from terminating, so the start-attempt
|
||||
// by the watchdog cron would create zombies )
|
||||
File stackLog = new File( "stacks.txt" );
|
||||
if ( stackLog.exists() )
|
||||
{
|
||||
StackSampler stackSampler = new StackSampler( stackLog, 1000 );
|
||||
stackSampler.start();
|
||||
System.out.println( "*** sampling stacks into stacks.txt *** ");
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Socket clientSocket = serverSocket.accept();
|
||||
RouteServer server = new RouteServer();
|
||||
server.serviceContext = serviceContext;
|
||||
server.clientSocket = clientSocket;
|
||||
server.starttime = System.currentTimeMillis();
|
||||
|
||||
// kill an old thread if thread limit reached
|
||||
|
||||
cleanupThreadQueue( threadQueue );
|
||||
|
||||
if ( debug ) System.out.println( "threadQueue.size()=" + threadQueue.size() );
|
||||
if ( threadQueue.size() >= maxthreads )
|
||||
{
|
||||
synchronized( threadPoolSync )
|
||||
{
|
||||
// wait up to 2000ms (maybe notified earlier)
|
||||
// to prevent killing short-running threads
|
||||
long maxage = server.starttime - threadQueue.peek().starttime;
|
||||
long maxWaitTime = 2000L-maxage;
|
||||
if ( debug ) System.out.println( "maxage=" + maxage + " maxWaitTime=" + maxWaitTime );
|
||||
if ( debug )
|
||||
{
|
||||
for ( RouteServer t : threadQueue )
|
||||
{
|
||||
System.out.println( "age=" + (server.starttime - t.starttime) );
|
||||
}
|
||||
}
|
||||
if ( maxWaitTime > 0 )
|
||||
{
|
||||
threadPoolSync.wait( maxWaitTime );
|
||||
}
|
||||
long t = System.currentTimeMillis();
|
||||
System.out.println( formattedTimeStamp(t) + " contention! ms waited " + (t - server.starttime) );
|
||||
}
|
||||
cleanupThreadQueue( threadQueue );
|
||||
if ( threadQueue.size() >= maxthreads )
|
||||
{
|
||||
if ( debug ) System.out.println( "stopping oldest thread..." );
|
||||
// no way... stop the oldest thread
|
||||
RouteServer oldest = threadQueue.poll();
|
||||
oldest.stopRouter();
|
||||
long t = System.currentTimeMillis();
|
||||
System.out.println( formattedTimeStamp(t) + " contention! ms killed " + (t - oldest.starttime) );
|
||||
}
|
||||
}
|
||||
|
||||
threadQueue.add( server );
|
||||
|
||||
server.start();
|
||||
if ( debug ) System.out.println( "thread started..." );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static HashMap<String,String> getUrlParams( String url ) throws UnsupportedEncodingException
|
||||
{
|
||||
HashMap<String,String> params = new HashMap<String,String>();
|
||||
String decoded = URLDecoder.decode( url, "UTF-8" );
|
||||
StringTokenizer tk = new StringTokenizer( decoded, "?&" );
|
||||
while( tk.hasMoreTokens() )
|
||||
{
|
||||
String t = tk.nextToken();
|
||||
StringTokenizer tk2 = new StringTokenizer( t, "=" );
|
||||
if ( tk2.hasMoreTokens() )
|
||||
{
|
||||
String key = tk2.nextToken();
|
||||
if ( tk2.hasMoreTokens() )
|
||||
{
|
||||
String value = tk2.nextToken();
|
||||
params.put( key, value );
|
||||
}
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
private static long getMaxRunningTime() {
|
||||
long maxRunningTime = 60000;
|
||||
String sMaxRunningTime = System.getProperty( "maxRunningTime" );
|
||||
if ( sMaxRunningTime != null )
|
||||
{
|
||||
maxRunningTime = Integer.parseInt( sMaxRunningTime ) * 1000;
|
||||
}
|
||||
return maxRunningTime;
|
||||
}
|
||||
|
||||
private static void writeHttpHeader( BufferedWriter bw, String status ) throws IOException
|
||||
{
|
||||
writeHttpHeader( bw, "text/plain", status );
|
||||
}
|
||||
|
||||
private static void writeHttpHeader( BufferedWriter bw, String mimeType, String status ) throws IOException
|
||||
{
|
||||
writeHttpHeader( bw, mimeType, null, status );
|
||||
}
|
||||
|
||||
private static void writeHttpHeader( BufferedWriter bw, String mimeType, String fileName, String status ) throws IOException
|
||||
{
|
||||
writeHttpHeader( bw, mimeType, fileName, null, status);
|
||||
}
|
||||
|
||||
private static void writeHttpHeader( BufferedWriter bw, String mimeType, String fileName, String headers, String status ) throws IOException
|
||||
{
|
||||
// http-header
|
||||
bw.write( String.format("HTTP/1.1 %s\n", status) );
|
||||
bw.write( "Connection: close\n" );
|
||||
bw.write( "Content-Type: " + mimeType + "; charset=utf-8\n" );
|
||||
if ( fileName != null )
|
||||
{
|
||||
bw.write( "Content-Disposition: attachment; filename=\"" + fileName + "\"\n" );
|
||||
}
|
||||
bw.write( "Access-Control-Allow-Origin: *\n" );
|
||||
if ( headers != null )
|
||||
{
|
||||
bw.write( headers );
|
||||
}
|
||||
bw.write( "\n" );
|
||||
}
|
||||
|
||||
private static void cleanupThreadQueue( PriorityQueue<RouteServer> threadQueue )
|
||||
{
|
||||
for ( ;; )
|
||||
{
|
||||
boolean removedItem = false;
|
||||
for ( RouteServer t : threadQueue )
|
||||
{
|
||||
if ( t.terminated )
|
||||
{
|
||||
threadQueue.remove( t );
|
||||
removedItem = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !removedItem )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo( RouteServer t )
|
||||
{
|
||||
return starttime < t.starttime ? -1 : ( starttime > t.starttime ? 1 : 0 );
|
||||
}
|
||||
|
||||
}
|
||||
package btools.server;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.Writer;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.URLDecoder;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import btools.router.OsmNodeNamed;
|
||||
import btools.router.OsmTrack;
|
||||
import btools.router.ProfileCache;
|
||||
import btools.router.RoutingContext;
|
||||
import btools.router.RoutingEngine;
|
||||
import btools.server.request.ProfileUploadHandler;
|
||||
import btools.server.request.RequestHandler;
|
||||
import btools.server.request.ServerHandler;
|
||||
import btools.util.StackSampler;
|
||||
|
||||
public class RouteServer extends Thread implements Comparable<RouteServer> {
|
||||
public static final String PROFILE_UPLOAD_URL = "/brouter/profile";
|
||||
static final String HTTP_STATUS_OK = "200 OK";
|
||||
static final String HTTP_STATUS_BAD_REQUEST = "400 Bad Request";
|
||||
static final String HTTP_STATUS_FORBIDDEN = "403 Forbidden";
|
||||
static final String HTTP_STATUS_NOT_FOUND = "404 Not Found";
|
||||
static final String HTTP_STATUS_INTERNAL_SERVER_ERROR = "500 Internal Server Error";
|
||||
|
||||
public ServiceContext serviceContext;
|
||||
|
||||
private Socket clientSocket = null;
|
||||
private RoutingEngine cr = null;
|
||||
private volatile boolean terminated;
|
||||
private long starttime;
|
||||
|
||||
private static Object threadPoolSync = new Object();
|
||||
private static boolean debug = Boolean.getBoolean("debugThreadPool");
|
||||
|
||||
public void stopRouter() {
|
||||
RoutingEngine e = cr;
|
||||
if (e != null) e.terminate();
|
||||
}
|
||||
|
||||
private static DateFormat tsFormat = new SimpleDateFormat("dd.MM.yy HH:mm", new Locale("en", "US"));
|
||||
|
||||
private static String formattedTimeStamp(long t) {
|
||||
synchronized (tsFormat) {
|
||||
return tsFormat.format(new Date(System.currentTimeMillis()));
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
BufferedReader br = null;
|
||||
BufferedWriter bw = null;
|
||||
|
||||
// first line
|
||||
String getline = null;
|
||||
String sessionInfo = null;
|
||||
String sIp = null;
|
||||
|
||||
try {
|
||||
br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "UTF-8"));
|
||||
bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"));
|
||||
|
||||
String agent = null;
|
||||
String encodings = null;
|
||||
String xff = null; // X-Forwarded-For
|
||||
String referer = null;
|
||||
|
||||
// more headers until first empty line
|
||||
for (; ; ) {
|
||||
// headers
|
||||
String line = br.readLine();
|
||||
if (line == null) {
|
||||
writeHttpHeader(bw, HTTP_STATUS_BAD_REQUEST);
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
if (line.length() == 0) {
|
||||
break;
|
||||
}
|
||||
if (getline == null) {
|
||||
getline = line;
|
||||
}
|
||||
line = line.toLowerCase();
|
||||
if (line.startsWith("user-agent: ")) {
|
||||
agent = line.substring("user-agent: ".length());
|
||||
}
|
||||
if (line.startsWith("accept-encoding: ")) {
|
||||
encodings = line.substring("accept-encoding: ".length());
|
||||
}
|
||||
if (line.startsWith("x-forwarded-for: ")) {
|
||||
xff = line.substring("x-forwarded-for: ".length());
|
||||
}
|
||||
if (line.startsWith("Referer: ")) {
|
||||
referer = line.substring("Referer: ".length());
|
||||
}
|
||||
if (line.startsWith("Referrer: ")) {
|
||||
referer = line.substring("Referrer: ".length());
|
||||
}
|
||||
}
|
||||
|
||||
InetAddress ip = clientSocket.getInetAddress();
|
||||
sIp = xff == null ? (ip == null ? "null" : ip.toString()) : xff;
|
||||
boolean newSession = IpAccessMonitor.touchIpAccess(sIp);
|
||||
sessionInfo = " new";
|
||||
if (!newSession) {
|
||||
int sessionCount = IpAccessMonitor.getSessionCount();
|
||||
sessionInfo = " " + Math.min(sessionCount, 999);
|
||||
sessionInfo = sessionInfo.substring(sessionInfo.length() - 4);
|
||||
}
|
||||
|
||||
String excludedAgents = System.getProperty("excludedAgents");
|
||||
if (agent != null && excludedAgents != null) {
|
||||
StringTokenizer tk = new StringTokenizer(excludedAgents, ",");
|
||||
while (tk.hasMoreTokens()) {
|
||||
if (agent.indexOf(tk.nextToken()) >= 0) {
|
||||
writeHttpHeader(bw, HTTP_STATUS_FORBIDDEN);
|
||||
bw.write("Bad agent: " + agent);
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (referer != null && referer.indexOf("brouter.de/brouter-web") >= 0) {
|
||||
if (getline.indexOf("%7C") >= 0 && getline.indexOf("%2C") >= 0) {
|
||||
writeHttpHeader(bw, HTTP_STATUS_FORBIDDEN);
|
||||
bw.write("Spam? please stop");
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (getline.startsWith("GET /favicon.ico")) {
|
||||
writeHttpHeader(bw, HTTP_STATUS_NOT_FOUND);
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
if (getline.startsWith("GET /robots.txt")) {
|
||||
writeHttpHeader(bw, HTTP_STATUS_OK);
|
||||
bw.write("User-agent: *\n");
|
||||
bw.write("Disallow: /\n");
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
|
||||
String url = getline.split(" ")[1];
|
||||
HashMap<String, String> params = getUrlParams(url);
|
||||
|
||||
long maxRunningTime = getMaxRunningTime();
|
||||
|
||||
RequestHandler handler;
|
||||
if (params.containsKey("lonlats") && params.containsKey("profile")) {
|
||||
handler = new ServerHandler(serviceContext, params);
|
||||
} else if (url.startsWith(PROFILE_UPLOAD_URL)) {
|
||||
if (getline.startsWith("OPTIONS")) {
|
||||
// handle CORS preflight request (Safari)
|
||||
String corsHeaders = "Access-Control-Allow-Methods: GET, POST\n"
|
||||
+ "Access-Control-Allow-Headers: Content-Type\n";
|
||||
writeHttpHeader(bw, "text/plain", null, corsHeaders, HTTP_STATUS_OK);
|
||||
bw.flush();
|
||||
return;
|
||||
} else {
|
||||
writeHttpHeader(bw, "application/json", HTTP_STATUS_OK);
|
||||
|
||||
String profileId = null;
|
||||
if (url.length() > PROFILE_UPLOAD_URL.length() + 1) {
|
||||
// e.g. /brouter/profile/custom_1400767688382
|
||||
profileId = url.substring(PROFILE_UPLOAD_URL.length() + 1);
|
||||
}
|
||||
|
||||
ProfileUploadHandler uploadHandler = new ProfileUploadHandler(serviceContext);
|
||||
uploadHandler.handlePostRequest(profileId, br, bw);
|
||||
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
} else if (url.startsWith("/brouter/suspects")) {
|
||||
writeHttpHeader(bw, url.endsWith(".json") ? "application/json" : "text/html", HTTP_STATUS_OK);
|
||||
SuspectManager.process(url, bw);
|
||||
return;
|
||||
} else {
|
||||
writeHttpHeader(bw, HTTP_STATUS_NOT_FOUND);
|
||||
bw.flush();
|
||||
return;
|
||||
}
|
||||
RoutingContext rc = handler.readRoutingContext();
|
||||
List<OsmNodeNamed> wplist = handler.readWayPointList();
|
||||
|
||||
if (wplist.size() < 10) {
|
||||
SuspectManager.nearRecentWps.add(wplist);
|
||||
}
|
||||
for (Map.Entry<String, String> e : params.entrySet()) {
|
||||
if ("timode".equals(e.getKey())) {
|
||||
rc.turnInstructionMode = Integer.parseInt(e.getValue());
|
||||
} else if ("heading".equals(e.getKey())) {
|
||||
rc.startDirection = Integer.valueOf(Integer.parseInt(e.getValue()));
|
||||
rc.forceUseStartDirection = true;
|
||||
} else if (e.getKey().startsWith("profile:")) {
|
||||
if (rc.keyValues == null) {
|
||||
rc.keyValues = new HashMap<String, String>();
|
||||
}
|
||||
rc.keyValues.put(e.getKey().substring(8), e.getValue());
|
||||
}
|
||||
}
|
||||
cr = new RoutingEngine(null, null, serviceContext.segmentDir, wplist, rc);
|
||||
cr.quite = true;
|
||||
cr.doRun(maxRunningTime);
|
||||
|
||||
if (cr.getErrorMessage() != null) {
|
||||
writeHttpHeader(bw, HTTP_STATUS_BAD_REQUEST);
|
||||
bw.write(cr.getErrorMessage());
|
||||
bw.write("\n");
|
||||
} else {
|
||||
OsmTrack track = cr.getFoundTrack();
|
||||
|
||||
String headers = encodings == null || encodings.indexOf("gzip") < 0 ? null : "Content-Encoding: gzip\n";
|
||||
writeHttpHeader(bw, handler.getMimeType(), handler.getFileName(), headers, HTTP_STATUS_OK);
|
||||
if (track != null) {
|
||||
if (headers != null) // compressed
|
||||
{
|
||||
java.io.ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
Writer w = new OutputStreamWriter(new GZIPOutputStream(baos), "UTF-8");
|
||||
w.write(handler.formatTrack(track));
|
||||
w.close();
|
||||
bw.flush();
|
||||
clientSocket.getOutputStream().write(baos.toByteArray());
|
||||
} else {
|
||||
bw.write(handler.formatTrack(track));
|
||||
}
|
||||
}
|
||||
}
|
||||
bw.flush();
|
||||
} catch (Throwable e) {
|
||||
try {
|
||||
writeHttpHeader(bw, HTTP_STATUS_INTERNAL_SERVER_ERROR);
|
||||
bw.flush();
|
||||
} catch (IOException _ignore) {
|
||||
}
|
||||
System.out.println("RouteServer got exception (will continue): " + e);
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
cr = null;
|
||||
if (br != null) try {
|
||||
br.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
if (bw != null) try {
|
||||
bw.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
if (clientSocket != null) try {
|
||||
clientSocket.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
terminated = true;
|
||||
synchronized (threadPoolSync) {
|
||||
threadPoolSync.notifyAll();
|
||||
}
|
||||
long t = System.currentTimeMillis();
|
||||
long ms = t - starttime;
|
||||
System.out.println(formattedTimeStamp(t) + sessionInfo + " ip=" + sIp + " ms=" + ms + " -> " + getline);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("BRouter " + OsmTrack.version + " / " + OsmTrack.versionDate);
|
||||
if (args.length != 5 && args.length != 6) {
|
||||
System.out.println("serve BRouter protocol");
|
||||
System.out.println("usage: java RouteServer <segmentdir> <profiledir> <customprofiledir> <port> <maxthreads> [bindaddress]");
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceContext serviceContext = new ServiceContext();
|
||||
serviceContext.segmentDir = new File(args[0]);
|
||||
serviceContext.profileDir = args[1];
|
||||
System.setProperty("profileBaseDir", serviceContext.profileDir);
|
||||
String dirs = args[2];
|
||||
StringTokenizer tk = new StringTokenizer(dirs, ",");
|
||||
serviceContext.customProfileDir = tk.nextToken();
|
||||
serviceContext.sharedProfileDir = tk.hasMoreTokens() ? tk.nextToken() : serviceContext.customProfileDir;
|
||||
|
||||
int maxthreads = Integer.parseInt(args[4]);
|
||||
|
||||
ProfileCache.setSize(2 * maxthreads);
|
||||
|
||||
PriorityQueue<RouteServer> threadQueue = new PriorityQueue<RouteServer>();
|
||||
|
||||
ServerSocket serverSocket = args.length > 5 ? new ServerSocket(Integer.parseInt(args[3]), 100, InetAddress.getByName(args[5])) : new ServerSocket(Integer.parseInt(args[3]));
|
||||
|
||||
// stacksample for performance profiling
|
||||
// ( caution: start stacksampler only after successfully creating the server socket
|
||||
// because that thread prevents the process from terminating, so the start-attempt
|
||||
// by the watchdog cron would create zombies )
|
||||
File stackLog = new File("stacks.txt");
|
||||
if (stackLog.exists()) {
|
||||
StackSampler stackSampler = new StackSampler(stackLog, 1000);
|
||||
stackSampler.start();
|
||||
System.out.println("*** sampling stacks into stacks.txt *** ");
|
||||
}
|
||||
|
||||
for (; ; ) {
|
||||
Socket clientSocket = serverSocket.accept();
|
||||
RouteServer server = new RouteServer();
|
||||
server.serviceContext = serviceContext;
|
||||
server.clientSocket = clientSocket;
|
||||
server.starttime = System.currentTimeMillis();
|
||||
|
||||
// kill an old thread if thread limit reached
|
||||
|
||||
cleanupThreadQueue(threadQueue);
|
||||
|
||||
if (debug) System.out.println("threadQueue.size()=" + threadQueue.size());
|
||||
if (threadQueue.size() >= maxthreads) {
|
||||
synchronized (threadPoolSync) {
|
||||
// wait up to 2000ms (maybe notified earlier)
|
||||
// to prevent killing short-running threads
|
||||
long maxage = server.starttime - threadQueue.peek().starttime;
|
||||
long maxWaitTime = 2000L - maxage;
|
||||
if (debug) System.out.println("maxage=" + maxage + " maxWaitTime=" + maxWaitTime);
|
||||
if (debug) {
|
||||
for (RouteServer t : threadQueue) {
|
||||
System.out.println("age=" + (server.starttime - t.starttime));
|
||||
}
|
||||
}
|
||||
if (maxWaitTime > 0) {
|
||||
threadPoolSync.wait(maxWaitTime);
|
||||
}
|
||||
long t = System.currentTimeMillis();
|
||||
System.out.println(formattedTimeStamp(t) + " contention! ms waited " + (t - server.starttime));
|
||||
}
|
||||
cleanupThreadQueue(threadQueue);
|
||||
if (threadQueue.size() >= maxthreads) {
|
||||
if (debug) System.out.println("stopping oldest thread...");
|
||||
// no way... stop the oldest thread
|
||||
RouteServer oldest = threadQueue.poll();
|
||||
oldest.stopRouter();
|
||||
long t = System.currentTimeMillis();
|
||||
System.out.println(formattedTimeStamp(t) + " contention! ms killed " + (t - oldest.starttime));
|
||||
}
|
||||
}
|
||||
|
||||
threadQueue.add(server);
|
||||
|
||||
server.start();
|
||||
if (debug) System.out.println("thread started...");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static HashMap<String, String> getUrlParams(String url) throws UnsupportedEncodingException {
|
||||
HashMap<String, String> params = new HashMap<String, String>();
|
||||
String decoded = URLDecoder.decode(url, "UTF-8");
|
||||
StringTokenizer tk = new StringTokenizer(decoded, "?&");
|
||||
while (tk.hasMoreTokens()) {
|
||||
String t = tk.nextToken();
|
||||
StringTokenizer tk2 = new StringTokenizer(t, "=");
|
||||
if (tk2.hasMoreTokens()) {
|
||||
String key = tk2.nextToken();
|
||||
if (tk2.hasMoreTokens()) {
|
||||
String value = tk2.nextToken();
|
||||
params.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
private static long getMaxRunningTime() {
|
||||
long maxRunningTime = 60000;
|
||||
String sMaxRunningTime = System.getProperty("maxRunningTime");
|
||||
if (sMaxRunningTime != null) {
|
||||
maxRunningTime = Integer.parseInt(sMaxRunningTime) * 1000;
|
||||
}
|
||||
return maxRunningTime;
|
||||
}
|
||||
|
||||
private static void writeHttpHeader(BufferedWriter bw, String status) throws IOException {
|
||||
writeHttpHeader(bw, "text/plain", status);
|
||||
}
|
||||
|
||||
private static void writeHttpHeader(BufferedWriter bw, String mimeType, String status) throws IOException {
|
||||
writeHttpHeader(bw, mimeType, null, status);
|
||||
}
|
||||
|
||||
private static void writeHttpHeader(BufferedWriter bw, String mimeType, String fileName, String status) throws IOException {
|
||||
writeHttpHeader(bw, mimeType, fileName, null, status);
|
||||
}
|
||||
|
||||
private static void writeHttpHeader(BufferedWriter bw, String mimeType, String fileName, String headers, String status) throws IOException {
|
||||
// http-header
|
||||
bw.write(String.format("HTTP/1.1 %s\n", status));
|
||||
bw.write("Connection: close\n");
|
||||
bw.write("Content-Type: " + mimeType + "; charset=utf-8\n");
|
||||
if (fileName != null) {
|
||||
bw.write("Content-Disposition: attachment; filename=\"" + fileName + "\"\n");
|
||||
}
|
||||
bw.write("Access-Control-Allow-Origin: *\n");
|
||||
if (headers != null) {
|
||||
bw.write(headers);
|
||||
}
|
||||
bw.write("\n");
|
||||
}
|
||||
|
||||
private static void cleanupThreadQueue(PriorityQueue<RouteServer> threadQueue) {
|
||||
for (; ; ) {
|
||||
boolean removedItem = false;
|
||||
for (RouteServer t : threadQueue) {
|
||||
if (t.terminated) {
|
||||
threadQueue.remove(t);
|
||||
removedItem = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!removedItem) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(RouteServer t) {
|
||||
return starttime < t.starttime ? -1 : (starttime > t.starttime ? 1 : 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,19 @@
|
|||
package btools.server;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.io.File;
|
||||
|
||||
import btools.router.OsmNodeNamed;
|
||||
|
||||
/**
|
||||
* Environment configuration that is initialized at server/service startup
|
||||
*/
|
||||
public class ServiceContext
|
||||
{
|
||||
public File segmentDir;
|
||||
public String profileDir;
|
||||
public String customProfileDir;
|
||||
public String sharedProfileDir;
|
||||
public Map<String,String> profileMap = null;
|
||||
public List<OsmNodeNamed> nogoList;
|
||||
}
|
||||
package btools.server;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.io.File;
|
||||
|
||||
import btools.router.OsmNodeNamed;
|
||||
|
||||
/**
|
||||
* Environment configuration that is initialized at server/service startup
|
||||
*/
|
||||
public class ServiceContext {
|
||||
public File segmentDir;
|
||||
public String profileDir;
|
||||
public String customProfileDir;
|
||||
public String sharedProfileDir;
|
||||
public Map<String, String> profileMap = null;
|
||||
public List<OsmNodeNamed> nogoList;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -3,6 +3,7 @@ package btools.server.request;
|
|||
import btools.router.RoutingContext;
|
||||
import btools.router.RoutingEngine;
|
||||
import btools.server.ServiceContext;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
|
|
@ -15,8 +16,7 @@ import java.util.Map;
|
|||
/**
|
||||
* Custom profile uploads
|
||||
*/
|
||||
public class ProfileUploadHandler
|
||||
{
|
||||
public class ProfileUploadHandler {
|
||||
// maximum number of characters (file size limit for custom profiles)
|
||||
private static final int MAX_LENGTH = 100000;
|
||||
|
||||
|
|
@ -24,29 +24,25 @@ public class ProfileUploadHandler
|
|||
public static final String CUSTOM_PREFIX = "custom_";
|
||||
public static final String SHARED_PREFIX = "shared_";
|
||||
|
||||
private ServiceContext serviceContext;
|
||||
|
||||
public ProfileUploadHandler( ServiceContext serviceContext)
|
||||
{
|
||||
this.serviceContext = serviceContext;
|
||||
}
|
||||
private ServiceContext serviceContext;
|
||||
|
||||
public void handlePostRequest(String profileId, BufferedReader br, BufferedWriter response) throws IOException
|
||||
{
|
||||
public ProfileUploadHandler(ServiceContext serviceContext) {
|
||||
this.serviceContext = serviceContext;
|
||||
}
|
||||
|
||||
public void handlePostRequest(String profileId, BufferedReader br, BufferedWriter response) throws IOException {
|
||||
BufferedWriter fileWriter = null;
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
String id;
|
||||
if ( profileId != null )
|
||||
{
|
||||
if (profileId != null) {
|
||||
// update existing file when id appended
|
||||
id = profileId.substring( ProfileUploadHandler.CUSTOM_PREFIX.length() );
|
||||
id = profileId.substring(ProfileUploadHandler.CUSTOM_PREFIX.length());
|
||||
} else {
|
||||
id = "" + System.currentTimeMillis();
|
||||
}
|
||||
File file = new File( getOrCreateCustomProfileDir(), id + ".brf" );
|
||||
fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream( file ) ) );
|
||||
File file = new File(getOrCreateCustomProfileDir(), id + ".brf");
|
||||
fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
|
||||
//StringWriter sw = new StringWriter(); bw = new BufferedWriter(sw);
|
||||
|
||||
// only profile text as content
|
||||
|
|
@ -56,57 +52,56 @@ public class ProfileUploadHandler
|
|||
//System.out.println("data: |" + sw.toString() + "|");
|
||||
|
||||
Map<String, String> responseData = new HashMap<String, String>();
|
||||
responseData.put( "profileid", CUSTOM_PREFIX + id );
|
||||
responseData.put("profileid", CUSTOM_PREFIX + id);
|
||||
|
||||
validateProfile( id, responseData );
|
||||
validateProfile(id, responseData);
|
||||
|
||||
response.write( toJSON( responseData ) );
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ( fileWriter != null ) try { fileWriter.close(); } catch( Exception e ) {}
|
||||
response.write(toJSON(responseData));
|
||||
} finally {
|
||||
if (fileWriter != null) try {
|
||||
fileWriter.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private File getOrCreateCustomProfileDir()
|
||||
{
|
||||
private File getOrCreateCustomProfileDir() {
|
||||
// workaround: customProfileDir relative to profileDir, because RoutingEngine doesn't know custom profiles
|
||||
File customProfileDir = new File(serviceContext.profileDir, serviceContext.customProfileDir);
|
||||
if (!customProfileDir.exists())
|
||||
{
|
||||
if (!customProfileDir.exists()) {
|
||||
customProfileDir.mkdir();
|
||||
}
|
||||
return customProfileDir;
|
||||
}
|
||||
|
||||
// reads HTTP POST content from input into output stream/writer
|
||||
private static void readPostData( BufferedReader ir, BufferedWriter bw, String id ) throws IOException
|
||||
{
|
||||
private static void readPostData(BufferedReader ir, BufferedWriter bw, String id) throws IOException {
|
||||
// Content-Type: text/plain;charset=UTF-8
|
||||
|
||||
int numChars = 0;
|
||||
|
||||
// Content-Length header is in bytes (!= characters for UTF8),
|
||||
// but Reader reads characters, so don't know number of characters to read
|
||||
for(;;)
|
||||
{
|
||||
for (; ; ) {
|
||||
// read will block when false, occurs at end of stream rather than -1
|
||||
if (!ir.ready()) {
|
||||
try { Thread.sleep(1000); } catch( Exception e ) {}
|
||||
if ( !ir.ready() ) break;
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
if (!ir.ready()) break;
|
||||
}
|
||||
int c = ir.read();
|
||||
if ( c == -1) break;
|
||||
bw.write( c );
|
||||
|
||||
if (c == -1) break;
|
||||
bw.write(c);
|
||||
|
||||
numChars++;
|
||||
if (numChars > MAX_LENGTH)
|
||||
throw new IOException("Maximum number of characters exceeded (" + MAX_LENGTH + ", " + id + ")");
|
||||
}
|
||||
}
|
||||
|
||||
private String toJSON( Map<String, String> data )
|
||||
{
|
||||
private String toJSON(Map<String, String> data) {
|
||||
boolean first = true;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{");
|
||||
|
|
@ -123,29 +118,22 @@ public class ProfileUploadHandler
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
public void validateProfile(String id, Map<String, String> responseData)
|
||||
{
|
||||
public void validateProfile(String id, Map<String, String> responseData) {
|
||||
// validate by initializing RoutingEngine, where parsing is done, and catching exceptions
|
||||
// see https://github.com/abrensch/brouter/issues/14
|
||||
try
|
||||
{
|
||||
try {
|
||||
RoutingContext rc = new RoutingContext();
|
||||
rc.localFunction = serviceContext.customProfileDir + "/" + id;
|
||||
new RoutingEngine( null, null, null, null, rc );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
rc.localFunction = serviceContext.customProfileDir + "/" + id;
|
||||
new RoutingEngine(null, null, null, null, rc);
|
||||
} catch (Exception e) {
|
||||
String msg = e.getMessage();
|
||||
if ( msg == null )
|
||||
{
|
||||
if (msg == null) {
|
||||
msg = "";
|
||||
}
|
||||
else if ( msg.indexOf( "does not contain expressions for context" ) >= 0 )
|
||||
{
|
||||
} else if (msg.indexOf("does not contain expressions for context") >= 0) {
|
||||
// remove absolute path in this specific exception, useful for server, but don't disclose to client
|
||||
msg = msg.substring( msg.indexOf( "does not contain expressions for context" ) );
|
||||
msg = msg.substring(msg.indexOf("does not contain expressions for context"));
|
||||
}
|
||||
responseData.put( "error", "Profile error: " + msg );
|
||||
responseData.put("error", "Profile error: " + msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,29 @@
|
|||
package btools.server.request;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import btools.router.OsmNodeNamed;
|
||||
import btools.router.OsmTrack;
|
||||
import btools.router.RoutingContext;
|
||||
import btools.server.ServiceContext;
|
||||
|
||||
public abstract class RequestHandler
|
||||
{
|
||||
protected ServiceContext serviceContext;
|
||||
protected HashMap<String,String> params;
|
||||
|
||||
public RequestHandler( ServiceContext serviceContext, HashMap<String,String> params )
|
||||
{
|
||||
this.serviceContext = serviceContext;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public abstract RoutingContext readRoutingContext();
|
||||
|
||||
public abstract List<OsmNodeNamed> readWayPointList();
|
||||
|
||||
public abstract String formatTrack(OsmTrack track);
|
||||
|
||||
public abstract String getMimeType();
|
||||
|
||||
public abstract String getFileName();
|
||||
}
|
||||
package btools.server.request;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import btools.router.OsmNodeNamed;
|
||||
import btools.router.OsmTrack;
|
||||
import btools.router.RoutingContext;
|
||||
import btools.server.ServiceContext;
|
||||
|
||||
public abstract class RequestHandler {
|
||||
protected ServiceContext serviceContext;
|
||||
protected HashMap<String, String> params;
|
||||
|
||||
public RequestHandler(ServiceContext serviceContext, HashMap<String, String> params) {
|
||||
this.serviceContext = serviceContext;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public abstract RoutingContext readRoutingContext();
|
||||
|
||||
public abstract List<OsmNodeNamed> readWayPointList();
|
||||
|
||||
public abstract String formatTrack(OsmTrack track);
|
||||
|
||||
public abstract String getMimeType();
|
||||
|
||||
public abstract String getFileName();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,343 +1,293 @@
|
|||
package btools.server.request;
|
||||
|
||||
import btools.mapaccess.OsmNode;
|
||||
import btools.router.OsmNodeNamed;
|
||||
import btools.router.OsmNogoPolygon;
|
||||
import btools.router.OsmTrack;
|
||||
import btools.router.RoutingContext;
|
||||
import btools.server.ServiceContext;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* URL query parameter handler for web and standalone server. Supports all
|
||||
* BRouter features without restrictions.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* lonlats = lon,lat|... (unlimited list of lon,lat waypoints separated by |)
|
||||
* nogos = lon,lat,radius|... (optional, radius in meters)
|
||||
* profile = profile file name without .brf
|
||||
* alternativeidx = [0|1|2|3] (optional, default 0)
|
||||
* format = [kml|gpx|geojson] (optional, default gpx)
|
||||
* trackname = name used for filename and format specific trackname (optional, default brouter)
|
||||
* exportWaypoints = 1 to export them (optional, default is no export)
|
||||
* pois = lon,lat,name|... (optional)
|
||||
*
|
||||
* Example URLs:
|
||||
* {@code http://localhost:17777/brouter?lonlats=8.799297,49.565883|8.811764,49.563606&nogos=&profile=trekking&alternativeidx=0&format=gpx}
|
||||
* {@code http://localhost:17777/brouter?lonlats=1.1,1.2|2.1,2.2|3.1,3.2|4.1,4.2&nogos=-1.1,-1.2,1|-2.1,-2.2,2&profile=shortest&alternativeidx=1&format=kml&trackname=Ride&pois=1.1,2.1,Barner Bar}
|
||||
*
|
||||
*/
|
||||
public class ServerHandler extends RequestHandler {
|
||||
|
||||
private RoutingContext rc;
|
||||
|
||||
public ServerHandler( ServiceContext serviceContext, HashMap<String, String> params )
|
||||
{
|
||||
super( serviceContext, params );
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoutingContext readRoutingContext()
|
||||
{
|
||||
rc = new RoutingContext();
|
||||
rc.memoryclass = 128;
|
||||
|
||||
String profile = params.get( "profile" );
|
||||
// when custom profile replace prefix with directory path
|
||||
if ( profile.startsWith( ProfileUploadHandler.CUSTOM_PREFIX ) )
|
||||
{
|
||||
String customProfile = profile.substring( ProfileUploadHandler.CUSTOM_PREFIX.length() );
|
||||
profile = new File( serviceContext.customProfileDir, customProfile ).getPath();
|
||||
}
|
||||
else if ( profile.startsWith( ProfileUploadHandler.SHARED_PREFIX ) )
|
||||
{
|
||||
String customProfile = profile.substring( ProfileUploadHandler.SHARED_PREFIX.length() );
|
||||
profile = new File( serviceContext.sharedProfileDir, customProfile ).getPath();
|
||||
}
|
||||
rc.localFunction = profile;
|
||||
|
||||
rc.setAlternativeIdx(Integer.parseInt(params.get( "alternativeidx" )));
|
||||
|
||||
List<OsmNodeNamed> poisList = readPoisList();
|
||||
rc.poipoints = poisList;
|
||||
|
||||
List<OsmNodeNamed> nogoList = readNogoList();
|
||||
List<OsmNodeNamed> nogoPolygonsList = readNogoPolygons();
|
||||
|
||||
if ( nogoList != null )
|
||||
{
|
||||
RoutingContext.prepareNogoPoints( nogoList );
|
||||
rc.nogopoints = nogoList;
|
||||
}
|
||||
|
||||
if (rc.nogopoints == null)
|
||||
{
|
||||
rc.nogopoints = nogoPolygonsList;
|
||||
}
|
||||
else if ( nogoPolygonsList != null )
|
||||
{
|
||||
rc.nogopoints.addAll(nogoPolygonsList);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OsmNodeNamed> readWayPointList()
|
||||
{
|
||||
// lon,lat|...
|
||||
String lonLats = params.get( "lonlats" );
|
||||
if (lonLats == null) throw new IllegalArgumentException( "lonlats parameter not set" );
|
||||
|
||||
String[] coords = lonLats.split("\\|");
|
||||
if (coords.length < 2)
|
||||
throw new IllegalArgumentException( "we need two lat/lon points at least!" );
|
||||
|
||||
List<OsmNodeNamed> wplist = new ArrayList<OsmNodeNamed>();
|
||||
for (int i = 0; i < coords.length; i++)
|
||||
{
|
||||
String[] lonLat = coords[i].split(",");
|
||||
if (lonLat.length < 2)
|
||||
throw new IllegalArgumentException( "we need two lat/lon points at least!" );
|
||||
wplist.add( readPosition( lonLat[0], lonLat[1], "via" + i ) );
|
||||
}
|
||||
|
||||
wplist.get(0).name = "from";
|
||||
wplist.get(wplist.size()-1).name = "to";
|
||||
|
||||
return wplist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatTrack(OsmTrack track)
|
||||
{
|
||||
String result;
|
||||
// optional, may be null
|
||||
String format = params.get( "format" );
|
||||
String trackName = getTrackName();
|
||||
if (trackName != null) {
|
||||
track.name = trackName;
|
||||
}
|
||||
String exportWaypointsStr = params.get( "exportWaypoints" );
|
||||
if (exportWaypointsStr != null && Integer.parseInt(exportWaypointsStr) != 0) {
|
||||
track.exportWaypoints = true;
|
||||
}
|
||||
|
||||
if (format == null || "gpx".equals(format))
|
||||
{
|
||||
result = track.formatAsGpx();
|
||||
}
|
||||
else if ("kml".equals(format))
|
||||
{
|
||||
result = track.formatAsKml();
|
||||
}
|
||||
else if ("geojson".equals(format))
|
||||
{
|
||||
result = track.formatAsGeoJson();
|
||||
}
|
||||
else if ("csv".equals(format))
|
||||
{
|
||||
try
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
BufferedWriter bw = new BufferedWriter(sw);
|
||||
track.writeMessages( bw, rc );
|
||||
return sw.toString();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return "Error: " + ex.getMessage();
|
||||
}
|
||||
}
|
||||
else {
|
||||
System.out.println("unknown track format '" + format + "', using default");
|
||||
result = track.formatAsGpx();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMimeType()
|
||||
{
|
||||
// default
|
||||
String result = "text/plain";
|
||||
|
||||
// optional, may be null
|
||||
String format = params.get( "format" );
|
||||
if ( format != null )
|
||||
{
|
||||
if ( "gpx".equals( format ) )
|
||||
{
|
||||
result = "application/gpx+xml";
|
||||
}
|
||||
else if ( "kml".equals( format ) )
|
||||
{
|
||||
result = "application/vnd.google-earth.kml+xml";
|
||||
}
|
||||
else if ( "geojson".equals( format ) )
|
||||
{
|
||||
result = "application/vnd.geo+json";
|
||||
}
|
||||
else if ( "csv".equals( format ) )
|
||||
{
|
||||
result = "text/tab-separated-values";
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileName()
|
||||
{
|
||||
String fileName = null;
|
||||
String format = params.get( "format" );
|
||||
String trackName = getTrackName();
|
||||
|
||||
if ( format != null )
|
||||
{
|
||||
fileName = ( trackName == null ? "brouter" : trackName ) + "." + format;
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private String getTrackName()
|
||||
{
|
||||
return params.get( "trackname" ) == null ? null : params.get( "trackname" ).replaceAll("[^a-zA-Z0-9 \\._\\-]+", "");
|
||||
}
|
||||
|
||||
private static OsmNodeNamed readPosition( String vlon, String vlat, String name )
|
||||
{
|
||||
if ( vlon == null ) throw new IllegalArgumentException( "lon " + name + " not found in input" );
|
||||
if ( vlat == null ) throw new IllegalArgumentException( "lat " + name + " not found in input" );
|
||||
|
||||
return readPosition(Double.parseDouble( vlon ), Double.parseDouble( vlat ), name);
|
||||
}
|
||||
|
||||
private static OsmNodeNamed readPosition( double lon, double lat, String name )
|
||||
{
|
||||
OsmNodeNamed n = new OsmNodeNamed();
|
||||
n.name = name;
|
||||
n.ilon = (int)( ( lon + 180. ) *1000000. + 0.5);
|
||||
n.ilat = (int)( ( lat + 90. ) *1000000. + 0.5);
|
||||
return n;
|
||||
}
|
||||
|
||||
private List<OsmNodeNamed> readPoisList()
|
||||
{
|
||||
// lon,lat,name|...
|
||||
String pois = params.get( "pois" );
|
||||
if ( pois == null ) return null;
|
||||
|
||||
String[] lonLatNameList = pois.split("\\|");
|
||||
|
||||
List<OsmNodeNamed> poisList = new ArrayList<OsmNodeNamed>();
|
||||
for (int i = 0; i < lonLatNameList.length; i++)
|
||||
{
|
||||
String[] lonLatName = lonLatNameList[i].split(",");
|
||||
|
||||
if (lonLatName.length != 3)
|
||||
continue;
|
||||
|
||||
OsmNodeNamed n = new OsmNodeNamed();
|
||||
n.ilon = (int)( ( Double.parseDouble(lonLatName[0]) + 180. ) *1000000. + 0.5);
|
||||
n.ilat = (int)( ( Double.parseDouble(lonLatName[1]) + 90. ) *1000000. + 0.5);
|
||||
n.name = lonLatName[2];
|
||||
poisList.add(n);
|
||||
}
|
||||
|
||||
return poisList;
|
||||
}
|
||||
|
||||
private List<OsmNodeNamed> readNogoList()
|
||||
{
|
||||
// lon,lat,radius|...
|
||||
String nogos = params.get( "nogos" );
|
||||
if ( nogos == null ) return null;
|
||||
|
||||
String[] lonLatRadList = nogos.split("\\|");
|
||||
|
||||
List<OsmNodeNamed> nogoList = new ArrayList<OsmNodeNamed>();
|
||||
for (int i = 0; i < lonLatRadList.length; i++)
|
||||
{
|
||||
String[] lonLatRad = lonLatRadList[i].split(",");
|
||||
String nogoWeight = "NaN";
|
||||
if (lonLatRad.length > 3) {
|
||||
nogoWeight = lonLatRad[3];
|
||||
}
|
||||
nogoList.add(readNogo(lonLatRad[0], lonLatRad[1], lonLatRad[2], nogoWeight));
|
||||
}
|
||||
|
||||
return nogoList;
|
||||
}
|
||||
|
||||
private static OsmNodeNamed readNogo( String lon, String lat, String radius, String nogoWeight )
|
||||
{
|
||||
double weight = "undefined".equals( nogoWeight ) ? Double.NaN : Double.parseDouble( nogoWeight );
|
||||
return readNogo(Double.parseDouble( lon ), Double.parseDouble( lat ), Integer.parseInt( radius ), weight );
|
||||
}
|
||||
|
||||
private static OsmNodeNamed readNogo( double lon, double lat, int radius, double nogoWeight )
|
||||
{
|
||||
OsmNodeNamed n = new OsmNodeNamed();
|
||||
n.name = "nogo" + radius;
|
||||
n.ilon = (int)( ( lon + 180. ) *1000000. + 0.5);
|
||||
n.ilat = (int)( ( lat + 90. ) *1000000. + 0.5);
|
||||
n.isNogo = true;
|
||||
n.nogoWeight = nogoWeight;
|
||||
return n;
|
||||
}
|
||||
|
||||
private List<OsmNodeNamed> readNogoPolygons()
|
||||
{
|
||||
List<OsmNodeNamed> result = new ArrayList<OsmNodeNamed>();
|
||||
parseNogoPolygons( params.get("polylines"), result, false );
|
||||
parseNogoPolygons( params.get("polygons"), result, true );
|
||||
return result.size() > 0 ? result : null;
|
||||
}
|
||||
|
||||
private static void parseNogoPolygons(String polygons, List<OsmNodeNamed> result, boolean closed )
|
||||
{
|
||||
if ( polygons != null )
|
||||
{
|
||||
String[] polygonList = polygons.split("\\|");
|
||||
for (int i = 0; i < polygonList.length; i++)
|
||||
{
|
||||
String[] lonLatList = polygonList[i].split(",");
|
||||
if ( lonLatList.length > 1 )
|
||||
{
|
||||
OsmNogoPolygon polygon = new OsmNogoPolygon(closed);
|
||||
int j;
|
||||
for (j = 0; j < 2 * (lonLatList.length / 2) - 1;)
|
||||
{
|
||||
String slon = lonLatList[j++];
|
||||
String slat = lonLatList[j++];
|
||||
int lon = (int)( ( Double.parseDouble(slon) + 180. ) *1000000. + 0.5);
|
||||
int lat = (int)( ( Double.parseDouble(slat) + 90. ) *1000000. + 0.5);
|
||||
polygon.addVertex(lon, lat);
|
||||
}
|
||||
|
||||
String nogoWeight = "NaN";
|
||||
if (j < lonLatList.length) {
|
||||
nogoWeight = lonLatList[j];
|
||||
}
|
||||
polygon.nogoWeight = Double.parseDouble( nogoWeight );
|
||||
|
||||
if ( polygon.points.size() > 0 )
|
||||
{
|
||||
polygon.calcBoundingCircle();
|
||||
result.add(polygon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
package btools.server.request;
|
||||
|
||||
import btools.mapaccess.OsmNode;
|
||||
import btools.router.OsmNodeNamed;
|
||||
import btools.router.OsmNogoPolygon;
|
||||
import btools.router.OsmTrack;
|
||||
import btools.router.RoutingContext;
|
||||
import btools.server.ServiceContext;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* URL query parameter handler for web and standalone server. Supports all
|
||||
* BRouter features without restrictions.
|
||||
* <p>
|
||||
* Parameters:
|
||||
* <p>
|
||||
* lonlats = lon,lat|... (unlimited list of lon,lat waypoints separated by |)
|
||||
* nogos = lon,lat,radius|... (optional, radius in meters)
|
||||
* profile = profile file name without .brf
|
||||
* alternativeidx = [0|1|2|3] (optional, default 0)
|
||||
* format = [kml|gpx|geojson] (optional, default gpx)
|
||||
* trackname = name used for filename and format specific trackname (optional, default brouter)
|
||||
* exportWaypoints = 1 to export them (optional, default is no export)
|
||||
* pois = lon,lat,name|... (optional)
|
||||
* <p>
|
||||
* Example URLs:
|
||||
* {@code http://localhost:17777/brouter?lonlats=8.799297,49.565883|8.811764,49.563606&nogos=&profile=trekking&alternativeidx=0&format=gpx}
|
||||
* {@code http://localhost:17777/brouter?lonlats=1.1,1.2|2.1,2.2|3.1,3.2|4.1,4.2&nogos=-1.1,-1.2,1|-2.1,-2.2,2&profile=shortest&alternativeidx=1&format=kml&trackname=Ride&pois=1.1,2.1,Barner Bar}
|
||||
*/
|
||||
public class ServerHandler extends RequestHandler {
|
||||
|
||||
private RoutingContext rc;
|
||||
|
||||
public ServerHandler(ServiceContext serviceContext, HashMap<String, String> params) {
|
||||
super(serviceContext, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoutingContext readRoutingContext() {
|
||||
rc = new RoutingContext();
|
||||
rc.memoryclass = 128;
|
||||
|
||||
String profile = params.get("profile");
|
||||
// when custom profile replace prefix with directory path
|
||||
if (profile.startsWith(ProfileUploadHandler.CUSTOM_PREFIX)) {
|
||||
String customProfile = profile.substring(ProfileUploadHandler.CUSTOM_PREFIX.length());
|
||||
profile = new File(serviceContext.customProfileDir, customProfile).getPath();
|
||||
} else if (profile.startsWith(ProfileUploadHandler.SHARED_PREFIX)) {
|
||||
String customProfile = profile.substring(ProfileUploadHandler.SHARED_PREFIX.length());
|
||||
profile = new File(serviceContext.sharedProfileDir, customProfile).getPath();
|
||||
}
|
||||
rc.localFunction = profile;
|
||||
|
||||
rc.setAlternativeIdx(Integer.parseInt(params.get("alternativeidx")));
|
||||
|
||||
List<OsmNodeNamed> poisList = readPoisList();
|
||||
rc.poipoints = poisList;
|
||||
|
||||
List<OsmNodeNamed> nogoList = readNogoList();
|
||||
List<OsmNodeNamed> nogoPolygonsList = readNogoPolygons();
|
||||
|
||||
if (nogoList != null) {
|
||||
RoutingContext.prepareNogoPoints(nogoList);
|
||||
rc.nogopoints = nogoList;
|
||||
}
|
||||
|
||||
if (rc.nogopoints == null) {
|
||||
rc.nogopoints = nogoPolygonsList;
|
||||
} else if (nogoPolygonsList != null) {
|
||||
rc.nogopoints.addAll(nogoPolygonsList);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OsmNodeNamed> readWayPointList() {
|
||||
// lon,lat|...
|
||||
String lonLats = params.get("lonlats");
|
||||
if (lonLats == null) throw new IllegalArgumentException("lonlats parameter not set");
|
||||
|
||||
String[] coords = lonLats.split("\\|");
|
||||
if (coords.length < 2)
|
||||
throw new IllegalArgumentException("we need two lat/lon points at least!");
|
||||
|
||||
List<OsmNodeNamed> wplist = new ArrayList<OsmNodeNamed>();
|
||||
for (int i = 0; i < coords.length; i++) {
|
||||
String[] lonLat = coords[i].split(",");
|
||||
if (lonLat.length < 2)
|
||||
throw new IllegalArgumentException("we need two lat/lon points at least!");
|
||||
wplist.add(readPosition(lonLat[0], lonLat[1], "via" + i));
|
||||
}
|
||||
|
||||
wplist.get(0).name = "from";
|
||||
wplist.get(wplist.size() - 1).name = "to";
|
||||
|
||||
return wplist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatTrack(OsmTrack track) {
|
||||
String result;
|
||||
// optional, may be null
|
||||
String format = params.get("format");
|
||||
String trackName = getTrackName();
|
||||
if (trackName != null) {
|
||||
track.name = trackName;
|
||||
}
|
||||
String exportWaypointsStr = params.get("exportWaypoints");
|
||||
if (exportWaypointsStr != null && Integer.parseInt(exportWaypointsStr) != 0) {
|
||||
track.exportWaypoints = true;
|
||||
}
|
||||
|
||||
if (format == null || "gpx".equals(format)) {
|
||||
result = track.formatAsGpx();
|
||||
} else if ("kml".equals(format)) {
|
||||
result = track.formatAsKml();
|
||||
} else if ("geojson".equals(format)) {
|
||||
result = track.formatAsGeoJson();
|
||||
} else if ("csv".equals(format)) {
|
||||
try {
|
||||
StringWriter sw = new StringWriter();
|
||||
BufferedWriter bw = new BufferedWriter(sw);
|
||||
track.writeMessages(bw, rc);
|
||||
return sw.toString();
|
||||
} catch (Exception ex) {
|
||||
return "Error: " + ex.getMessage();
|
||||
}
|
||||
} else {
|
||||
System.out.println("unknown track format '" + format + "', using default");
|
||||
result = track.formatAsGpx();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMimeType() {
|
||||
// default
|
||||
String result = "text/plain";
|
||||
|
||||
// optional, may be null
|
||||
String format = params.get("format");
|
||||
if (format != null) {
|
||||
if ("gpx".equals(format)) {
|
||||
result = "application/gpx+xml";
|
||||
} else if ("kml".equals(format)) {
|
||||
result = "application/vnd.google-earth.kml+xml";
|
||||
} else if ("geojson".equals(format)) {
|
||||
result = "application/vnd.geo+json";
|
||||
} else if ("csv".equals(format)) {
|
||||
result = "text/tab-separated-values";
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileName() {
|
||||
String fileName = null;
|
||||
String format = params.get("format");
|
||||
String trackName = getTrackName();
|
||||
|
||||
if (format != null) {
|
||||
fileName = (trackName == null ? "brouter" : trackName) + "." + format;
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private String getTrackName() {
|
||||
return params.get("trackname") == null ? null : params.get("trackname").replaceAll("[^a-zA-Z0-9 \\._\\-]+", "");
|
||||
}
|
||||
|
||||
private static OsmNodeNamed readPosition(String vlon, String vlat, String name) {
|
||||
if (vlon == null) throw new IllegalArgumentException("lon " + name + " not found in input");
|
||||
if (vlat == null) throw new IllegalArgumentException("lat " + name + " not found in input");
|
||||
|
||||
return readPosition(Double.parseDouble(vlon), Double.parseDouble(vlat), name);
|
||||
}
|
||||
|
||||
private static OsmNodeNamed readPosition(double lon, double lat, String name) {
|
||||
OsmNodeNamed n = new OsmNodeNamed();
|
||||
n.name = name;
|
||||
n.ilon = (int) ((lon + 180.) * 1000000. + 0.5);
|
||||
n.ilat = (int) ((lat + 90.) * 1000000. + 0.5);
|
||||
return n;
|
||||
}
|
||||
|
||||
private List<OsmNodeNamed> readPoisList() {
|
||||
// lon,lat,name|...
|
||||
String pois = params.get("pois");
|
||||
if (pois == null) return null;
|
||||
|
||||
String[] lonLatNameList = pois.split("\\|");
|
||||
|
||||
List<OsmNodeNamed> poisList = new ArrayList<OsmNodeNamed>();
|
||||
for (int i = 0; i < lonLatNameList.length; i++) {
|
||||
String[] lonLatName = lonLatNameList[i].split(",");
|
||||
|
||||
if (lonLatName.length != 3)
|
||||
continue;
|
||||
|
||||
OsmNodeNamed n = new OsmNodeNamed();
|
||||
n.ilon = (int) ((Double.parseDouble(lonLatName[0]) + 180.) * 1000000. + 0.5);
|
||||
n.ilat = (int) ((Double.parseDouble(lonLatName[1]) + 90.) * 1000000. + 0.5);
|
||||
n.name = lonLatName[2];
|
||||
poisList.add(n);
|
||||
}
|
||||
|
||||
return poisList;
|
||||
}
|
||||
|
||||
private List<OsmNodeNamed> readNogoList() {
|
||||
// lon,lat,radius|...
|
||||
String nogos = params.get("nogos");
|
||||
if (nogos == null) return null;
|
||||
|
||||
String[] lonLatRadList = nogos.split("\\|");
|
||||
|
||||
List<OsmNodeNamed> nogoList = new ArrayList<OsmNodeNamed>();
|
||||
for (int i = 0; i < lonLatRadList.length; i++) {
|
||||
String[] lonLatRad = lonLatRadList[i].split(",");
|
||||
String nogoWeight = "NaN";
|
||||
if (lonLatRad.length > 3) {
|
||||
nogoWeight = lonLatRad[3];
|
||||
}
|
||||
nogoList.add(readNogo(lonLatRad[0], lonLatRad[1], lonLatRad[2], nogoWeight));
|
||||
}
|
||||
|
||||
return nogoList;
|
||||
}
|
||||
|
||||
private static OsmNodeNamed readNogo(String lon, String lat, String radius, String nogoWeight) {
|
||||
double weight = "undefined".equals(nogoWeight) ? Double.NaN : Double.parseDouble(nogoWeight);
|
||||
return readNogo(Double.parseDouble(lon), Double.parseDouble(lat), Integer.parseInt(radius), weight);
|
||||
}
|
||||
|
||||
private static OsmNodeNamed readNogo(double lon, double lat, int radius, double nogoWeight) {
|
||||
OsmNodeNamed n = new OsmNodeNamed();
|
||||
n.name = "nogo" + radius;
|
||||
n.ilon = (int) ((lon + 180.) * 1000000. + 0.5);
|
||||
n.ilat = (int) ((lat + 90.) * 1000000. + 0.5);
|
||||
n.isNogo = true;
|
||||
n.nogoWeight = nogoWeight;
|
||||
return n;
|
||||
}
|
||||
|
||||
private List<OsmNodeNamed> readNogoPolygons() {
|
||||
List<OsmNodeNamed> result = new ArrayList<OsmNodeNamed>();
|
||||
parseNogoPolygons(params.get("polylines"), result, false);
|
||||
parseNogoPolygons(params.get("polygons"), result, true);
|
||||
return result.size() > 0 ? result : null;
|
||||
}
|
||||
|
||||
private static void parseNogoPolygons(String polygons, List<OsmNodeNamed> result, boolean closed) {
|
||||
if (polygons != null) {
|
||||
String[] polygonList = polygons.split("\\|");
|
||||
for (int i = 0; i < polygonList.length; i++) {
|
||||
String[] lonLatList = polygonList[i].split(",");
|
||||
if (lonLatList.length > 1) {
|
||||
OsmNogoPolygon polygon = new OsmNogoPolygon(closed);
|
||||
int j;
|
||||
for (j = 0; j < 2 * (lonLatList.length / 2) - 1; ) {
|
||||
String slon = lonLatList[j++];
|
||||
String slat = lonLatList[j++];
|
||||
int lon = (int) ((Double.parseDouble(slon) + 180.) * 1000000. + 0.5);
|
||||
int lat = (int) ((Double.parseDouble(slat) + 90.) * 1000000. + 0.5);
|
||||
polygon.addVertex(lon, lat);
|
||||
}
|
||||
|
||||
String nogoWeight = "NaN";
|
||||
if (j < lonLatList.length) {
|
||||
nogoWeight = lonLatList[j];
|
||||
}
|
||||
polygon.nogoWeight = Double.parseDouble(nogoWeight);
|
||||
|
||||
if (polygon.points.size() > 0) {
|
||||
polygon.calcBoundingCircle();
|
||||
result.add(polygon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,24 +8,21 @@ import org.junit.Test;
|
|||
|
||||
import btools.mapaccess.PhysicalFile;
|
||||
|
||||
public class IntegrityCheckTest
|
||||
{
|
||||
public class IntegrityCheckTest {
|
||||
private File workingDir;
|
||||
|
||||
@Test
|
||||
public void integrityTest() throws Exception
|
||||
{
|
||||
URL resulturl = this.getClass().getResource( "/testtrack0.gpx" );
|
||||
Assert.assertTrue( "reference result not found: ", resulturl != null );
|
||||
File resultfile = new File( resulturl.getFile() );
|
||||
public void integrityTest() throws Exception {
|
||||
URL resulturl = this.getClass().getResource("/testtrack0.gpx");
|
||||
Assert.assertTrue("reference result not found: ", resulturl != null);
|
||||
File resultfile = new File(resulturl.getFile());
|
||||
workingDir = resultfile.getParentFile();
|
||||
|
||||
File segmentDir = new File( workingDir, "/../../../../brouter-map-creator/build/resources/test/tmp/segments" );
|
||||
File segmentDir = new File(workingDir, "/../../../../brouter-map-creator/build/resources/test/tmp/segments");
|
||||
File[] files = segmentDir.listFiles();
|
||||
|
||||
for ( File f : files )
|
||||
{
|
||||
PhysicalFile.checkFileIntegrity( f );
|
||||
for (File f : files) {
|
||||
PhysicalFile.checkFileIntegrity(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,75 +4,73 @@ import java.util.*;
|
|||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.URL;
|
||||
import java.io.File;
|
||||
|
||||
import btools.router.*;
|
||||
import btools.mapaccess.*;
|
||||
|
||||
public class RouterTest
|
||||
{
|
||||
public class RouterTest {
|
||||
private File workingDir;
|
||||
|
||||
@Test
|
||||
public void routerTest() throws Exception
|
||||
{
|
||||
URL resulturl = this.getClass().getResource( "/testtrack0.gpx" );
|
||||
Assert.assertTrue( "reference result not found: ", resulturl != null );
|
||||
public void routerTest() throws Exception {
|
||||
URL resulturl = this.getClass().getResource("/testtrack0.gpx");
|
||||
Assert.assertTrue("reference result not found: ", resulturl != null);
|
||||
File resultfile = new File(resulturl.getFile());
|
||||
workingDir = resultfile.getParentFile();
|
||||
|
||||
String msg;
|
||||
|
||||
// first test: route within dreiech test-map crossing tile border
|
||||
|
||||
msg = calcRoute( 8.720897, 50.002515, 8.723658, 49.997510, "testtrack" );
|
||||
|
||||
msg = calcRoute(8.720897, 50.002515, 8.723658, 49.997510, "testtrack");
|
||||
|
||||
// error message from router?
|
||||
Assert.assertTrue( "routing failed: " + msg, msg == null );
|
||||
Assert.assertTrue("routing failed: " + msg, msg == null);
|
||||
|
||||
// if the track didn't change, we expect the first alternative also
|
||||
File a1 = new File( workingDir, "testtrack1.gpx" );
|
||||
Assert.assertTrue( "result content missmatch", a1.exists() );
|
||||
File a1 = new File(workingDir, "testtrack1.gpx");
|
||||
Assert.assertTrue("result content missmatch", a1.exists());
|
||||
|
||||
// second test: to-point far off
|
||||
|
||||
msg = calcRoute( 8.720897, 50.002515, 16.723658, 49.997510, "notrack" );
|
||||
msg = calcRoute(8.720897, 50.002515, 16.723658, 49.997510, "notrack");
|
||||
|
||||
Assert.assertTrue( msg, msg != null && msg.indexOf( "not found" ) >= 0 );
|
||||
Assert.assertTrue(msg, msg != null && msg.indexOf("not found") >= 0);
|
||||
}
|
||||
|
||||
private String calcRoute( double flon, double flat, double tlon, double tlat, String trackname ) throws Exception
|
||||
{
|
||||
private String calcRoute(double flon, double flat, double tlon, double tlat, String trackname) throws Exception {
|
||||
String wd = workingDir.getAbsolutePath();
|
||||
|
||||
List<OsmNodeNamed> wplist = new ArrayList<OsmNodeNamed>();
|
||||
OsmNodeNamed n;
|
||||
n = new OsmNodeNamed();
|
||||
n.name = "from";
|
||||
n.ilon = 180000000 + (int)(flon*1000000 + 0.5);
|
||||
n.ilat = 90000000 + (int)(flat*1000000 + 0.5);
|
||||
wplist.add( n );
|
||||
n.ilon = 180000000 + (int) (flon * 1000000 + 0.5);
|
||||
n.ilat = 90000000 + (int) (flat * 1000000 + 0.5);
|
||||
wplist.add(n);
|
||||
|
||||
n = new OsmNodeNamed();
|
||||
n.name = "to";
|
||||
n.ilon = 180000000 + (int)(tlon*1000000 + 0.5);
|
||||
n.ilat = 90000000 + (int)(tlat*1000000 + 0.5);
|
||||
wplist.add( n );
|
||||
n.ilon = 180000000 + (int) (tlon * 1000000 + 0.5);
|
||||
n.ilat = 90000000 + (int) (tlat * 1000000 + 0.5);
|
||||
wplist.add(n);
|
||||
|
||||
RoutingContext rctx = new RoutingContext();
|
||||
rctx.localFunction = wd + "/../../../../misc/profiles2/trekking.brf";
|
||||
// c.setAlternativeIdx( 1 );
|
||||
|
||||
RoutingEngine re = new RoutingEngine(
|
||||
wd + "/" + trackname,
|
||||
wd + "/" + trackname,
|
||||
new File ( wd, "/../../../../brouter-map-creator/build/resources/test/tmp/segments"),
|
||||
wplist,
|
||||
rctx );
|
||||
wd + "/" + trackname,
|
||||
wd + "/" + trackname,
|
||||
new File(wd, "/../../../../brouter-map-creator/build/resources/test/tmp/segments"),
|
||||
wplist,
|
||||
rctx);
|
||||
|
||||
re.doRun(0);
|
||||
|
||||
re.doRun( 0 );
|
||||
|
||||
return re.getErrorMessage();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue