Loading TestHttpService.java→messif/utility/RestServiceAlgorithm.java +213 −0 Original line number Diff line number Diff line package messif.utility; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.util.Random; import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; import messif.algorithms.Algorithm; import messif.objects.LocalAbstractObject; import messif.objects.NoDataObject; import messif.operations.query.KNNQueryOperation; /** * Simple class that can be used for testing HTTP REST services. * It also provides a MESSIF {@link Algorithm} that allows to execute * {@link KNNQueryOperation}s via REST service. * * <p>Example: * <pre> * System.out.println(RestServiceAlgorithm.processHttpRequest("localhost", 12345, "/insertImage?imageId=testImage", null, new File("myTestImage.jpg"))); * System.out.println(RestServiceAlgorithm.processHttpRequest("localhost", 12345, "/search?k=2", "locator", "testImage")); * </pre> * * @author Michal Batko, Masaryk University, Brno, Czech Republic, batko@fi.muni.cz */ public class TestHttpService { /** Random number generator */ public static final Random randomGenerator = new Random(); public class RestServiceAlgorithm extends Algorithm { /** Class id for serialization */ private static final long serialVersionUID = 1L; /** Host (IP address) where the service is running */ private final String host; /** TCP port on which the service is running */ private final int port; /** Name of the service to execute (including all necessary parameters)*/ private final String service; /** Additional parameter where the number of results (k) is passed */ private final String resultCountParamName; /** Additional parameter where the query object is passed */ private final String queryObjectParamName; /** * @param host the host (IP address) where the service is running * @param port the TCP port on which the service is running * @param service the name of the service to execute (including all necessary parameters) * @param resultCountParamName the additional parameter where the number of results (k) is passed * @param queryObjectParamName the additional parameter where the query object is passed; * if <tt>null</tt>, the query object is sent via POST method */ public RestServiceAlgorithm(String host, int port, String service, String resultCountParamName, String queryObjectParamName) { super("HttpService on " + host + ":" + port); this.host = host; this.port = port; this.service = service; this.resultCountParamName = resultCountParamName; this.queryObjectParamName = queryObjectParamName; } /** * Create a float vector of arbitrary dimension. * @param dim the dimension of the vector to create * @return the coma separated vector of random float numbers of the specified dimension * Executes KNN query operation via the REST service. * @param operation the operation to execute * @throws IOException if there was a problem working with the REST service */ public static String createLongFloatVector(int dim) { StringBuilder str = new StringBuilder(); str.append(randomGenerator.nextFloat()); for (int i = 0; i < dim; i++) str.append(", ").append(randomGenerator.nextFloat()); return str.toString(); public void executeSearch(KNNQueryOperation operation) throws IOException { StringBuilder searchService = new StringBuilder(service); if (resultCountParamName != null) searchService = appendQueryParameter(searchService, resultCountParamName, Integer.toString(operation.getK())); String result = processHttpRequest(host, port, searchService, queryObjectParamName, operation.getQueryObject()); // Parse JSON output Pattern pattern = Pattern.compile("\\[([^\\[,]+),\"([^]]+)\"\\]"); Matcher matcher = pattern.matcher(result); while (matcher.find()) { operation.addToAnswer(new NoDataObject(matcher.group(2)), Float.parseFloat(matcher.group(1)), null); } operation.endOperation(); } /** Loading @@ -45,13 +97,28 @@ public class TestHttpService { * @return the REST service response * @throws IOException if the REST service returned an error return code */ public static String processHttpRequest(String host, int port, String service, String dataParamName, LocalAbstractObject obj) throws IOException { public static String processHttpRequest(String host, int port, CharSequence service, String dataParamName, LocalAbstractObject obj) throws IOException { // Convert the object to string data ByteArrayOutputStream objData = new ByteArrayOutputStream(); obj.write(objData); return processHttpRequest(host, port, service, dataParamName, new String(objData.toByteArray())); } /** * Process request on a HTTP REST service. * @param host the host (IP address) where the service is running * @param port the TCP port on which the service is running * @param service the name of the service to execute (including all necessary parameters) * @param dataParamName the additional parameter where the data are passed; * if <tt>null</tt>, the data are sent via POST method * @param obj the object to send as data, it will be converted to text representation * @return the REST service response * @throws IOException if the REST service returned an error return code */ public static String processHttpRequest(String host, int port, CharSequence service, String dataParamName, File obj) throws IOException { return processHttpRequest(host, port, service, dataParamName, new FileInputStream(obj)); } /** * Process request on a HTTP REST service. * @param host the host (IP address) where the service is running Loading @@ -63,22 +130,39 @@ public class TestHttpService { * @return the REST service response * @throws IOException if the REST service returned an error return code */ public static String processHttpRequest(String host, int port, String service, String dataParamName, String data) throws IOException { public static String processHttpRequest(String host, int port, CharSequence service, String dataParamName, Object data) throws IOException { // Append data parameter if needed if (dataParamName != null && data != null) service = service + (service.indexOf('?') != -1 ? '&' : '?') + dataParamName + '=' + URLEncoder.encode(data, "utf-8"); service = appendQueryParameter(service, dataParamName, data.toString()); // Open connection URL url = new URL("http", host, port, service); URL url = new URL("http", host, port, service.toString()); URLConnection conn = url.openConnection(); // Send data if not sent by parameter if (dataParamName == null && data != null) { conn.setDoOutput(true); if (data instanceof byte[]) { OutputStream out = conn.getOutputStream(); out.write((byte[])data); out.close(); } else if (data instanceof InputStream) { InputStream in = (InputStream)data; OutputStream out = conn.getOutputStream(); byte[] buffer = new byte[1024]; int bytes = in.read(buffer); while (bytes != -1) { out.write(buffer, 0, bytes); bytes = in.read(buffer); } out.close(); in.close(); } else { // Convert to string and send Writer out = new OutputStreamWriter(conn.getOutputStream(), "utf-8"); out.write(data); out.write(data.toString()); out.close(); } } // Read result try { Loading Loading @@ -113,19 +197,17 @@ public class TestHttpService { } /** * Test the REST service by calling two inserts and one search. * @param args ignored * @throws IOException if the REST service returned an error return code * Appends the HTTP query parameter to the given string. * @param input the string to append the parameter to * @param parameterName the parameter name * @param parameterValue the value of the parameter to append * @return the updated string * @throws UnsupportedEncodingException if the given parameter value cannot be converted to UTF-8 encoding */ public static void main(String[] args) throws IOException { String host = "localhost"; int port = 12345; String dataParamName = "data"; // data sent in GET parameter "data"; set to null to use POST transfer method String longData = createLongFloatVector(100); System.out.print("Inserting long data (" + longData.length() + " characters): "); System.out.println(processHttpRequest(host, port, "/insert?locator=1", dataParamName, longData)); System.out.println(processHttpRequest(host, port, "/insert?locator=2", dataParamName, createLongFloatVector(100))); System.out.println(processHttpRequest(host, port, "/search?locator=&k=2", dataParamName, createLongFloatVector(100))); public static StringBuilder appendQueryParameter(CharSequence input, String parameterName, String parameterValue) throws UnsupportedEncodingException { StringBuilder str = input instanceof StringBuilder ? (StringBuilder)input : new StringBuilder(input); str.append(str.indexOf("?") != -1 ? '&' : '?'); str.append(parameterName).append('=').append(URLEncoder.encode(parameterValue, "utf-8")); return str; } } Loading
TestHttpService.java→messif/utility/RestServiceAlgorithm.java +213 −0 Original line number Diff line number Diff line package messif.utility; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.util.Random; import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; import messif.algorithms.Algorithm; import messif.objects.LocalAbstractObject; import messif.objects.NoDataObject; import messif.operations.query.KNNQueryOperation; /** * Simple class that can be used for testing HTTP REST services. * It also provides a MESSIF {@link Algorithm} that allows to execute * {@link KNNQueryOperation}s via REST service. * * <p>Example: * <pre> * System.out.println(RestServiceAlgorithm.processHttpRequest("localhost", 12345, "/insertImage?imageId=testImage", null, new File("myTestImage.jpg"))); * System.out.println(RestServiceAlgorithm.processHttpRequest("localhost", 12345, "/search?k=2", "locator", "testImage")); * </pre> * * @author Michal Batko, Masaryk University, Brno, Czech Republic, batko@fi.muni.cz */ public class TestHttpService { /** Random number generator */ public static final Random randomGenerator = new Random(); public class RestServiceAlgorithm extends Algorithm { /** Class id for serialization */ private static final long serialVersionUID = 1L; /** Host (IP address) where the service is running */ private final String host; /** TCP port on which the service is running */ private final int port; /** Name of the service to execute (including all necessary parameters)*/ private final String service; /** Additional parameter where the number of results (k) is passed */ private final String resultCountParamName; /** Additional parameter where the query object is passed */ private final String queryObjectParamName; /** * @param host the host (IP address) where the service is running * @param port the TCP port on which the service is running * @param service the name of the service to execute (including all necessary parameters) * @param resultCountParamName the additional parameter where the number of results (k) is passed * @param queryObjectParamName the additional parameter where the query object is passed; * if <tt>null</tt>, the query object is sent via POST method */ public RestServiceAlgorithm(String host, int port, String service, String resultCountParamName, String queryObjectParamName) { super("HttpService on " + host + ":" + port); this.host = host; this.port = port; this.service = service; this.resultCountParamName = resultCountParamName; this.queryObjectParamName = queryObjectParamName; } /** * Create a float vector of arbitrary dimension. * @param dim the dimension of the vector to create * @return the coma separated vector of random float numbers of the specified dimension * Executes KNN query operation via the REST service. * @param operation the operation to execute * @throws IOException if there was a problem working with the REST service */ public static String createLongFloatVector(int dim) { StringBuilder str = new StringBuilder(); str.append(randomGenerator.nextFloat()); for (int i = 0; i < dim; i++) str.append(", ").append(randomGenerator.nextFloat()); return str.toString(); public void executeSearch(KNNQueryOperation operation) throws IOException { StringBuilder searchService = new StringBuilder(service); if (resultCountParamName != null) searchService = appendQueryParameter(searchService, resultCountParamName, Integer.toString(operation.getK())); String result = processHttpRequest(host, port, searchService, queryObjectParamName, operation.getQueryObject()); // Parse JSON output Pattern pattern = Pattern.compile("\\[([^\\[,]+),\"([^]]+)\"\\]"); Matcher matcher = pattern.matcher(result); while (matcher.find()) { operation.addToAnswer(new NoDataObject(matcher.group(2)), Float.parseFloat(matcher.group(1)), null); } operation.endOperation(); } /** Loading @@ -45,13 +97,28 @@ public class TestHttpService { * @return the REST service response * @throws IOException if the REST service returned an error return code */ public static String processHttpRequest(String host, int port, String service, String dataParamName, LocalAbstractObject obj) throws IOException { public static String processHttpRequest(String host, int port, CharSequence service, String dataParamName, LocalAbstractObject obj) throws IOException { // Convert the object to string data ByteArrayOutputStream objData = new ByteArrayOutputStream(); obj.write(objData); return processHttpRequest(host, port, service, dataParamName, new String(objData.toByteArray())); } /** * Process request on a HTTP REST service. * @param host the host (IP address) where the service is running * @param port the TCP port on which the service is running * @param service the name of the service to execute (including all necessary parameters) * @param dataParamName the additional parameter where the data are passed; * if <tt>null</tt>, the data are sent via POST method * @param obj the object to send as data, it will be converted to text representation * @return the REST service response * @throws IOException if the REST service returned an error return code */ public static String processHttpRequest(String host, int port, CharSequence service, String dataParamName, File obj) throws IOException { return processHttpRequest(host, port, service, dataParamName, new FileInputStream(obj)); } /** * Process request on a HTTP REST service. * @param host the host (IP address) where the service is running Loading @@ -63,22 +130,39 @@ public class TestHttpService { * @return the REST service response * @throws IOException if the REST service returned an error return code */ public static String processHttpRequest(String host, int port, String service, String dataParamName, String data) throws IOException { public static String processHttpRequest(String host, int port, CharSequence service, String dataParamName, Object data) throws IOException { // Append data parameter if needed if (dataParamName != null && data != null) service = service + (service.indexOf('?') != -1 ? '&' : '?') + dataParamName + '=' + URLEncoder.encode(data, "utf-8"); service = appendQueryParameter(service, dataParamName, data.toString()); // Open connection URL url = new URL("http", host, port, service); URL url = new URL("http", host, port, service.toString()); URLConnection conn = url.openConnection(); // Send data if not sent by parameter if (dataParamName == null && data != null) { conn.setDoOutput(true); if (data instanceof byte[]) { OutputStream out = conn.getOutputStream(); out.write((byte[])data); out.close(); } else if (data instanceof InputStream) { InputStream in = (InputStream)data; OutputStream out = conn.getOutputStream(); byte[] buffer = new byte[1024]; int bytes = in.read(buffer); while (bytes != -1) { out.write(buffer, 0, bytes); bytes = in.read(buffer); } out.close(); in.close(); } else { // Convert to string and send Writer out = new OutputStreamWriter(conn.getOutputStream(), "utf-8"); out.write(data); out.write(data.toString()); out.close(); } } // Read result try { Loading Loading @@ -113,19 +197,17 @@ public class TestHttpService { } /** * Test the REST service by calling two inserts and one search. * @param args ignored * @throws IOException if the REST service returned an error return code * Appends the HTTP query parameter to the given string. * @param input the string to append the parameter to * @param parameterName the parameter name * @param parameterValue the value of the parameter to append * @return the updated string * @throws UnsupportedEncodingException if the given parameter value cannot be converted to UTF-8 encoding */ public static void main(String[] args) throws IOException { String host = "localhost"; int port = 12345; String dataParamName = "data"; // data sent in GET parameter "data"; set to null to use POST transfer method String longData = createLongFloatVector(100); System.out.print("Inserting long data (" + longData.length() + " characters): "); System.out.println(processHttpRequest(host, port, "/insert?locator=1", dataParamName, longData)); System.out.println(processHttpRequest(host, port, "/insert?locator=2", dataParamName, createLongFloatVector(100))); System.out.println(processHttpRequest(host, port, "/search?locator=&k=2", dataParamName, createLongFloatVector(100))); public static StringBuilder appendQueryParameter(CharSequence input, String parameterName, String parameterValue) throws UnsupportedEncodingException { StringBuilder str = input instanceof StringBuilder ? (StringBuilder)input : new StringBuilder(input); str.append(str.indexOf("?") != -1 ? '&' : '?'); str.append(parameterName).append('=').append(URLEncoder.encode(parameterValue, "utf-8")); return str; } }