Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

EDT:Resource Binding Services

Resource Binding Introduction


To access a service, you must specify 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."

Specifying "how" and "where" in the call statement

If you are accessing a service that was written in EGL, you can specify "how" and "where" in the call statement.

The usage is particularly simple and is available whether the service is being deployed as an EGL REST-RPC service (outside of a Rich UI application) or as a dedicated service (along with a Rich UI application): 

  • An example of accessing an EGL REST-RPC service:
myBindingVar HttpRest{@Resource {uri="binding:myDD#myEntry"}};

call 
   MyServiceType.myFunction("abc")          // "how"
   using myBindingVar                       // "where"
   returning to myCallBackFunction
   onException myExceptionHandler;
 
  • An example of accessing a dedicated service:
myBindingVar HttpProxy{};

call 
   MyServiceType.myFunction("abc")          // "how"
   using myBindingVar                       // "where"
   returning to myCallBackFunction
   onException myExceptionHandler;



Specifying "how" and "where" in a proxy function

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 back-end code.

(The proxy-function construct has been in use for some time, for IBM i program access. The construct is now in use for service access, too. The change for service access occurred after EDT version .081 Milestone 2. For details on the prior support for service access, see the EDT help topics in the build for 0.81 Milestone 2.) 

At development time, the proxy function is empty. It lists the invocation parameters and, if appropriate, a return type. Here is the outline of such a function:

