Skip to content
This repository has been archived by the owner on Feb 22, 2019. It is now read-only.
Pavel Vlasov edited this page Feb 19, 2016 · 6 revisions

Classes, interfaces, annotations and extensions in this bundle are used to expose application functionality over HTTP.

Concepts

  • Routes - match HTTP requests to application actions. Routes can be chained, e.g. a root route can deleage to an object route, which can delegate to another object route or to an extension route.
    • Root routes - Use HTTP method and path pattern for matching.
    • Object routes - Use context object type, HTTP method, and path pattern for matching.
    • Extension routes - Similar to object routes but use extension string instead of pattern for matching.
  • RoutingServlet - dispatches requests to root routes loaded from services and extensions by ExtensionManager
  • WebContext - instances of web context or its subtypes are passed to route.execute() method.
  • ObjectPathResolver - resolves object path, is used to construct HTTP references.
  • UIPart - contribution to a particular object type UI.

Extension points

  • HTML Factory - declares HTML factory accessible by adapting context to HTMLFactory. The factory is used to build Web UI.
  • Object Path Resolver - extension point for registering object path resolvers.
  • Route - extension points for registering routes.
  • UI Part - registers UI parts for a particular class.

Examples

Examples are taken from the Server and Examples repository.

Routing servlet

Declaration in plugin.xml:

<extension point="org.eclipse.equinox.http.registry.servlets">
  <servlet
         alias="/router"
         class="org.nasdanika.web.RoutingServlet">
     <init-param
           name="json-pretty-print"
           value="true">
     </init-param>
  </servlet>
</extension>

Init parameters

  • jsonPrettyPrint - true value causes JSON output to be indented.
  • adapter-service-filter - service filter for adapter services
  • route-service-filter - service filter for route services
  • ui-part-service-filter - service filter for UI part services
  • html-factory - Name of HTML factory extension to use
  • default-access-decision - deny sets default access decision to DENY, ALLOW otherwise

Routes

Root route

Route extension

Routes to AppRoute which implements Route. Declaration in plugin.xml:

<extension point="org.nasdanika.web.route">
  <root-route
        class="org.nasdanika.examples.bank.app.AppRoute"
        method="GET"
        pattern="app.html">
  </root-route>
</extension>
Route service

credit-cards-cdo-transaction-context-provider.xml component provides a root route service which opens CDO Transaction and uses object routes for navigating to repository objects:

<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.nasdanika.examples.bank.app">
   <implementation class="org.nasdanika.cdo.web.CDOViewContextAutocloseRouteComponent"/>
   <property name="pattern" type="String" value="nasdanika(\..+)?(/.+)?"/>
   <property name="method" type="String" value="GET"/>
   <service>
      <provide interface="org.nasdanika.web.Route"/>
   </service>
   <reference 
       bind="setContextProvider" 
       cardinality="1..1" 
       interface="org.nasdanika.cdo.CDOTransactionContextProvider" 
       name="CDOTransactionContextProvider" 
       policy="static" 
       unbind="clearContextProvider"/>
   <property name="type" type="String" value="root"/>
</scr:component>

If pattern property contains ${bundleId} token(s), this token is expanded to bundle id. This allows avoid route conflicts in situations when component routes do not serve application landing pages, but are referenced from such pages. In this case the landing page component can lookup bundles to be referenced by symbolic name and version using BundleContext.getBundles() method and generate links to routes exposed by bundle's components. This kind of assembly of a web application from loosely coupled components is similar and complementary to the UI parts approach.

Object route

Declaration in plugin.xml:

<object-route
      class="org.nasdanika.cdo.web.routes.CDOTransactionRoute"
      method="*"
      target="org.eclipse.emf.cdo.transaction.CDOTransaction">
</object-route>

Routes are matched indirectly when WebContext.getAction(Object target, int pathOffset) method is invoked.

EOperation route annotations

EOperations can be annotated with org.nasdanika.cdo.web:route and org.nasdanika.cdo.web:home-route to instruct the framework to route requests to annotated operations. These annotations support the following details:

  • action - security action for authorization check, defaults to HTTP method name.
  • qualifier - sequrity qualifier for authorization check, defaults to operatin name.
  • method - a comma separated list of HTTP methods to match, matches any method if omitted.
  • path - path to match, can contain path parameters in {}, e.g. statement/{year}/{month}. Path takes precedence over pattern
  • pattern - regex pattern to match request path. Not applicable to the home route annotation. If omitted, path length shall be 1 and equal to the operation name.
  • produces - response content type. Optional.
  • consumes - request content type. Optional, used to match request to method.

Home route matches the object path with .html extension, e.g. L3.html.

