Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Maynstall Database WebServices
Contents
Introduction
Within Maynstall, there is a layer of database services which allow a JPA-style data model to be exposed via REST-style web services. These services provide a consistent client-side representation of the POJOs including the ability to modify objects on the client and then persist a transaction of changes to the server. The services also include the following:
- Background loading of related objects upon reference to those objects
- Blocking and non-blocking with events mode of loading data not yet available on the client
- Meta information to inspect pending changes on the client side
- Usage of JPA annotations to support understanding inter-object relationships
- Default JPA provider on the server providing integration with JPA (aka EclipseLink) to automatically expose any object
- Security interceptors to restrict reading, updating, deleting and creating objects based on user and/or attributes being changed
- Registration of model providers allowing mixing of objects from remote WS-based services as well as local JPA DB connections
- Triggers for loading a large portion of the model in a single request for optimization
- Procedures that can be registered via extension point to allow complex Java implementations of queries on the server
- Out-of-band loading of large binary attributes as well as out-of-band uploading of binary data avoiding expensive serialization in the XML payloads
- Lazy loading of large binary attributes with out-of-band download
- Custom depth specification to control amount of data retrieved upon access to an object
Getting Started
To get started with the Maynstall database layer for remote objects, use the attached project set on this Wiki page. It provides you with the right set of projects that you need to work with the services. Note you will also need to EclipseLink or another JPA provider in your workspace / Eclipse install to allow the Maynstall code to resolve the various dependencies.
Download Team Project Set - Media:MaynstallDBWS-projectSet.psf
Overview of Plug-ins
- org.eclipse.maynstall.client.core
- Provides base services for using REST-style web services, and in particular, services that are backed by a Maynstall-based server side (provides simple services for accessing and sending requests)
- org.eclipse.maynstall.client.model.provider
- Registers a provider of Maynstall model contexts that is backed by a remote set of web services including providing transactional commits over the loaded data model.
- org.eclipse.maynstall.common.tracker
- Required to support a dependency in org.eclipse.maynstall.common.ws, not technically used by the Maynstall database web services.
- org.eclipse.maynstall.common.type
- Provides a set of common types used on the client and server side by the data model and data services. Also includes a few references to enums used by the Maynstall provisioning technologies (and is not directly required by the Maynstall database web services).
- org.eclipse.maynstall.common.util
- Provides common utilities leveraged by Maynstall services including services for calculating checksums, dealing with DOM, and accessing files used to configure Maynstall.
- org.eclipse.maynstall.common.ws
- Provides a set of common web service abstractions for building REST-style web services; mainly used as an underlying layer for the data services supported by Maynstall, but can be used as a building block for other REST web services as well.
- org.eclipse.maynstall.model.core
- Provides the main abstraction of the IModelContext and supporting classes which can be used on the client and server side for accessing content from different providers, including remote REST-based provider, and the JPA provider.
- org.eclipse.maynstall.model.provider.common
- Provides the common abstractions used by the different providers to implement the different mechanisms (including custom) model objects.
- org.eclipse.maynstall.server.model.provider
- Provides a JPA implementation of the model provider for leveraging JPA model objects via both the Maynstall model context paradigm as well as typically tied in to the model provider web services for access from a client.
- org.eclipse.maynstall.server.model.provider.ws
- Provides a set of web services to support usage of any model providers remotely via REST-style web services including typical CRUD style object access simply using the JPA annotated objects.
- org.eclipse.maynstall.server.persistence
- Provides base services for using JPA models within the Maynstall web service abstractions.
Coding with the Maynstall DB Access
Step 1: Creating your model
To get started using the remote Maynstall DB access, you must first create your JPA-annotated POJOs that will be made available remotely via Maynstall. When doing this, note that Maynstall respects relationships like OneToMany, ManyToMany, etc. and these must be specified to allow Maynstall to correctly understand the relationships when sending the information to the server side (and when serializing the content back to the client).
Also, Maynstall intercepts the access to the various methods on the model objects. If you are going to implement utility methods on your POJOs, it is currently necessary to use the @ComputedAccessor annotation to flag that certain methods should be left as is, and not attempt to use the lazily loaded model that Maynstall is handling behind the scenes.
This is an area of potential improvement in Maynstall since the code could better understand the field-level definitions to determine what calls / accessors should be intercepted and how.
Step 2: Setting up your model mappings
In Maynstall in each process you have, you can independently map your model to providers. For instance, on the client-side of your application, your model can be mapped to the remote REST-style service whereas on the server, you can map your model to JPA. On either side, if you then use IModelContext, you can access the model objects independently of concern for whether objects are on the client or server. There are extra annotations that can be specified on the object, such as model loading triggers that may only be used on one side of the client.
<extension point="org.eclipse.maynstall.model.core.modelContext"> <modelContext Id="MyClientModelContext" provider="org.eclipse.maynstall.client.model.provider.DefaultClientModelContext"> </modelContext> </extension> <extension point="org.eclipse.maynstall.model.core.modelObjectSet"> <modelObjects modelContext="MyClientModelContext"> <modelObject class="com.foo.bar.User"> </modelObject> <modelObject class="com.foo.bar.Address"> </modelObject> </modelObjects> </extension>
The code above maps the com.foo.bar.User object back to the default client-side model context which uses REST-style web services to retrieve objects from the server.
Step 3: Setting up Maynstall models for the server
For the server side, you need to follow the normal configuration of JPA within OSGi to make sure the JPA model objects are initialized correctly. Similar to the client-side mapping, on the server side objects must be mapped back to the JPAModelContext provider which tells Maynstall that when exposing the objects via the web services to use JPA provider for actually getting the data that is serialized over the wire.
Step 4: Using the Maynstall model context in your code
The following is an example usage of the Maynstall model context using an object that is specified via JPA.
IModelContext context = ModelContext.createModelContext(); // get a user from the context User user = context.get(User.class, "fred"); // if not loaded, can trigger lazy loading of address object Address address = user.getAddress(); // set an attribute locally on an object address.setCity("AnotherCity"); // saves the pending changes to the remote model context context.persist();
Step 5: Optimizing access to objects
Note that if there are performance issues with a distant remote client (high latency network), it is possible to use a trigger pattern to allow data to be loaded on the same request of loading the user.
@Entity @DynamicExposure(procedure = "loadUser") public class User { ...snip... }
In this instance, the @DynamicExposure call is triggered when the client attempts to load the user object for the first time, instead of just loading the User object using the current default depth, the trigger is executed to load the user and associated objects that are typically used without requiring another round trip to the server. Note that procedures can be used outside of triggers for cases where the same set of the model objects may not be loaded the same use-case dependent.
The procedure needs to be defined on the server-side for the set of data to be exposed. For instance:
public class LoadUserProcedure implements IModelContextProcedureHandler { public <T> ExecuteResult execute( IModelContext context, Class<T> clazz, String procedureName, String... args) throws Exception { ...snip... } }
Finally, the procedure needs to be registered via extension point on the server.
<extension point="org.eclipse.maynstall.model.core.modelProcedureHandler"> <modelContextProcedure handler="com.foo.bar.server.procedure.LoadUserProcedure" name="loadUser" target="com.foo.bar.User"> </modelContextProcedure> </extension>
Step 6: Other concepts to review
The following are some key classes / concepts that are used in Maynstall.
- Default Depth
- The depth used when loading objects or lazily loading content when no other explicit depth is specified. On both the search and get calls, a depth can optionally be specified to control how much data is loaded.
- On Demand Loading
- An option of the model context that allows Maynstall to dynamically load objects and attributes on demand when a reference is walked or an attribute accessed that has not yet been accessed. On demand loading leverages the default depth as specified in the model context instance.
- Custom Depths
- Allows creation of custom depths to control which set of attributes and/or relationships are returned from the server. This allows a subset of data to be returned to the client, with the remaining data loaded on demand (if enabled).
- IModelContextMeta
- Provides information on the model including information such as available attributes, pending changes, etc. Can also be used to modify the model generically instead of using reflection.
- SearchCriteria
- Allows for the specification of a search using constructs specified via method constructs instead of a string format.
- IModelRequestInterceptor
- Allows for security services to be integrated into the server restricting access and updating of objects in a model-aware (code-level) mechanism.