From 6f9cef9b3fd0317dc11a97377539e02cb6b24d49 Mon Sep 17 00:00:00 2001 From: Norbert Renner Date: Thu, 22 May 2014 11:11:58 +0200 Subject: [PATCH 1/4] profile upload (a first implementation), similar to CgiUpload, adds a new customprofiledir argument, a new file is created on each upload --- .../main/java/btools/server/RouteServer.java | 36 +++++-- .../java/btools/server/ServiceContext.java | 1 + .../server/request/ProfileUploadHandler.java | 95 +++++++++++++++++++ misc/scripts/standalone/server.cmd | 4 +- misc/scripts/standalone/server.sh | 4 +- 5 files changed, 126 insertions(+), 14 deletions(-) create mode 100644 brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java diff --git a/brouter-server/src/main/java/btools/server/RouteServer.java b/brouter-server/src/main/java/btools/server/RouteServer.java index 9ddcde0..20098ae 100644 --- a/brouter-server/src/main/java/btools/server/RouteServer.java +++ b/brouter-server/src/main/java/btools/server/RouteServer.java @@ -20,6 +20,7 @@ import btools.router.OsmNodeNamed; import btools.router.OsmTrack; import btools.router.RoutingContext; import btools.router.RoutingEngine; +import btools.server.request.ProfileUploadHandler; import btools.server.request.RequestHandler; import btools.server.request.ServerHandler; @@ -65,6 +66,16 @@ public class RouteServer extends Thread { handler = new ServerHandler( serviceContext, params ); } + else if ("/brouter/profile".equals(url)) + { + writeHttpHeader(bw); + + ProfileUploadHandler uploadHandler = new ProfileUploadHandler( serviceContext ); + uploadHandler.handlePostRequest(br, bw); + + bw.flush(); + return; + } else { throw new IllegalArgumentException( "unknown request syntax: " + getline ); @@ -76,12 +87,7 @@ public class RouteServer extends Thread cr.quite = true; cr.doRun( maxRunningTime ); - // http-header - bw.write( "HTTP/1.1 200 OK\n" ); - bw.write( "Connection: close\n" ); - bw.write( "Content-Type: text/xml; charset=utf-8\n" ); - bw.write( "Access-Control-Allow-Origin: *\n" ); - bw.write( "\n" ); + writeHttpHeader(bw); if ( cr.getErrorMessage() != null ) { @@ -115,22 +121,23 @@ public class RouteServer extends Thread public static void main(String[] args) throws Exception { System.out.println("BRouter 0.9.9 / 18042014 / abrensch"); - if ( args.length != 4 ) + if ( args.length != 5 ) { System.out.println("serve BRouter protocol"); - System.out.println("usage: java RouteServer "); + System.out.println("usage: java RouteServer "); return; } ServiceContext serviceContext = new ServiceContext(); serviceContext.segmentDir = args[0]; System.setProperty( "profileBaseDir", args[1] ); + serviceContext.customProfileDir = args[2]; - int maxthreads = Integer.parseInt( args[3] ); + int maxthreads = Integer.parseInt( args[4] ); TreeMap threadMap = new TreeMap(); - ServerSocket serverSocket = new ServerSocket(Integer.parseInt(args[2])); + ServerSocket serverSocket = new ServerSocket(Integer.parseInt(args[3])); long last_ts = 0; for (;;) { @@ -187,4 +194,13 @@ public class RouteServer extends Thread } return maxRunningTime; } + + private static void writeHttpHeader(BufferedWriter bw) throws IOException { + // http-header + bw.write( "HTTP/1.1 200 OK\n" ); + bw.write( "Connection: close\n" ); + bw.write( "Content-Type: text/xml; charset=utf-8\n" ); + bw.write( "Access-Control-Allow-Origin: *\n" ); + bw.write( "\n" ); + } } diff --git a/brouter-server/src/main/java/btools/server/ServiceContext.java b/brouter-server/src/main/java/btools/server/ServiceContext.java index 096a78d..823177f 100644 --- a/brouter-server/src/main/java/btools/server/ServiceContext.java +++ b/brouter-server/src/main/java/btools/server/ServiceContext.java @@ -11,6 +11,7 @@ import btools.router.OsmNodeNamed; public class ServiceContext { public String segmentDir; + public String customProfileDir; public Map profileMap = null; public List nogoList; } diff --git a/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java b/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java new file mode 100644 index 0000000..831c0a5 --- /dev/null +++ b/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java @@ -0,0 +1,95 @@ +package btools.server.request; + +import btools.server.ServiceContext; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; + +/** + * Custom profile uploads + */ +public class ProfileUploadHandler +{ + // maximum number of characters (file size limit for custom profiles) + private static final int MAX_LENGTH = 100000; + + private ServiceContext serviceContext; + + public ProfileUploadHandler( ServiceContext serviceContext) + { + this.serviceContext = serviceContext; + } + + public void handlePostRequest(BufferedReader br, BufferedWriter response) throws IOException + { + BufferedWriter fileWriter = null; + + try + { + String id = getOrCreateCustomProfileDir() + "/" + System.currentTimeMillis(); + File file = new File ( id + ".brf" ); + fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream( file ) ) ); + //StringWriter sw = new StringWriter(); bw = new BufferedWriter(sw); + + // only profile text as content + readPostData(br, fileWriter, id); + + fileWriter.flush(); + //System.out.println("data: |" + sw.toString() + "|"); + + response.write("profileid=" + id); + } + finally + { + if ( fileWriter != null ) try { fileWriter.close(); } catch( Exception e ) {} + } + } + + private File getOrCreateCustomProfileDir() + { + File customProfileDir = new File(serviceContext.customProfileDir); + 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 + { + // Content-Type: text/plain;charset=UTF-8 + + for(;;) + { + // headers + String line = ir.readLine(); + if ( line == null ) break; + + // blank line before content after headers + if ( line.length() == 0 ) + { + 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(;;) + { + // read will block when false, occurs at end of stream rather than -1 + if (!ir.ready()) break; + int c = ir.read(); + if ( c == -1) break; + bw.write( c ); + + numChars++; + if (numChars > MAX_LENGTH) + throw new IOException("Maximum number of characters exceeded (" + MAX_LENGTH + ", " + id + ")"); + } + break; + } + } + } +} diff --git a/misc/scripts/standalone/server.cmd b/misc/scripts/standalone/server.cmd index 541072b..a04a794 100644 --- a/misc/scripts/standalone/server.cmd +++ b/misc/scripts/standalone/server.cmd @@ -1,9 +1,9 @@ @echo off REM BRouter standalone server -REM java -cp brouter.jar btools.brouter.RouteServer +REM java -cp brouter.jar btools.brouter.RouteServer set JAVA_OPTS=-Xmx128M -Xms128M -Xmn8M set CLASSPATH=../brouter.jar -java %JAVA_OPTS% -cp %CLASSPATH% btools.server.RouteServer ..\segments2 ..\profiles2 17777 1 +java %JAVA_OPTS% -cp %CLASSPATH% btools.server.RouteServer ..\segments2 ..\profiles2 ..\customprofiles 17777 1 diff --git a/misc/scripts/standalone/server.sh b/misc/scripts/standalone/server.sh index 0867d91..bda1068 100755 --- a/misc/scripts/standalone/server.sh +++ b/misc/scripts/standalone/server.sh @@ -1,9 +1,9 @@ #!/bin/sh # BRouter standalone server -# java -cp brouter.jar btools.brouter.RouteServer +# java -cp brouter.jar btools.brouter.RouteServer JAVA_OPTS="-Xmx128M -Xms128M -Xmn8M" CLASSPATH=../brouter.jar -java $JAVA_OPTS -cp $CLASSPATH btools.server.RouteServer ../segments2 ../profiles2 17777 1 +java $JAVA_OPTS -cp $CLASSPATH btools.server.RouteServer ../segments2 ../profiles2 ../customprofiles 17777 1 From 3df98310fb7ea5a8e008281bca663a2fe0c523f6 Mon Sep 17 00:00:00 2001 From: Norbert Renner Date: Thu, 22 May 2014 12:54:26 +0200 Subject: [PATCH 2/4] don't pass directory path to client, use prefix instead --- .../btools/server/request/ProfileUploadHandler.java | 9 ++++++--- .../java/btools/server/request/ServerHandler.java | 11 ++++++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java b/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java index 831c0a5..b6ecfbe 100644 --- a/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java +++ b/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java @@ -16,6 +16,9 @@ public class ProfileUploadHandler // maximum number of characters (file size limit for custom profiles) private static final int MAX_LENGTH = 100000; + // prefix for custom profile id to distinguish from default profiles + public static final String CUSTOM_PREFIX = "custom_"; + private ServiceContext serviceContext; public ProfileUploadHandler( ServiceContext serviceContext) @@ -29,8 +32,8 @@ public class ProfileUploadHandler try { - String id = getOrCreateCustomProfileDir() + "/" + System.currentTimeMillis(); - File file = new File ( id + ".brf" ); + String id = "" + System.currentTimeMillis(); + File file = new File( getOrCreateCustomProfileDir(), id + ".brf" ); fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream( file ) ) ); //StringWriter sw = new StringWriter(); bw = new BufferedWriter(sw); @@ -40,7 +43,7 @@ public class ProfileUploadHandler fileWriter.flush(); //System.out.println("data: |" + sw.toString() + "|"); - response.write("profileid=" + id); + response.write("profileid=" + CUSTOM_PREFIX + id); } finally { diff --git a/brouter-server/src/main/java/btools/server/request/ServerHandler.java b/brouter-server/src/main/java/btools/server/request/ServerHandler.java index 2ca962a..afa717c 100644 --- a/brouter-server/src/main/java/btools/server/request/ServerHandler.java +++ b/brouter-server/src/main/java/btools/server/request/ServerHandler.java @@ -8,6 +8,7 @@ import btools.router.OsmNodeNamed; import btools.router.OsmTrack; import btools.router.RoutingContext; import btools.server.ServiceContext; +import java.io.File; /** * URL query parameter handler for web and standalone server. Supports all @@ -38,7 +39,15 @@ public class ServerHandler extends RequestHandler { { RoutingContext rc = new RoutingContext(); - rc.localFunction = params.get( "profile" ); + 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(); + } + rc.localFunction = profile; + rc.setAlternativeIdx(Integer.parseInt(params.get( "alternativeidx" ))); List nogoList = readNogoList(); From 8327fd4e24485e5914c06802b5892e3f957688c9 Mon Sep 17 00:00:00 2001 From: Norbert Renner Date: Thu, 22 May 2014 13:09:35 +0200 Subject: [PATCH 3/4] fix: custom profile dir relative to profile dir --- brouter-server/src/main/java/btools/server/RouteServer.java | 3 ++- brouter-server/src/main/java/btools/server/ServiceContext.java | 1 + .../main/java/btools/server/request/ProfileUploadHandler.java | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/brouter-server/src/main/java/btools/server/RouteServer.java b/brouter-server/src/main/java/btools/server/RouteServer.java index 20098ae..6760d97 100644 --- a/brouter-server/src/main/java/btools/server/RouteServer.java +++ b/brouter-server/src/main/java/btools/server/RouteServer.java @@ -130,7 +130,8 @@ public class RouteServer extends Thread ServiceContext serviceContext = new ServiceContext(); serviceContext.segmentDir = args[0]; - System.setProperty( "profileBaseDir", args[1] ); + serviceContext.profileDir = args[1]; + System.setProperty( "profileBaseDir", serviceContext.profileDir ); serviceContext.customProfileDir = args[2]; int maxthreads = Integer.parseInt( args[4] ); diff --git a/brouter-server/src/main/java/btools/server/ServiceContext.java b/brouter-server/src/main/java/btools/server/ServiceContext.java index 823177f..eabd996 100644 --- a/brouter-server/src/main/java/btools/server/ServiceContext.java +++ b/brouter-server/src/main/java/btools/server/ServiceContext.java @@ -11,6 +11,7 @@ import btools.router.OsmNodeNamed; public class ServiceContext { public String segmentDir; + public String profileDir; public String customProfileDir; public Map profileMap = null; public List nogoList; diff --git a/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java b/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java index b6ecfbe..4e4def3 100644 --- a/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java +++ b/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java @@ -53,7 +53,8 @@ public class ProfileUploadHandler private File getOrCreateCustomProfileDir() { - File customProfileDir = new File(serviceContext.customProfileDir); + // workaround: customProfileDir relative to profileDir, because RoutingEngine doesn't know custom profiles + File customProfileDir = new File(serviceContext.profileDir, serviceContext.customProfileDir); if (!customProfileDir.exists()) { customProfileDir.mkdir(); From 5651260691cc27d2c536a5d42547e426b2f25265 Mon Sep 17 00:00:00 2001 From: Norbert Renner Date: Thu, 22 May 2014 17:55:17 +0200 Subject: [PATCH 4/4] reuse (overwrite) existing custom profile file in editing session (id passed in URL) --- .../src/main/java/btools/server/RouteServer.java | 13 +++++++++++-- .../btools/server/request/ProfileUploadHandler.java | 11 +++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/brouter-server/src/main/java/btools/server/RouteServer.java b/brouter-server/src/main/java/btools/server/RouteServer.java index 6760d97..dc91b70 100644 --- a/brouter-server/src/main/java/btools/server/RouteServer.java +++ b/brouter-server/src/main/java/btools/server/RouteServer.java @@ -26,6 +26,8 @@ import btools.server.request.ServerHandler; public class RouteServer extends Thread { + public static final String PROFILE_UPLOAD_URL = "/brouter/profile"; + public ServiceContext serviceContext; private Socket clientSocket = null; @@ -66,12 +68,19 @@ public class RouteServer extends Thread { handler = new ServerHandler( serviceContext, params ); } - else if ("/brouter/profile".equals(url)) + else if ( url.startsWith( PROFILE_UPLOAD_URL ) ) { writeHttpHeader(bw); + 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(br, bw); + uploadHandler.handlePostRequest( profileId, br, bw ); bw.flush(); return; diff --git a/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java b/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java index 4e4def3..537f39b 100644 --- a/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java +++ b/brouter-server/src/main/java/btools/server/request/ProfileUploadHandler.java @@ -26,13 +26,20 @@ public class ProfileUploadHandler this.serviceContext = serviceContext; } - public void handlePostRequest(BufferedReader br, BufferedWriter response) throws IOException + public void handlePostRequest(String profileId, BufferedReader br, BufferedWriter response) throws IOException { BufferedWriter fileWriter = null; try { - String id = "" + System.currentTimeMillis(); + String id; + if ( profileId != null ) + { + // update existing file when id appended + 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 ) ) ); //StringWriter sw = new StringWriter(); bw = new BufferedWriter(sw);