Parameter annotations

  • org.nasdanika.cdo:context-parameter - argument is computed by adapting the context
  • org.nasdanika.cdo:service-parameter - argument is computed by looking up an OSGi service with parameter's type, an optional filter data entry can be used to specify service filter.
  • org.nasdanika.cdo:query-parameter - argument is taken from a query parameter(s) with the name taken from name data entry. If there is no such query parameter, argument value is taken from defaultValue annotation data entry.
  • org.nasdanika.cdo:path-parameter - argument is taken from a named path segment with the name taken from name data entry. If there is no such path segment, argument value is taken from defaultValue annotation data entry.
  • org.nasdanika.cdo:cookie-parameter - argument is taken from a request cookies(s). An optional name data entry can be used to filter cookies by name.

HTML Factory

Declaration in plugin.xml:

<extension
      point="org.nasdanika.web.html_factory">
   <default_html_factory>
         <stylesheet>/bootstrap/css/bootstrap.min.css</stylesheet>
         <stylesheet>
            /bootstrap/css/bootstrap-theme.min.css
         </stylesheet>
         <script>
            /js/jquery-2.1.0.min.js
         </script>
         <script>
            /js/underscore-min.js
         </script>
         <script>/js/backbone-min.js</script>
         <script>/bootstrap/js/bootstrap.min.js</script>
         <script>
            /js/require.js
         </script>
   </default_html_factory>
</extension>

Accessing by adapting context:

context.adapt(HTMLFactory.class)

Object path resolver

Extension in plugin.xml:

<resolver
      class="org.nasdanika.cdo.web.objectpathresolvers.CDOResourcePathResolver"
      target="org.eclipse.emf.cdo.eresource.CDOResource">
</resolver>

Implementation - CDOResourcePathResolver:

public class CDOResourcePathResolver implements ObjectPathResolver<CDOResource> {

	@Override
	public String resolve(CDOResource obj, ObjectPathResolver<Object> master, Context context) throws Exception {
		CDOView view = obj.cdoView();
		if (view==null) {
			return null;
		}
		String viewPath = master.resolve(view, null, context);
		if (viewPath==null) {
			return null;
		}
		return viewPath+"/elements"+obj.getPath();
	}

}

Indirect use by invoking getObjectPath() in CDOViewToHTMLRendererConverter:

for (CDOResourceNode e: source.getElements()) {
	String pe = context.getPath()[0];
	int didx = pe.lastIndexOf('.');
	if (didx!=-1) {
		pe = pe.substring(0, didx);
	}
	if (context instanceof HttpContext) {
		elements.add(htmlFactory.routeLink(null, "/"+((HttpContext) context).getObjectPath(e)+".html", e.getName()).toString()); // TODO - escape names
	}
}

UI Part

Extension point

Declaration in plugin.xml:

<extension point="org.nasdanika.web.ui_part">
    <ui_part
          category="tabs"
          class="org.nasdanika.examples.bank.app.ProtectedActionsUIPart"
          target="org.eclipse.emf.ecore.EClass">
    </ui_part>
</extension>

ProtectedActionsUIPart.java:

public class ProtectedActionsUIPart implements UIPart<HttpContext, NamedItemsContainer<?>> {

	@Override
	public void create(HttpContext context, NamedItemsContainer<?> out,	Map<String, Object> environment) throws Exception {
		// if permission
		out.item("Protected actions", "Coming soon");
		
	}

}

Collection of UI parts for EClass in EObjectToHTMLRendererConverter.java:

context.buildUICategory("tabs", listsAndContainmentsTabs, null);
Service

offers-ui-part-component.xml:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Offers UI Part">
   <implementation class="org.nasdanika.examples.bank.app.OffersUIPart"/>
   <service>
      <provide interface="org.nasdanika.web.html.UIPart"/>
   </service>
   <property name="target" type="String" value="org.nasdanika.examples.bank.Customer"/>
   <property name="category" type="String" value="right-panel"/>
</scr:component>

OffersUIPart.java:

public class OffersUIPart implements UIPart<HttpContext, Fragment> {

	@Override
	public  void create(HttpContext context, Fragment out, Map<String, Object> environment) throws Exception {
		out.content(context.adapt(HTMLFactory.class).alert(Style.SUCCESS, true, "0% APR on balance transfers for 15 months"));
	}

}

Collection of ui parts in CustomerImpl:

Fragment rightPanelContent = htmlFactory.fragment();
context.buildUICategory("right-panel", rightPanelContent, null);
if (!rightPanelContent.isEmpty()) {
	mainPanel.width(DeviceSize.LARGE, 9);
	appPanel.contentPanel(rightPanelContent).width(DeviceSize.LARGE, 3);
}

How it is rendered:

Customer home screen