Child pages
  • Routing handler for RAMP server
Skip to end of metadata
Go to start of metadata

Getting started

  1. Install the RAMP server as described in the RAMP SDK documentation.
  2. Ensure you have a ramp-config.properties, if required, and/or set up the routing.endpoint property.
  3. Copy the service server files (from the routing.zip attachment) into the 'integration' directory (/etc/ramp/integration).
  4. Start apache tomcat.
  5. Open /ramp/ramp/feature/ft in your browser. A file should automatically download if the server is set up correctly. You can delete/ignore this file. An error screen will appear if something is wrong.
  6. Create an application on the RAMP deployment server, and point your feature/service server to your locally installed tomcat installation.
  7. Create a client application in Eclipse.
  8. Add routing.rs and security.rs (if secure communication to the RAMP server is required) from the routing.zip attachment.
  9. Create an endpoint server (ASP.NET MVC sample included).
  10. Setup bindings for HTTPS and associate with a trusted certificate, if required.
  11. Write MVC/REST actions to handle requests from the client.
  12. Write client code to call the target endpoints on your endpoint server (sample included).
  13. Upload RAMP feature.
  14. Download the client application to your device/emulator.

Supports:

  • Text/REST (GET, POST)
  • JSON (GET/POST)
  • HTTP/HTTPS to target from service server

RAMP server configuration:

First you will have to setup your service server. 

Find a sample configuration (main-context.xml included in the routing.zip attachment) for adding routing beyond the barebones template.

Most of the detail deals with setting http client and security settings.

This setup provide support for HTTP and HTTPS traffic, and requires the target to have a trusted certificate.

Consult the Java documentation on how to configure the JVM for alternative scenario's eg self-signed certificates.

Configuration  options:

These have been set up for liberal defaults already, but may require changing depending on your requirements.

defaultMaxPerRoute: Sets up the maximum number of concurrent connections to a single endpoint.

maxTotal: Sets up the maximum number of all concurrent connections.

You will need to configure the 'routing.endpoint' properties in your property file or hard code it.

Client

Client functions:

The following set of functions are to provide you easy access to the routing handler on the service service.

Note: When calling synchronous web services, always provide a ServiceForm in your client app.

Derived synchronous client functions
/*
 * General purpose request function
 * 
 * Parameters:
 * target - String - name of the target page to call
 * method - String - the HTTP method to use, ie GET, POST, PUT, DELETE, HEAD, PATCH
 * type   - String - the data type of the request, ie JSON or anything else
 * query  - Map	   - query string parameters to be appended to the request url
 * data	  - Map	   - data arguments to send to the request
 * 
 * Returns:
 * The value as returned by the page (either String or complex data object)
 * 
 * Note:
 * - the handler's endpoint will be prefixed to the target
 * - query string parameters are form-urlencoded
 * - data is passed as content if JSON is the type, else form-urlencoded
 * - returned data is a string, except when type is JSON or the response's content type is 'application/json' 
 */
function request(target, method, type, query, data) {
	svcresult = webService("routingHandler",  "target", target,
			  	   							  "method", method,
											  "type", type,
											  "query", query,
											  "data", data);
	errormsg = mapGet(svcresult, "error");
	if (errormsg != "")
	{
		error(errormsg);
	}
	else
	{
		return mapGet(svcresult, "result");
	}
} 

/*
 * Helper function for GET requests
 */
function get(target, query) {
	return request(target, "GET", "", query, Map());
}

/*
 * Helper function for POST requests
 */
function post(target, query, data) {
	return request(target, "POST", "", query, data);
}

/*
 * Helper function for JSON requests
 */
function json(target, query, data) {
	return request(target, "POST", "json", query, data);
}
Note: Make sure to call endAsyncRequest in your callback function to extract the result or signal an error.
Derived asynchronous client functions
/*
 * General purpose asynchronous request function
 * 
 * Parameters:
 * target - String - name of the target page to call
 * method - String - the HTTP method to use, ie GET, POST, PUT, DELETE, HEAD, PATCH
 * type   - String - the data type of the request, ie JSON or anything else
 * query  - Map	   - query string parameters to be appended to the request url
 * data	  - Map	   - data arguments to send to the request
 * callback - String - name of callback function to call
 * 
 * Note:
 * - the handler's endpoint will be prefixed to the target
 * - query string parameters are form-urlencoded
 * - data is passed as content if JSON is the type, else form-urlencoded
 * - returned data is a string, except when type is JSON or the response's content type is 'application/json' 
 */
function requestAsync(target, method, type, query, data, callback) {
	webServiceAsync("routingHandler", callback, "target", target,
			  	   							  	"method", method,
											  	"type", type,
											  	"query", query,
											  	"data", data);
} 

/*
 * Helper function for async GET requests
 */
function getAsync(target, query, callback) {
	requestAsync(target, "GET", "", query, Map(), callback);
}

/*
 * Helper function for async POST requests
 */
function postAsync(target, query, data, callback) {
	requestAsync(target, "POST", "", query, data, callback);
}

