You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2014/02/07 15:54:33 UTC
svn commit: r1565668 - in /isis/site/trunk/content: ./
components/objectstores/jdo/ core/services/
Author: danhaywood
Date: Fri Feb 7 14:54:32 2014
New Revision: 1565668
URL: http://svn.apache.org/r1565668
Log:
isis services
Added:
isis/site/trunk/content/components/objectstores/jdo/background-command-service-jdo.md
isis/site/trunk/content/components/objectstores/jdo/command-service-jdo.md
Modified:
isis/site/trunk/content/components/objectstores/jdo/about.md
isis/site/trunk/content/components/objectstores/jdo/auditing-service-jdo.md
isis/site/trunk/content/core/services/auditing-service.md
isis/site/trunk/content/core/services/background-service.md
isis/site/trunk/content/core/services/bulk-interaction.md
isis/site/trunk/content/core/services/xmlsnapshot-service.md
isis/site/trunk/content/documentation.md
Modified: isis/site/trunk/content/components/objectstores/jdo/about.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/components/objectstores/jdo/about.md?rev=1565668&r1=1565667&r2=1565668&view=diff
==============================================================================
--- isis/site/trunk/content/components/objectstores/jdo/about.md (original)
+++ isis/site/trunk/content/components/objectstores/jdo/about.md Fri Feb 7 14:54:32 2014
@@ -25,10 +25,12 @@ The DataNucleus objectstore enables the
### Applib Service Implementations:
- [Eagerly Registering Entities](eagerly-registering-entities.html)
-- [Publishing Service on JDO](publishing-service-jdo.html)
-- [Auditing Service on JDO](auditing-service-jdo.html)
- [Exception Recognizers](exception-recognizers-jdo.html)
- [Settings Services](settings-services-jdo.html)
+- [Command Service on JDO](command-service-jdo.html) [1.4.0-snapshot, stub]
+- [Background Command Service on JDO](command-service-jdo.html) [1.4.0-snapshot, stub]
+- [Publishing Service on JDO](publishing-service-jdo.html)
+- [Auditing Service on JDO](auditing-service-jdo.html)
### Releases
Modified: isis/site/trunk/content/components/objectstores/jdo/auditing-service-jdo.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/components/objectstores/jdo/auditing-service-jdo.md?rev=1565668&r1=1565667&r2=1565668&view=diff
==============================================================================
--- isis/site/trunk/content/components/objectstores/jdo/auditing-service-jdo.md (original)
+++ isis/site/trunk/content/components/objectstores/jdo/auditing-service-jdo.md Fri Feb 7 14:54:32 2014
@@ -9,7 +9,7 @@ The JDO objectstore provides a simple im
Register like any other service in `isis.properties`:
<pre>
-isis.services=<i>...other services...</i>,\
+isis.services=...,\
org.apache.isis.objectstore.jdo.applib.service.audit.AuditingServiceJdo,\
...
</pre>
Added: isis/site/trunk/content/components/objectstores/jdo/background-command-service-jdo.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/components/objectstores/jdo/background-command-service-jdo.md?rev=1565668&view=auto
==============================================================================
--- isis/site/trunk/content/components/objectstores/jdo/background-command-service-jdo.md (added)
+++ isis/site/trunk/content/components/objectstores/jdo/background-command-service-jdo.md Fri Feb 7 14:54:32 2014
@@ -0,0 +1,5 @@
+Title: BackgroundCommandServiceJdo
+
+> this is a stub
+
+
\ No newline at end of file
Added: isis/site/trunk/content/components/objectstores/jdo/command-service-jdo.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/components/objectstores/jdo/command-service-jdo.md?rev=1565668&view=auto
==============================================================================
--- isis/site/trunk/content/components/objectstores/jdo/command-service-jdo.md (added)
+++ isis/site/trunk/content/components/objectstores/jdo/command-service-jdo.md Fri Feb 7 14:54:32 2014
@@ -0,0 +1,5 @@
+Title: BackgroundCommandServiceJdo
+
+> this is a stub
+
+
\ No newline at end of file
Modified: isis/site/trunk/content/core/services/auditing-service.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/core/services/auditing-service.md?rev=1565668&r1=1565667&r2=1565668&view=diff
==============================================================================
--- isis/site/trunk/content/core/services/auditing-service.md (original)
+++ isis/site/trunk/content/core/services/auditing-service.md Fri Feb 7 14:54:32 2014
@@ -46,10 +46,10 @@ An alternative implementation, that pers
### Register the Service
-Register like any other service in `isis.properties`:
+Register like any other service in `isis.properties`. For example, if using the [JDO auditing implementation](../../components/objectstores/jdo/auditing-service.html) then it would be:
isis.services=...,\
- com.mycompany.myapp.isis.SomeAuditingService,\
+ org.apache.isis.objectstore.jdo.applib.service.audit.AuditingServiceJdo,\
...
Modified: isis/site/trunk/content/core/services/background-service.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/core/services/background-service.md?rev=1565668&r1=1565667&r2=1565668&view=diff
==============================================================================
--- isis/site/trunk/content/core/services/background-service.md (original)
+++ isis/site/trunk/content/core/services/background-service.md Fri Feb 7 14:54:32 2014
@@ -1,17 +1,300 @@
Title: Background Service [1.4.0-SNAPSHOT]
-> this is a stub, for `BackgroundService` and `BackgroundCommandService`
+The `BackgroundService`, and its companion `BackgroundCommandService`, enable action invocations to be persisted such that they may be invoked in the background.
+
+The `BackgroundService` is responsible for capturing a memento representing the action invocation, and persisting it. The default `BackgroundServiceDefault` implementation (provided by isis-core) uses (a private copy of) [MementoService](./memento-service.html), and then delegates the persistence of the memento to the companion `BackgroundCommandService` (discussed further [below](#BackgroundCommandService)).
+
+The JDO objectstore provides an implementation of `BackgroundCommandService` ([BackgroundCommandServiceJdo](../../components/objectstores/jdo/background-command-service-jdo.html)) that persists to an RBMS entities. You are welcome to write other implementations to other data stores (eg NoSQL) if required.
+
+The persisting of commands is only half the story; there needs to be a separate process to read the commands and execute them. The `BackgroundCommandExecution` class (also discussed [below](#BackgroundCommandExecution) provides the mechanism to do this.
+
+
+
+## BackgroundService
+
+The `BackgroundService` is the entry point for domain classes wishing to perform actions asynchronously. This can be done in a typesafe way; the (default implementation of) `BackgroundService` actually uses a proxy wrapper around the target so that it can capture the action to invoke and its arguments, and then persist them rather than execute them.
+
+### API & Implementation
+
+Returns a proxy around the object which is then used to obtain the signature of the action to be invoked in the background.
+
+ public interface BackgroundService {
+
+ @Programmatic
+ <T> T execute(final T object);
+ }
+
+The default implementation is provided by core:
+
+* `org.apache.isis.core.runtime.services.background.BackgroundServiceDefault`
+
+
+### Usage
+
+Using the `BackgroundService` is very straight-forward. For example:
+
+ public void submitCustomerInvoices() {
+ for(Customer customer: customerRepository.findCustomersToInvoice()) {
+ backgroundService.execute(customer).submitInvoice();
+ }
+ container.informUser("Calculating...");
+ }
+
+Will create a bunch of background commands executing the `submitInvoice()` method for each of the customers returned from the customer repository.
+
+For the end-user, executing an action that delegates work off to the `BackgroundService` raises the problem of how does the user know the work is complete?
+
+One option is for the background jobs to take responsibility to notify the user themselves. In the above example, this would be the `submitInvoice()` method called upon each customer. One could imagine more complex designs where only the final command executed notifies the user.
+
+However, an alternative is to rely on the fact that the `BackgroundService` will automatically hint that the `Command` representing the original interaction (to `submitCustomerInvoices()` in the example above) should be persisted. This will be available if the related `CommandContext` and `CommandService` domain services are configured, and the `CommandService` supports persistent commands. You can read more about `CommandContext` and `CommandService` [here](./command-context.html).
+
+Thus, the original action can run a query to obtain it corresponding `Command`, and return this to the user. The child `Command`s created by the `BackgroundService` will then be associated with it.
+
+We could therefore refactor the method as follows:
+
+ public Command submitCustomerInvoices() {
+ for(Customer customer: customerRepository.findCustomersToInvoice()) {
+ backgroundService.execute(customer).submitInvoice();
+ }
+ return commandContext.getCommand();
+ }
+
+where `commandContext` field is the injected `CommandContext` domain service.
+
+
+## BackgroundCommandService
+
+The `BackgroundCommandService` is a companion to the default `BackgroundServiceDefault` implementation, and takes responsibility for persisting the required action as a background command.
+
+Typically this service isn't called from domain classes, but it exists as a domain service so that it is pluggable.
+
### API
+The API of the `BackgroundCommandService` is:
+
+ public interface BackgroundCommandService {
+
+ public void schedule(
+ final ActionInvocationMemento aim,
+ final Command command,
+ final String targetClassName, final String targetActionName, final String targetArgs);
+
+ }
+
+where `ActionInvocationMemento` is a wrapper around a [MementoService](./memento-service.html)'s `Memento`, capturing the details of an action invocation (for execution later on).
+
+For the record, the API of `ActionInvocationMemento` is:
+
+ public class ActionInvocationMemento {
+
+ public String getActionId() { ... }
+ public String getTargetClassName() { ... }
+ public String getTargetActionName() { ... }
+ public Bookmark getTarget() { ... }
+ public int getNumArgs() { ... }
+ public Class<?> getArgType(final int num) throws ClassNotFoundException { ... }
+ public <T> T getArg(final int num, final Class<T> type) { ... }
+
+ public String asMementoString() { ... }
+ }
+
+The `asMementoString()` method tehrefore lets the `BackgroundCommandService` implementation convert the action invocation into a simple string.
+
### Implementation
+The JDO object store provides the [BackgroundCommandServiceJdo](../../components/objectstores/jdo/background-command-service-jdo.html) implementation that persists `Command`s to an RDBMS.
+
### Usage
+As noted above, this service isn't intended to be called from domain classes; rather it acts as a plug-in point to the default `BackgroundServiceDefault` service.
+
+## Related Services
+
+These services are closely related to the `CommandContext` and `CommandService` services (both described [here]](./command-context.html) services. The `CommandContext` service is responsible for providing a parent `Command` with which the background `Command`s can then be associated as children, while the `CommandService` is responsible for persisting those parent `Command`s (analogous to the way in which the `BackgroundCommandService` persists the child background `Command`s).
+
+The core framework provides default implementations of `CommandContext` and also `BackgroundService`, and there is very little reason to use any other implementation.
+
+The implementations of `CommandService` and `BackgroundCommandService` also go together; typically both parent `Command`s and child background `Command`s will be persisted in the same way. The JDO objectstore provides implementations of both ([CommandServiceJdo](../../components/objectstores/jdo/command-service-jdo.html) and [BackgroundCommandServiceJdo](../../components/objectstores/jdo/background-command-service-jdo.html)).
+
+## BackgroundCommandExecution
+
+The `BackgroundCommandExecution` (in isis-core) is an abstract template class provided by isis-core that defines an abstract hook method to obtain background `Command`s to be executed:
+
+ public abstract class BackgroundCommandExecution
+ extends AbstractIsisSessionTemplate {
+ ...
+ protected abstract List<? extends Command> findBackgroundCommandsToExecute();
+ ...
+ }
+
+The developer is required to implement this hook method in a subclass.
+
+If using the JDO implementation of `BackgroundCommandService`, then this subclass exists already, namely:
+
+* `org.apache.isis.objectstore.jdo.service.BackgroundCommandExecutionFromBackgroundCommandServiceJdo`
+
+This returns all background `Command`s that are not yet started.
+
+
+## Quartz Scheduler Configuration
+
+The last part of the puzzle is to actually run this class. These could be run in a batch job overnight, or run continually by, say, the [Quartz](http://quartz-scheduler.org) scheduler. For the latter case, we want to define a Quartz cron job that will inherit the `execute(...)` method of `BackgroundCommandExecution` (inherited from *its* superclass, `AbstractIsisSessionTemplate`).
+
+The following does the trick:
+
+ import org.apache.isis.objectstore.jdo.service.BackgroundCommandExecutionFromBackgroundCommandServiceJdo;
+
+ public class BackgroundCommandExecutionQuartzJob extends AbstractIsisQuartzJob {
+
+ public BackgroundCommandExecutionQuartzJob() {
+ super(new BackgroundCommandExecutionFromBackgroundCommandServiceJdo());
+ }
+ }
+
+where `AbstractIsisQuartzJob` is the following boilerplate:
+
+ import org.quartz.Job;
+ import org.quartz.JobExecutionContext;
+ import org.quartz.JobExecutionException;
+ ...
+ public class AbstractIsisQuartzJob implements Job {
+
+ public static enum ConcurrentInstancesPolicy {
+ SINGLE_INSTANCE_ONLY,
+ MULTIPLE_INSTANCES
+ }
+
+ private final AbstractIsisSessionTemplate isisRunnable;
+
+ private final ConcurrentInstancesPolicy concurrentInstancesPolicy;
+ private boolean executing;
+
+ public AbstractIsisQuartzJob(AbstractIsisSessionTemplate isisRunnable) {
+ this(isisRunnable, ConcurrentInstancesPolicy.SINGLE_INSTANCE_ONLY);
+ }
+ public AbstractIsisQuartzJob(AbstractIsisSessionTemplate isisRunnable, ConcurrentInstancesPolicy concurrentInstancesPolicy) {
+ this.isisRunnable = isisRunnable;
+ this.concurrentInstancesPolicy = concurrentInstancesPolicy;
+ }
+
+ // //////////////////////////////////////
+
+ public void execute(final JobExecutionContext context)
+ throws JobExecutionException {
+ final AuthenticationSession authSession = newAuthSession(context);
+ try {
+ if(concurrentInstancesPolicy == ConcurrentInstancesPolicy.SINGLE_INSTANCE_ONLY && executing) {
+ return;
+ }
+ executing = true;
+
+ isisRunnable.execute(authSession, context);
+ } finally {
+ executing = false;
+ }
+ }
+
+ AuthenticationSession newAuthSession(JobExecutionContext context) {
+ String user = getKey(context, SchedulerConstants.USER_KEY);
+ String rolesStr = getKey(context, SchedulerConstants.ROLES_KEY);
+ String[] roles = Iterables.toArray(
+ Splitter.on(",").split(rolesStr), String.class);
+ return new SimpleSession(user, roles);
+ }
+
+ String getKey(JobExecutionContext context, String key) {
+ return context.getMergedJobDataMap().getString(key);
+ }
+ }
+
+This can be configured to run using Quartz' `quartz-config.xml` file:
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <job-scheduling-data
+ xmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData
+ http://www.quartz-scheduler.org/xml/job_scheduling_data_1_8.xsd"
+ version="1.8">
+
+ <schedule>
+ <job>
+ <name>BackgroundCommandExecutionJob</name>
+ <group>Isis</group>
+ <description>Poll and execute any background actions persisted by the BackgroundActionServiceJdo domain service</description>
+ <job-class>webapp.scheduler.BackgroundCommandExecutionQuartzJob</job-class>
+ <job-data-map>
+ <entry>
+ <key>webapp.scheduler.user</key>
+ <value>scheduler_user</value>
+ </entry>
+ <entry>
+ <key>webapp.scheduler.roles</key>
+ <value>admin_role</value>
+ </entry>
+ </job-data-map>
+ </job>
+
+ <trigger>
+ <cron>
+ <name>BackgroundCommandExecutionJobEveryTenSeconds</name>
+ <job-name>BackgroundCommandExecutionJob</job-name>
+ <job-group>Isis</job-group>
+ <cron-expression>0/10 * * * * ?</cron-expression>
+ </cron>
+ </trigger>
+ </schedule>
+ </job-scheduling-data>
+
+The remaining two pieces of configuration are the `quartz.properties` file:
+
+ org.quartz.scheduler.instanceName = SchedulerQuartzConfigXml
+ org.quartz.threadPool.threadCount = 1
+ org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
+ org.quartz.plugin.jobInitializer.class =org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
+ org.quartz.plugin.jobInitializer.fileNames = webapp/scheduler/quartz-config.xml
+ org.quartz.plugin.jobInitializer.failOnFileNotFound = true
+
+and the entry in `web.xml` for the Quartz servlet:
+
+ <servlet>
+ <servlet-name>QuartzInitializer</servlet-name>
+ <servlet-class>org.quartz.ee.servlet.QuartzInitializerServlet</servlet-class>
+ <init-param>
+ <param-name>config-file</param-name>
+ <param-value>webapp/scheduler/quartz.properties</param-value>
+ </init-param>
+ <init-param>
+ <param-name>shutdown-on-unload</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <init-param>
+ <param-name>start-scheduler-on-load</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+All of this stuff is configured in the example todo app, found on github:
+* [BackgroundCommandExecutionQuartzJob]()
+* [AbstractIsisQuartzJob]()
+* [quartz-config.xml]()
+* [quartz.properties]()
+* [web.xml]()
+
+
+## Registering the Services
-### Registering the Services
+Register like any other service in `isis.properties`. For example, if using the default implementation of `BackgroundService` and the JDO implementation of `BackgroundCommandService`, it would be:
+ isis.services=...,\
+ org.apache.isis.core.runtime.services.background.BackgroundServiceDefault,\
+ org.apache.isis.objectstore.jdo.applib.service.background.BackgroundCommandServiceJdo,\
+ org.apache.isis.objectstore.jdo.applib.service.background.BackgroundCommandServiceJdoRepository,\
+ org.apache.isis.objectstore.jdo.applib.service.background.BackgroundCommandServiceJdoContributions,\
+ ...
-### Related Services
+Note that the JDO implementation provides additional supporting `...Repository` and `...Contributions` services to query for and render background `Command`s.
Modified: isis/site/trunk/content/core/services/bulk-interaction.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/core/services/bulk-interaction.md?rev=1565668&r1=1565667&r2=1565668&view=diff
==============================================================================
--- isis/site/trunk/content/core/services/bulk-interaction.md (original)
+++ isis/site/trunk/content/core/services/bulk-interaction.md Fri Feb 7 14:54:32 2014
@@ -5,6 +5,43 @@ Title: Bulk Interaction [1.4.0-SNAPSHOT]
### API
+ @RequestScoped
+ public static class InteractionContext {
+
+ public static enum InvokedAs { BULK, REGULAR }
+
+ public InvokedAs getInvokedAs() { ... }
+
+ public List<Object> getDomainObjects() { ... }
+ public int getSize() { ... }
+ public int getIndex() { ... }
+ public boolean isFirst() { ... }
+ public boolean isLast() { ... }
+
+ }
+
+
+
+ /**
+ * Whether this particular {@link InteractionContext} was applied as a {@link InvokedAs#BULK bulk} action
+ * (against each domain object in a list of domain objects) or as a {@link InvokedAs#REGULAR regular}
+ * action (against a single domain object).
+ */
+ @Programmatic
+
+
+ /**
+ * The list of domain objects which are being acted upon.
+ */
+
+
+ /**
+ * The 0-based index to the object being acted upon.
+ *
+ * <p>
+ * Will be a value in range [0, {@link #getSize() size}).
+ */
+
### Usage
@@ -16,3 +53,35 @@ Title: Bulk Interaction [1.4.0-SNAPSHOT]
### Related Services
+
+
+
+### Unit testing support
+
+
+ @RequestScoped
+ public static class InteractionContext {
+
+
+ /**
+ * Intended only to support unit testing.
+ */
+ public static InteractionContext regularAction(Object domainObject) {
+ return new InteractionContext(InvokedAs.REGULAR, Collections.singletonList(domainObject));
+ }
+
+ /**
+ * Intended only to support unit testing.
+ */
+ public static InteractionContext bulkAction(Object... domainObjects) {
+ return bulkAction(Arrays.asList(domainObjects));
+ }
+
+ /**
+ * Intended only to support unit testing.
+ */
+ public static InteractionContext bulkAction(List<Object> domainObjects) {
+ return new InteractionContext(InvokedAs.BULK, domainObjects);
+ }
+
+ }
\ No newline at end of file
Modified: isis/site/trunk/content/core/services/xmlsnapshot-service.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/core/services/xmlsnapshot-service.md?rev=1565668&r1=1565667&r2=1565668&view=diff
==============================================================================
--- isis/site/trunk/content/core/services/xmlsnapshot-service.md (original)
+++ isis/site/trunk/content/core/services/xmlsnapshot-service.md Fri Feb 7 14:54:32 2014
@@ -5,6 +5,47 @@ Title: XML Snapshot Service [1.4.0-SNAPS
### API
+ public interface XmlSnapshotService {
+
+ public interface Snapshot {
+ public Document getXmlDocument();
+ public Document getXsdDocument();
+
+ public String getXmlDocumentAsString();
+ public String getXsdDocumentAsString();
+ }
+
+ public interface Builder {
+ public void includePath(final String path);
+ public void includePathAndAnnotation(final String path, final String annotation);
+ }
+
+ public static class Exception extends RuntimeException { ... }
+
+ @Programmatic
+ public XmlSnapshotService.Snapshot snapshotFor(final Object domainObject);
+
+ @Programmatic
+ public XmlSnapshotService.Builder builderFor(final Object domainObject);
+
+ public Document asDocument(String xmlStr);
+
+ public <T> T getChildElementValue(final Element el, final String tagname, final Class<T> expectedCls);
+
+ public Element getChildElement(final Element el, final String tagname);
+
+ public String getChildTextValue(final Element el);
+ }
+
+
+where:
+
+* `asDocument()` is a convenience to convert xml string back into a W3C Document
+* `getChildElementValue()` is a convenience to extract the value of an XML element, based on its type.
+* `getChildElement()` is a convenience method to walk XML document.
+* `getChildTextValue()` is a convenience method to obtain value of child text node.
+
+
### Usage
Modified: isis/site/trunk/content/documentation.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/documentation.md?rev=1565668&r1=1565667&r2=1565668&view=diff
==============================================================================
--- isis/site/trunk/content/documentation.md (original)
+++ isis/site/trunk/content/documentation.md Fri Feb 7 14:54:32 2014
@@ -472,10 +472,12 @@ Note: this viewer is third-party open so
<p class="display:none"/>
- [Eagerly Registering Entity Types](components/objectstores/jdo/eagerly-registering-entities.html)
+ - [Exception Recognizers](components/objectstores/jdo/exception-recognizers-jdo.html)
+ - [Settings Services on JDO](components/objectstores/jdo/settings-services-jdo.html)
+ - [Command Service on JDO](components/objectstores/jdo/command-service-jdo.html) [1.4.0-snapshot, stub]
+ - [Background Command Service on JDO](components/objectstores/jdo/command-service-jdo.html) [1.4.0-snapshot, stub]
- [Publishing Service on JDO](components/objectstores/jdo/publishing-service-jdo.html)
- [Auditing Service on JDO](components/objectstores/jdo/auditing-service-jdo.html)
- - [Exception Recognizers](components/objectstores/jdo/exception-recognizers-jdo.html)
- - [Settings Services on JDO](components/objectstores/jdo/settings-services-jdo.html) [1.3.0]
}