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]
 
   
 }