/*
 * Helper function for async JSON requests
 */
function jsonAsync(target, query, data, callback) {
	requestAsync(target, "POST", "json", query, data, callback);
}
/*
 * Helper function to get result and signal error, if any
 */
function endAsyncRequest(result, errmsg) {
	if (errmsg != "")
		error(errmsg);
	errmsg = mapGet(result, "error");
	if (errmsg != "")
		error(errmsg);
	return mapGet(result, "result");
}
Note: When calling synchronous web services, always provide a ServiceForm in your client app.
Derived secure client functions
/*
 * General purpose secure request function
 * 
 * Parameters:
 * target - String - name of the target page to call
 * method - String - the HTTP method to use, ie GET, POST, PUT, DELETE, HEAD, PATCH
 * type   - String - the data type of the request, ie JSON or anything else
 * query  - Map	   - query string parameters to be appended to the request url
 * data	  - Map	   - data arguments to send to the request
 * 
 * Returns:
 * The value as returned by the page (either String or complex data object)
 * 
 * Note:
 * - the handler's endpoint will be prefixed to the target
 * - query string parameters are form-urlencoded
 * - data is passed as content if JSON is the type, else form-urlencoded
 * - returned data is a string, except when type is JSON or the response's content type is 'application/json' 
 */
function secureRequest(target, method, type, query, data) {
	svcresult = sendSecure("secureRoutingHandler", Map("target", target,
			  	   					 			  	   "method", method,
											  	  	   "type", type,
											  	  	   "query", query,
											  	  	   "data", data));
	errormsg = mapGet(svcresult, "error");
	if (errormsg != "")
	{
		error(errormsg);
	}
	else
	{
		return mapGet(svcresult, "result");
	}										  	  	   
}

/*
 * Helper function for secure GET requests
 */
function secureGet(target, query) {
	return secureRequest(target, "GET", "", query, Map());
}

/*
 * Helper function for secure POST requests
 */
function securePost(target, query, data) {
	return secureRequest(target, "POST", "", query, data);
}

/*
 * Helper function for secure JSON requests
 */
function secureJson(target, query, data) {
	return secureRequest(target, "POST", "json", query, data);
} 

All 3 of the above sections are included in the routing.zip attachment.

Client examples

Synchronous client invocation examples
// simple get call, returns a string value from server
mainform.result1.text = get("SimpleGet", Map());
 
// get call with query string parameters, returns string value from server
mainform.result2.text = get("ComplexGet", Map("param1", "hello world", "param2", "42"));
 
// simple post call with 1 query string parameter and 1 form parameter, returns string value from server
mainform.result3.text = post("SimplePost", Map("param2", "hello world"), Map("param1", "42"));

// simple json call with no query parameters and post content as { bar : 1 }, returns json from server
mainform.result4.text = json("SimpleJson", Map(), Map("bar", 1));

// json call with post content as { bars: [{ foo: { baz: bar }}, { foo: { baz: but }}]}
mainform.result5.text = json("ComplexJson", Map(), Map("bars", List( Map("foo", Map("baz", "bar")), Map("foo", Map("baz", "but")))));

// same as above, but server returns the json that was passed to the call, with deconstruction
resp = json("ComplexJsonResponse", Map(), Map("bars", List( Map("foo", Map("baz", "bar")), Map("foo", Map("baz", "but")))));
item1 = mapGet(listGet(resp, 0), "foo");
item2 = mapGet(listGet(resp, 1), "foo");
mainform.result6.text = listSize(resp) ++ " - " ++ mapGet(item1, "baz") ++ " - " ++ mapGet(item2, "baz");

// json call with post content as { bar: { foo: { baz: bar }}}
mainform.result7.text = json("ComplexJsonDynamic", Map(), Map("bar", Map("foo", Map("baz", "bar"))));

// simple get, but with json response from server
mainform.result8.text = get("SimpleJson", Map("bar", 1));

