To access a service, you must specify both how to interact with the external logic and where it resides. You can think of the two kinds of information in an abbreviated way: "how" and "where."
For background information, see Resource bindings.
myBindingVar IHttp?{@Resource {uri="binding:myEntry"}}; call MyServiceType.myFunction("abc") // "how" using myBindingVar // "where" returning to myCallBackFunction onException myExceptionHandler;
The example uses the IHttp? Interface type for flexibility. Later, if you want to switch to a different kind of access target, you switch to a different deployment descriptor. You will not need to change the invocation, and you will not need to regenerate the example.
call MyServiceType.myFunction("abc") // "how" // "where" (the service is deployed // with the Rich UI application) returning to myCallBackFunction onException myExceptionHandler;
This second case is even simpler, but any future use of an EGL REST-RPC service requires that you change the invocation and regenerate the example code.
If you are accessing a REST or EGL REST-RPC service, you can encapsulate the "how" and "where" information in a single location, by adding a proxy function to a library or handler. The call statement invokes the proxy function, which acts as an intermediary between that statement and the backend code. You also specify a third kind of information in the proxy function, for use by the EGL generator that is storing invocation code in place of the annotations.
function myProxyFunction(p1 string, p2 string) RETURNS(int) {} end
You do not write any logic for the proxy function. Instead, you tell an EGL generator what is required. In particular, you specify an annotation that is specific to the kind of backend code that will be invoked.
function myProxyFunction(p1 string, p2 string) RETURNS(int) // "how" { @EglService{serviceName="MyServiceType"} // "what more" does // the generator need? } end
function myProxyFunction02(p1 string, p2 string) RETURNS(int) // "how" { @Rest // "what more" does // the generator need? { method = HttpMethod._GET, uriTemplate = "/org/search/?string01={p1}&string02={p2}" } } end
function myProxyFunction(p1 string, p2 string) RETURNS(int) // "how" { @EglService{serviceName="MyServiceType"}, // "what more" @Resource{uri = "binding:myEntry"} // "where" } end function myProxyFunction02(p1 string, p2 string) RETURNS(int) // "how" { @Rest // "what more" { method = HttpMethod._GET, uriTemplate = "/org/search/?string01={p1}&string02={p2}" }, @Resource{uri = "binding:myEntry02"} // "where" } end
The "where" information that you specify in the proxy function is optional and, if present, is a default. The detail is ignored if you specify the "where" detail in the code that invokes the proxy function.
function myProxyFunction02(p1 string, p2 string) RETURNS(int) // "how" { @Rest // "what more" { method = HttpMethod._GET, uriTemplate = "/org/search/?string01={p1}&string02={p2}" }, @ExternalName{value = "my-Operation"}, // "what more" @Resource{uri = "binding:myEntry02"} // "where" } end
The primary reason to declare an ExternalName annotation is that the name of a third-party service operation is not valid as the name of an EGL proxy function.
You say, "I can specify the 'how' and 'where' information in two places. What is the best practice?"
call myProxyFunction("abc") // "how" and "where" returning to myCallBackFunction onException myExceptionHandler;
As shown, you have no binding variable and have hidden the "how" and "where" information in the proxy function.
call MyServiceType.myFunction("abc") // "how" // "where" (the service is deployed // with the Rich UI application) returning to myCallBackFunction onException myExceptionHandler;
Although you can run the deployed service during an EGL debugging session, the EGL debugger will not step into the service.
A workspace URI is useful only at development time, when an internal Test Server enables you to debug the code. The Test Server is described here: EGL test server.
In this case, your task in the EGL Deployment Descriptor editor is twofold: you update not only the Resource Binding tab, but the Service Deployment tab as well. That secondary requirement ensures that the deployment descriptor file includes the detail necessary to deploy the service. However, before you fulfill the EGL deployment step, you'll need to ensure that the URI in the resource binding is pointing to the deployed EGL REST-RPC service.
At this writing, you can bind to a REST, EGL REST-RPC, or dedicated service. The distinctions among the service types are explained here, with "binary-exchange service" in place of the more narrowly defined "dedicated service": Service-oriented architecture (SOA) for EGL developers (http://www.eclipse.org/edt/papers/topics/egl_soa_overview.html).
For details on defining a REST or EGL REST-RPC service binding in the EGL deployment descriptor, see Adding a REST binding to the EGL deployment descriptor.
If you are defining a workspace binding, you must also deploy the Service type. For details, see Adding web-service deployment details to the EGL deployment descriptor.
myBindingVariable IHttp? = Resources.getResource("binding:myEntry"); myBindingVariable.request.encoding = encoding.json; myBindingVariable.request.headers = new dictionary{edt.proxy.invocation.timeout = 6}; call myProxyFunction() using myBindingVariable returning to myCallBackFunction onException myExceptionHandler; end
The example is accessing an instance of an HttpRest object.
myBindingVariable IHttp? = new HttpRest{ restType = eglx.rest.ServiceType.TrueRest, request.uri = "http://www.example.com/myproject/restservices/weather_service", request.encoding = Encoding.json, request.headers = new dictionary{edt.proxy.invocation.timeout = 6}}; call myProxyFunction() using myBindingVariable returning to myCallBackFunction onException myExceptionHandler; end
For details on the HttpRest object, see eglx.http package.