Gaelic Mardao

REST service framework for Google App Engine

License

License

GroupId

GroupId

com.wadpam.gaelic
ArtifactId

ArtifactId

gaelic-mardao
Last Version

Last Version

1.0.8
Release Date

Release Date

Type

Type

jar
Description

Description

Gaelic Mardao
REST service framework for Google App Engine

Download gaelic-mardao

How to add to project

<!-- https://jarcasting.com/artifacts/com.wadpam.gaelic/gaelic-mardao/ -->
<dependency>
    <groupId>com.wadpam.gaelic</groupId>
    <artifactId>gaelic-mardao</artifactId>
    <version>1.0.8</version>
</dependency>
// https://jarcasting.com/artifacts/com.wadpam.gaelic/gaelic-mardao/
implementation 'com.wadpam.gaelic:gaelic-mardao:1.0.8'
// https://jarcasting.com/artifacts/com.wadpam.gaelic/gaelic-mardao/
implementation ("com.wadpam.gaelic:gaelic-mardao:1.0.8")
'com.wadpam.gaelic:gaelic-mardao:jar:1.0.8'
<dependency org="com.wadpam.gaelic" name="gaelic-mardao" rev="1.0.8">
  <artifact name="gaelic-mardao" type="jar" />
</dependency>
@Grapes(
@Grab(group='com.wadpam.gaelic', module='gaelic-mardao', version='1.0.8')
)
libraryDependencies += "com.wadpam.gaelic" % "gaelic-mardao" % "1.0.8"
[com.wadpam.gaelic/gaelic-mardao "1.0.8"]

Dependencies

compile (3)

Group / Artifact Type Version
com.wadpam.gaelic : gaelic-core jar 1.0.8
net.sf.mardao : mardao-core jar 2.3.3
org.slf4j : slf4j-api jar 1.6.1

provided (1)

Group / Artifact Type Version
javax.servlet : servlet-api jar 2.5

test (8)

Group / Artifact Type Version
junit : junit jar 4.8.1
org.springframework : spring-test jar 3.2.0.RELEASE
org.slf4j : slf4j-log4j12 jar 1.6.1
com.google.appengine : appengine-api-1.0-sdk jar 1.7.7
com.google.appengine : appengine-testing jar 1.7.7
com.google.appengine : appengine-api-labs jar 1.7.7
com.google.appengine : appengine-api-stubs jar 1.7.7
net.sf.mardao : mardao-gae jar 2.3.3

Project Modules

There are no modules declared in this project.

Gaelic

REST framework for Google App Engine

Generate starter project using Maven Archetype

mvn archetype:generate -DarchetypeGroupId=com.wadpam.gaelic -DarchetypeArtifactId=gaelic-archetype-starter -DarchetypeVersion=1.0.8

If this is your first time using this App Engine SDK of the version, download and unpack the SDK by typing

mvn gae:unpack

in the generated projects directory. Then, build your project and start your development server with

mvn clean gae:run

Introduction

Gaelic was created when we wanted to replace Spring framework with something more suitable for Google App Engine. We had suffered bad from (too) long initialization times (loading requests), and needed something that initializes very quickly.

We tried Jersey, but decided to give up the following:

  • Annotation-based mapping of resources / controllers
  • Compatibility with non-GAE environments

and push hard for

  • Convention over Configuration
  • Very few dependencies

Supported Features

and non-functional requirements:

  • Core dependency only to Jackson and Slf4j
  • Security adds dependency to commons-codec

Application Configuration

The GaelicServlet requires an implementation of the GaelicConfig to be specified as an init-param in web.xml:

<servlet>
    <servlet-name>GaelicServlet</servlet-name>
    <servlet-class>com.wadpam.gaelic.GaelicServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <init-param> 
        <param-name>com.wadpam.gaelic.Config</param-name> 
        <param-value>com.example.config.AppConfig</param-value> 
    </init-param> 
</servlet>

The Configuration is instantiated and the

    Node init(GaelicServlet gaelicServlet, ServletConfig servletConfig);

method is invoked. It should return your one root Node (subclass) instance.

Here's a simple Config example:

public class UnitTestConfig implements GaelicConfig, SecurityConfig {

    @Override
    public Node init(GaelicServlet gaelicServlet, ServletConfig servletConfig) {

        DomainSecurityInterceptor securityInterceptor = new DomainSecurityInterceptor();

        SecurityDetailsService detailsService = new UnitTestDetailsService();
        securityInterceptor.setSecurityDetailsService(detailsService);

        Collection<Map.Entry<String, Collection<String>>> basicWhitelist = WHITELIST_BUILDER
                .with("\\A/api/[^/]+/public\\z", GET)
                .build();
        securityInterceptor.setWhitelistedMethods(basicWhitelist);

        // add /api/{domain}
        BUILDER.root()
            .path("api")
                .interceptedPath("{domain}", securityInterceptor)
                    // add /endpoints
                    .add("endpoints", MethodUriLeaf.class).named("getEndpoints()");

        BUILDER.from("{domain}")
                    // add public whitelisted
                    .add("public", MethodUriLeaf.class).named("public");

        BUILDER.from("{domain}")
                    // add _admin
                    .path("_admin")
                        .add("task", MethodUriLeaf.class).named("AdminTask");

        return BUILDER.build();
    }

}

It creates and maps the following resource tree:

  • /api
  • /api/{domain}
  • /api/{domain}/endpoints
  • /api/{domain}/public
  • /api/{domain}/_admin/task

Where

  • the Security interceptor is mapped to /api/* requests
  • endpoints is a protected resource
  • GET public has public access
  • task should be Container-based secured via web.xml

Interceptors

Interceptors are implemented either by implementing the Interceptor interface, or by extending the InterceptorAdapter class. The interceptors should be injected into either InterceptorDelegate node, or into InterceptedPath path.

Security

Three security interceptors are provided by the Gaelic framework:

SecurityInterceptor extends InterceptorAdapter
+ - DomainSecurityInterceptor extends SecurityInterceptor
    + - OAuth2Interceptor extends DomainSecurityInterceptor

CRUD Resources

There is a CrudLeaf you can extend or map in the tree, to get out-of-the-box methods for the basic CRUD operations:

  • GET / a page of entities
  • GET /{id} a specific entity
  • POST / to create a new entity
  • POST /{id} to update a specific entity
  • DELETE /{id} to delete a specific entity

There is also a CrudService implementation with connects your Resource with the Datastore using Mardao.

App Domain

With the concept of App Domains, you can host for multiple, separated customers from the same App Engine application. Their data is separated (multi-tenancy) by using Namespaces. Convention is to select domain via the REST path, e.g.

http://example.appspot.com/api/bmw/user

where the App Domain would be named bmw. This App Domain entity also has properties for username and password, so you can protect some API methods within /api/bmw/ with Basic Authentication. An App Domain also has a tracking code property, allowing to send tracking for /api/bmw to a bmw-dedicated Analytics Account (e.g. Google Analytics).

OAuth2 Provider

Look at the sub-module gaelic-oauth2-provider README page for more information on OAuth2 Provider implementation.

Versions

Version
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.2