function myExternalLogic(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 back-end code that will be invoked. 

Here are examples:

  • For a REST service invocation, declare a Rest annotation:

function myExternalLogic(p1 string, p2 string)RETURNS(int) {
   @Rest                                                             // "how"
   {
      method = HttpMethod._GET, 
      uriTemplate = "/org/search/?string01={p1}&string02={p2}" 
   }  
}
end


  • For an EGL REST-RPC service invocation, declare an EglRestRPC annotation:

function myExternalLogic(p1 string, p2 string)RETURNS(int) {
   @EGLRestRpc{serviceName="MyServiceType.myFunction"}               // "how"
}
end


To add "where" information to the proxy function, specify the Resource annotation at the same level as the other annotation.  Here is an example:

 
function myExternalLogic(p1 string, p2 string)RETURNS(int) {
   @Rest {                                                           // "how"
      method = HttpMethod._GET, 
      uriTemplate = "/org/search/?string01={p1}&string02={p2}" 
   },
   @Resource{uri = "binding:myDD#myEntry"}                           // "where"  
}
end


The "where" information that you specify in the proxy is a default.  The detail is not used if you specify "where" detail in the code that invokes the proxy function.

Deciding on the best practice for "how" and "where"

You say, "I can specify the 'how' and 'where' information in two places. What is the best practice?"

The proxy function is particularly useful when you are accessing a service that is in a more-or-less permanent location. In this case, you have the minor complexity of creating a proxy function, but you invoke the back-end logic simply:

call 
   myExternalLogic("abc")                    // "how" and "where"
   returning to myCallBackFunction         
   onException myExceptionHandler;

As shown, you have no binding variable and have hidden the "where" and "how" information in the proxy function.

If you are coding a service written in EGL, you might avoid coding a proxy function at all. In this case, you rely on the Service type to tell "how." Two variations apply:

  • If you are accessing a dedicated service, the EGL deployer handles the "where" automatically. You can write a call statement without specifying a binding variable or a call-statement using clause:
call 
   MyServiceType.myOperation("abc")           // "how" and "where"
   returning to myCallBackFunction
   onException myExceptionHandler;
  • If you are developing an EGL REST-RPC service and want to switch access easily between the code being developed and, later, the code that is deployed, consider declaring a binding variable of type IHttp, which is an Interface type. You then assign one of two types of values to that variable.

    Here is a partial  example:
function callTheService()
   myBindingVar IHttp? = getEndPoint();
    	
   call 
      MyServiceType.myFunction()            // "how"
      using myBindingVar                    // "where" 
      returning to myCallBackFunction
      onException myExceptionHandler;    		
   end

function getEndPoint() returns(IHttp)
   http IHttp?;
   try
      http = Resources.getResource("binding:myDD#myEntry");   // "where" for an EGL REST-RPC service
      onException(exception AnyException)
   end
        
   if (http == null)
      http = new HttpProxy;                                   // "where" for a service under development or deployed as dedicated
   end
   return http;
end

If the EGL DD entry is present, the call statement accesses an EGL REST-RPC service. In that case, the binding variable has a value of type EGLRestRpc. If the EGL DD entry is absent, the call statement accesses the service under development or, at run time, a dedicated service. In those cases, the binding variable has a value of type HttpProxy.

Specifying the main detail in a service binding

A resource binding that is specifically for service access is known as a service binding.  The main detail there is in one of three categories:

  • If the service is deployed on an application server, you can specify a Universal Resource Identifier (URI) that begins with the http: or https: prefix. Here is an example:
http://myserver:8080/myproject/restservices/myService
Although you can run the deployed service during an EGL debugging session, the EGL debugger does not step into the service.
  • If the service is available in your workspace and was written in EGL, you can use a workspace URI, which is an identifier that points to a workspace location. Here is an example:
workspace://mySourceProject/servicepackage.myService
In this case, the URI is useful only at development time, and an internal Test Server enables you to debug the code. In this case, your task in the EGL Deployment Descriptor editor is twofold: to update the Service Deployment tab as well as the Resource Bindings tab. You must arrange for service deployment.
  • If a Rich UI application includes a Service type that will be deployed as a dedicated service, an Internal Test Server enables you to debug the code.

    In this case, the EGL deployment descriptor is never used.


Defining a service binding in the EGL deployment descriptor

At this writing, you can bind to a REST or EGL REST-RPC service. The distinctions among the service types are explained here: http://www.eclipse.org/edt/papers/topics/egl_soa_overview.html

To define a service binding in the EGL deployment descriptor, do as follows:

  • In an EGL project, expand the EGLSource folder and double-click the deployment descriptor, which has the file extension .egldd.  
  • Click the Resource Bindings tab. The Resource Bindings Configuraton page is displayed.
  • Click Add and, at the Add a Resource Binding page, select REST Service Binding. The Add a REST Service Binding page is displayed, as shown here:

Bind Img8.JPG


  • In the topmost field, specify the binding name. You can reference that name in your code, whether in a Resource annotation or in a statement that invokes the Resources.getResource function.
  • In the Base URI field, specify a URI, which might be a workspace URI:
    • If you are accessing an EGL REST-RPC service, specify the complete URI.
    • If you are accessing a third-party REST service, you might decide to include only high-level details and to supplement them with values that are stored in an Interface type. For specifics, see the following help topic: "Creating an Interface part to access a REST service."
  • The sessionCookieID field is not in use.

If you are defining a service binding for a Service type in your workspace, you must ensure that the service will be deployed: 

  • Switch to the Service Deployment tab. If the service is not already listed, click Add. The Add Web Services page is displayed.

Bind Img6.JPG 

  • Highlight the Service type of interest, click Add, and click Finish. The Web Service Deployment tab is re-displayed with the new detail.

Bind Img7.JPG

  • To save the deployment descriptor, press Ctrl-S.

[ the rest of this page is being rewritten.... ]

Retrieving a service binding and changing it in your code

Here is an example of preparing a variable and then using it to access a third-party REST service:

myService MyServiceType?;                                          
http HttpRest{@Resource{uri="binding:myService"}};                  /.8 syntax
http.request.encoding = encoding.json;                                  
call myService.myFunction() using http                              /.8 syntax 
   returning to myCallBackFunction 
   onException myExceptionHandler;


The code acts as follows:

  1. Declares an access variable. 

    The declaration references an Interface type that typically includes one or more uriTemplate annotation fields, each of which is a set of lower-level URI qualifiers that are resolved at run time. A resolved template might be this: /GetWeatherByZipCode?zipCode=27709 

  2. Accesses a new instance of an HTTPRest object.

    That object provides a higher-level URI such as http: //www.example.com/myproject/restservices/weather_service

    In this case, the object contains details that are retrieved from a service binding in the EGL deployment descriptor. If you do not specify a uri annotation field, the name of the service binding is assumed to be the name of the variable. In the example, the value of the annotation field defaults to "binding:myService".

    For details on the HttpRest object, see the help topic named "eglx.http package."

  3. Adds detail to the HTTPRest object; for example, to ensure that data is transferred to and from the service in JSON format.

  4. Invokes the Resources.completeBind function so that the variable references the HTTPRest object.

Creating a service binding in your code

You can create a service binding in your code, in which case the EGL deployment descriptor is not involved. For example, you might substitute the second statement in the following code for the object declaration that was shown in the preceding section:

myService IMyService?; 
http HttpRest = new HttpRest{
   restType = eglx.rest.ServiceType.TrueRest, 
   uri = "www.example.com/myproject/restservices/weather_service"};
myBinding.request.encoding = Encoding.json;
call myService.myFunction() using http                             // .8 syntax   
   returning to myCallBackFunction
   onException myExceptionHandler;

For details on the HttpRest object, see the help topic named "eglx.http package."


Next:  SQL database bindings

Previous:  Resource binding introduction

Back to the top