// json call to passes in byte array from image, server sends modified byte array back that gets assigned to the image
icon.src = json("DataTest", Map(), Map("imgsrc", icon.src));
mainform.result9.image = "icon";
Asynchronous client invocation examples
// the 'setResultX' functions perform the same functions as above
getAsync("SimpleGet", Map(), "setResult1");
getAsync("ComplexGet", Map("param1", "hello world", "param2", "42"), "setResult2");
postAsync("SimplePost", Map("param2", "hello world"), Map("param1", "42"), "setResult3");
jsonAsync("SimpleJson", Map(), Map("bar", 1), "setResult4");
jsonAsync("ComplexJson", Map(), Map("bars", List( Map("foo", Map("baz", "bar")), Map("foo", Map("baz", "but")))), "setResult5");
jsonAsync("ComplexJsonResponse", Map(), Map("bars", List( Map("foo", Map("baz", "bar")), Map("foo", Map("baz", "but")))), "setResult6");
jsonAsync("ComplexJsonDynamic", Map(), Map("bar", Map("foo", Map("baz", "bar"))), "setResult7");
getAsync("SimpleJson", Map("bar", 1), "setResult8");
jsonAsync("DataTest", Map(), Map("imgsrc", icon.src), "setResult9");
Secure client invocation examples
mainform.result1.text = secureGet("SimpleGet", Map());
mainform.result2.text = secureGet("ComplexGet", Map("param1", "hello world", "param2", "42"));
mainform.result3.text = securePost("SimplePost", Map("param2", "hello world"), Map("param1", "42"));
mainform.result4.text = secureJson("SimpleJson", Map(), Map("bar", 1));
mainform.result5.text = secureJson("ComplexJson", Map(), Map("bars", List( Map("foo", Map("baz", "bar")), Map("foo", Map("baz", "but")))));
resp = secureJson("ComplexJsonResponse", Map(), Map("bars", List( Map("foo", Map("baz", "bar")), Map("foo", Map("baz", "but")))));
item1 = mapGet(listGet(resp, 0), "foo");
item2 = mapGet(listGet(resp, 1), "foo");
mainform.result6.text = listSize(resp) ++ " - " ++ mapGet(item1, "baz") ++ " - " ++ mapGet(item2, "baz");
mainform.result7.text = secureJson("ComplexJsonDynamic", Map(), Map("bar", Map("foo", Map("baz", "bar"))));
mainform.result8.text = secureGet("SimpleJson", Map("bar", 1));
icon.src = secureJson("DataTest", Map(), Map("imgsrc", icon.src));
mainform.result9.image = "icon";

All 3 of the above sections are included in the routing-examples.zip attachment.

Targets:

ASP.NET MVC (3/4)

For ease of use, a controller base class has been developed to make communication seamless with the services server. This is included in both attachments called RAMPController.cs.

Simply add this file to you project and inherit from it. For more complex integration, you can use the content of the base class in your custom controllers.

RAMP clients only supports 4 basic datatypes (String, List, Map and Byte arrays), when sending a JSON response, types will be decomposed into Map, likewise arrays into List, the rest String, with the exception of byte arrays that are specially encoded to preserve type information.

The JSON request data will automatically by composed into types, lists, arrays/byte arrays (or even dynamic), if the conversion is possible.

For text/REST based requests, the data is simple types. The response data is a string. 

For JSON responses, the schema is { result: "", error: "" }.

One can use the provided JsonResult and JsonError methods to automatically return the schema as expected by the RAMP server.

Simple controller action examples
public class HomeController : VMT.Mvc.RAMPController
{
  // Simple GET request returning a string.
  public ActionResult SimpleGet()
  {
    return Content("SimpleGet");
  }

  // GET request accepting (query string) parameters.
  // Note: ASP.NET MVC will automatically make sure the input is a valid type.
  public ActionResult ComplexGet(string param1, int param2)
  {
    return Content(string.Format("ComplexGet: p1:{0} p2:{1}", param1, param2));
  }

  // POST request where the parameters are passed as form content
  public ActionResult SimplePost(int param1, string param2)
  {
    return Content("SimplePost: " + param1 + " - " + param2);
  }

  // Same as the get, but returns a JSON object. 
  // Note: The response content-type is 'application/json' and gets handled automatically by the RAMP server.
  public ActionResult SimpleJson(int bar)
  {
    return Json(new { result = bar }, JsonRequestBehavior.AllowGet);
  }
}
Complex controller action examples
// sample container
public class Bar
{
  public Foo foo { get; set; }
}

// sample class
public class Foo
{
  public string baz { get; set; }
}
 
public class HomeController : VMT.Mvc.RAMPController
{
  // JSON request, ASP.NET MVC automatically converted the Map/List/String data from the client.
  public ActionResult ComplexJson(Foo foo)
  {
    return Json(new { result = "ComplexJson: " + foo.baz });
  }

  // A list is passed to the request, and the same list is returned to the client.
  public ActionResult ComplexJsonResponse(Bar[] bars)
  {
    return Json(new { result = bars });
  }

  // Normal post request, receiving byte data from client, rotating the image 90 degree, and returning it.
  // Note: Error checking and resource disposal omitted for clarity.
  public ActionResult DataTest(byte[] imgsrc)
  {
    var str = new MemoryStream(imgsrc);
    var img = Image.FromStream(str);
    img.RotateFlip(RotateFlipType.Rotate90FlipNone);
    var nstr = new MemoryStream();
    img.Save(nstr, System.Drawing.Imaging.ImageFormat.Png);
    return Json(new { result = nstr.ToArray() });
  }
}
 
Dynamic JSON
public class HomeController : VMT.Mvc.RAMPController
{
  // Note: Uses the same 'schema' as the Bar class in previous example.
  public ActionResult ComplexJsonDynamic(dynamic bar)
  {
    return Json(new { result = bar.foo.baz });
  }
}

The above three sections are included as a MVC 3 project (targeting .NET 4) in the routing-examples.zip attachment.

Download

routing.zip

routing-examples.zip

 

  • No labels