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 2015/06/16 07:42:15 UTC
[27/45] isis git commit: ISIS-1133: breaking out reference guide and
devenv guide;
moving appendices' release notes and migration notes to other docs;
improving the documentation page.
http://git-wip-us.apache.org/repos/asf/isis/blob/9c5dafab/adocs/documentation/src/main/asciidoc/guides/_ug_testing_fixture-scripts_sudo-service.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_testing_fixture-scripts_sudo-service.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_fixture-scripts_sudo-service.adoc
new file mode 100644
index 0000000..2c1172e
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_fixture-scripts_sudo-service.adoc
@@ -0,0 +1,59 @@
+[[_ug_testing_fixture-scripts_sudo-service]]
+= `SudoService`
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+:_basedir: ../
+:_imagesdir: images/
+
+
+
+Sometimes in our fixture scripts we want to perform a business action running as a particular user. This might be for the usual reason - so that our fixtures accurately reflect the reality of the system with all business constraints enforced using the `WrapperFactory` - or more straightforwardly it might be simply that the action depends on the identity of the user invoking the action.
+
+An example of the latter case is in the (non-ASF) http://github.com/isisaddons/isis-app-todoapp[Isis addons' todoapp]'s `ToDoItem` class:
+
+[source,java]
+.Production code that depends on current user
+----
+public ToDoItem newToDo(
+ @Parameter(regexPattern = "\\w[@&:\\-\\,\\.\\+ \\w]*") @ParameterLayout(named="Description")
+ final String description,
+ @ParameterLayout(named="Category")
+ final Category category,
+ @Parameter(optionality = Optionality.OPTIONAL) @ParameterLayout(named="Subcategory")
+ final Subcategory subcategory,
+ @Parameter(optionality = Optionality.OPTIONAL) @ParameterLayout(named="Due by")
+ final LocalDate dueBy,
+ @Parameter(optionality = Optionality.OPTIONAL) @ParameterLayout(named="Cost")
+ final BigDecimal cost) {
+ return newToDo(description, category, subcategory, currentUserName(), dueBy, cost);
+}
+private String currentUserName() {
+ return container.getUser().getName(); // <1>
+}
+----
+<1> is the current user.
+
+The fixture for this can use the `SudoService` to run a block of code as a specified user:
+
+[source,java]
+.Fixture Script
+----
+final String description = ...
+final Category category = ...
+final Subcategory subcategory = ...
+final LocalDate dueBy = ...
+final BigDecimal cost = ...
+final Location location = ...
+
+toDoItem = sudoService.sudo(username,
+ new Callable<ToDoItem>() {
+ @Override
+ public ToDoItem call() {
+ final ToDoItem toDoItem = wrap(toDoItems).newToDo(
+ description, category, subcategory, dueBy, cost);
+ wrap(toDoItem).setLocation(location);
+ return toDoItem;
+ }
+ });
+----
+
+Behind the scenes the `SudoService` simply talks to the `DomainObjectContainer` to override the user returned by the `getUser()` API. It is possible to override both users and roles.
http://git-wip-us.apache.org/repos/asf/isis/blob/9c5dafab/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support.adoc
new file mode 100644
index 0000000..f103703
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support.adoc
@@ -0,0 +1,24 @@
+[[_ug_testing_integ-test-support]]
+= Integration Test Support
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+:_basedir: ../
+:_imagesdir: images/
+
+
+As discussed in the introductory overview of this chapter, Apache Isis allows you to integration test your domain objects from within JUnit. There are several parts to this:
+
+* configuring the Isis runtime so it can be bootstrapped (mostly boilerplate)
+* defining a base class to perform said bootstrapping
+* using fixture scripts to set up the app
+* using `WrapperFactory` so that the UI can be simulated.
+
+We'll get to all that shortly, but let's start by taking a look at what a typical integration test looks like.
+
+
+include::_ug_testing_integ-test-support_typical-usage.adoc[leveloffset=+1]
+include::_ug_testing_integ-test-support_bootstrapping.adoc[leveloffset=+1]
+include::_ug_testing_integ-test-support_wrapper-factory.adoc[leveloffset=+1]
+include::_ug_testing_integ-test-support_maven-configuration.adoc[leveloffset=+1]
+
+
+
http://git-wip-us.apache.org/repos/asf/isis/blob/9c5dafab/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_bootstrapping.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_bootstrapping.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_bootstrapping.adoc
new file mode 100644
index 0000000..41957ea
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_bootstrapping.adoc
@@ -0,0 +1,231 @@
+[[_ug_testing_integ-test-support_bootstrapping]]
+= Bootstrapping
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+:_basedir: ../
+:_imagesdir: images/
+
+
+Integration tests instantiate an Isis "runtime" (as a singleton) within a JUnit test. Because (depending on the size of your app) it takes a little time to bootstrap Isis, the framework caches the runtime on a thread-local from one test to the next.
+
+Nevertheless, we do need to bootstrap the runtime for the very first test.
+
+Since the integration tests don't depend on the `webapp` module, it's necessary to repeat all the (relevant) all the configuration in `isis.properties` and related files. That said, in practice the relevant information isn't all that much.
+
+[NOTE]
+====
+We hope to simplify the way this works in future versions of Isis.
+====
+
+The example code in this section is taken from the app generated by the xref:ug.adoc#_ug_getting-started_simpleapp-archetype[SimpleApp archetype].
+
+
+
+
+== Builder
+
+The bootstrapping itself is mostly performed by a subclass of the `IsisSystemForTest.Builder` class:
+
+[source,java]
+----
+private static class SimpleAppSystemBuilder extends IsisSystemForTest.Builder { // <1>
+
+ public SimpleAppSystemBuilder() {
+ withLoggingAt(org.apache.log4j.Level.INFO);
+ with(testConfiguration());
+ with(new DataNucleusPersistenceMechanismInstaller()); // <2>
+
+ withServicesIn( "domainapp" ); // <3>
+ }
+
+ private static IsisConfiguration testConfiguration() {
+ final IsisConfigurationForJdoIntegTests testConfiguration =
+ new IsisConfigurationForJdoIntegTests(); // <4>
+
+ testConfiguration.addRegisterEntitiesPackagePrefix("domainapp.dom.modules"); // <5>
+ return testConfiguration;
+ }
+}
+----
+<1> subclass the framework-provided `IsisSystemForTest.Builder`.
+<2> equivalent to `isis.persistor=datanucleus` in `isis.properties`
+<3> specify the `isis.services` key in `isis.properties` (where "domainapp" is the base package for all classes within the app)
+<4> `IsisConfigurationForJdoIntegTests` has pre-canned configuration for using an in-memory HSQLDB and other standard settings; more on this below.
+<5> equivalent to `isis.persistor.datanucleus.RegisterEntities.packagePrefix` key (typically in `persistor_datanucleus.properties`
+
+
+
+
+=== IsisConfigurationForJdoIntegTests
+
+Integration tests are configured programmatically, with a default set of properties to bootstrap the JDO/DataNucleus objectstore using an HSQLDB in-memory database.
+
+To remove a little bit of boilerplate, the `IsisConfigurationForJdoIntegTests` class (in the `org.apache.isis.objectstore.jdo.datanucleus` package) can be used to bootstrap the application. If necessary, this class can be subclassed to override these defaults.
+
+
+.Default Configuration Properties for Integration Tests
+[cols="2a,1,3a", options="header"]
+|===
+|Property
+|Value
+|Description
+
+|`isis.persistor.datanucleus.impl.` +
+`javax.jdo.option.ConnectionURL`
+|jdbc:hsqldb:mem:test
+|JDBC URL
+
+|`isis.persistor.datanucleus.impl.` +
+`javax.jdo.option.ConnectionDriverName`
+|org.hsqldb.jdbcDriver
+|JDBC Driver
+
+|`isis.persistor.datanucleus.impl.` +
+`javax.jdo.option.ConnectionUserName`
+|sa
+|Username
+
+|`isis.persistor.datanucleus.impl.` +
+`javax.jdo.option.ConnectionPassword`
+|<empty string>
+|Password
+
+|`isis.persistor.datanucleus.impl.` +
+`datanucleus.schema.autoCreateAll`
+|true
+|Recreate DB for each test run (an in-memory database)
+
+|`isis.persistor.datanucleus.impl.` +
+`datanucleus.schema.validateAll`
+|false
+|Disable validations (minimize bootstrap time)
+
+|`isis.persistor.datanucleus.impl.` +
+`datanucleus.persistenceByReachabilityAtCommit`
+|false
+|As per WEB-INF/persistor_datanucleus.properties
+
+|`isis.persistor.datanucleus.impl.` +
+`datanucleus.identifier.case`
+|MixedCase
+|As per WEB-INF/persistor_datanucleus.properties
+
+|`isis.persistor.datanucleus.impl.` +
+`datanucleus.cache.level2.type`
+|none
+|As per WEB-INF/persistor_datanucleus.properties
+
+|`isis.persistor.datanucleus.impl.` +
+`datanucleus.cache.level2.mode`
+|ENABLE_SELECTIVE
+|As per WEB-INF/persistor_datanucleus.properties
+
+|`isis.persistor.datanucleus.` +
+`install-fixtures`
+|true
+|Automatically install any fixtures that might have been registered
+
+|`isis.persistor.` +
+`enforceSafeSemantics`
+|false
+|
+
+|`isis.deploymentType`
+|server_prototype
+|
+|===
+
+
+
+
+
+== System Initializer
+
+The builder is defined and used within a class we call the system initializer that is responsible for instantiating the Isis runtime, and binding it to a thread-local. This is performed within a static `initIsft()` method.
+
+Here's the code:
+
+[source,java]
+----
+public class SimpleAppSystemInitializer {
+ public static void initIsft() {
+ IsisSystemForTest isft = IsisSystemForTest.getElseNull();
+ if(isft == null) {
+ isft = new SimpleAppSystemBuilder() // <1>
+ .build()
+ .setUpSystem();
+ IsisSystemForTest.set(isft); // <2>
+ }
+ }
+ private static class SimpleAppSystemBuilder
+ extends IsisSystemForTest.Builder { ... }
+
+}
+----
+<1> instantiates and initializes the Isis runtime (the `IsisSystemForTest` class)
+<2> binds the runtime to a thread-local.
+
+
+
+
+== Abstract Class
+
+We recommend defining a base class for all your other classes to integration classes to inherit from. The main responsibility of this class is tocall the system initializer, described earlier. We only need the initialization to be performed once, so this call is performed in a `@BeforeClass` hook.
+
+The code below shows the general form:
+
+[source,java]
+----
+public abstract class SimpleAppIntegTest {
+ @BeforeClass
+ public static void initClass() {
+ org.apache.log4j.PropertyConfigurator.configure("logging.properties"); // <1>
+ SimpleAppSystemInitializer.initIsft(); // <2>
+ new ScenarioExecutionForIntegration(); // <3>
+ }
+}
+----
+<1> ensure that logging messages don't get swallowed
+<2> initialize the Isis runtime
+<3> primarily exists to support the writing of xref:ug.adoc#_ug_testing_bdd-spec-support[BDD specifications], but also enables finer-grained management of sessions/transactions (discussed below).
+
+
+
+=== `IntegrationTestAbstract`
+
+In fact, we recommend that your base class inherit from Isis' `IntegrationTestAbstract` class:
+
+[source,java]
+----
+public abstract class SimpleAppIntegTest extends IntegrationTestAbstract {
+ ...
+}
+----
+
+Although not mandatory, this provides a number of helper/convenience methods and JUnit rules:
+
+[source,java]
+----
+ @Rule
+ public IsisTransactionRule isisTransactionRule = // <1>
+ new IsisTransactionRule();
+ @Rule
+ public JUnitRuleMockery2 context = // <2>
+ JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
+ @Rule
+ public ExpectedException expectedExceptions = // <3>
+ ExpectedException.none();
+ @Rule
+ public ExceptionRecognizerTranslate exceptionRecognizerTranslations = // <4>
+ ExceptionRecognizerTranslate.create();
+----
+<1> ensures an Isis session/transaction running for each test
+<2> sets up a JMock context (using Isis' extension to JMock as described in <<JMock Extensions>>
+<3> standard JUnit rule for writing tests that throw exceptions
+<4> to capture messages that require translation, as described in xref:ug.adoc#_ug_more-advanced_i18n[i18 support].
+
+All of these rules could be inlined in your own base class; as we say, they are a convenience.
+
+In addition, `IntegrationTestAbstract` provides a number of helper/convenience methods. Most important amongst these are `nextSession()` and `nextTransaction()` that to allow tests to simulate multiple separate user interactions (each of which would normally occur in a separate transaction).
+
+It also provides `wrap(...)` and `unwrap(...)` which delegate to the `WrapperFactory`. We talk about these methods in the next section
+
http://git-wip-us.apache.org/repos/asf/isis/blob/9c5dafab/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_maven-configuration.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_maven-configuration.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_maven-configuration.adoc
new file mode 100644
index 0000000..e56a865
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_maven-configuration.adoc
@@ -0,0 +1,46 @@
+[[_ug_testing_integ-test-support_maven-configuration]]
+= Maven Configuration
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+:_basedir: ../
+:_imagesdir: images/
+
+
+Apache Isis' integration test support is automatically configured if you use the xref:ug.adoc#_ug_getting-started_simpleapp-archetype[SimpleApp archetype]. To set it up manually, update the `pom.xml` of your domain object model module:
+
+[source,xml]
+----
+<dependency>
+ <groupId>org.apache.isis.core</groupId>
+ <artifactId>isis-core-integtestsupport</artifactId>
+</dependency>
+<dependency>
+ <groupId>org.apache.isis.core</groupId>
+ <artifactId>isis-core-wrapper</artifactId>
+</dependency>
+----
+
+We also recommend that you configure the `maven-surefire-plugin` to pick up the following class patterns:
+
+[source,xml]
+----
+<plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ <include>**/*Test_*.java</include>
+ <include>**/*Spec*.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/Test*.java</exclude>
+ <exclude>**/*ForTesting.java</exclude>
+ <exclude>**/*Abstract*.java</exclude>
+ </excludes>
+ <useFile>true</useFile>
+ <printSummary>true</printSummary>
+ <outputDirectory>${project.build.directory}/surefire-reports</outputDirectory>
+ </configuration>
+</plugin>
+----
http://git-wip-us.apache.org/repos/asf/isis/blob/9c5dafab/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_typical-usage.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_typical-usage.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_typical-usage.adoc
new file mode 100644
index 0000000..66c9936
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_typical-usage.adoc
@@ -0,0 +1,124 @@
+[[_ug_testing_integ-test-support_typical-usage]]
+= Typical Usage
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+:_basedir: ../
+:_imagesdir: images/
+
+
+This example adapted from the link:http://github.com/isisaddons/isis-app-todoapp[Isis addons' todoapp] (non-ASF). The code we want to test (simplified) is:
+
+[source,java]
+----
+public class ToDoItem ... {
+
+ private boolean complete;
+ @Property( editing = Editing.DISABLED )
+ public boolean isComplete() {
+ return complete;
+ }
+ public void setComplete(final boolean complete) {
+ this.complete = complete;
+ }
+
+ @Action()
+ public ToDoItem completed() {
+ setComplete(true);
+ ...
+ return this;
+ }
+ public String disableCompleted() {
+ return isComplete() ? "Already completed" : null;
+ }
+ ...
+}
+----
+
+We typically put the bootstrapping of Isis into a superclass (`AbstractToDoIntegTest` below), then subclass as required.
+
+For this test (of the "completed()" action) we need an instance of a `ToDoItem` that is not yet complete. Here's the setup:
+
+[source,java]
+----
+public class ToDoItemIntegTest extends AbstractToDoIntegTest {
+
+ @Inject
+ FixtureScripts fixtureScripts; // <1>
+ @Inject
+ ToDoItems toDoItems; // <2>
+ ToDoItem toDoItem; // <3>
+
+ @Before
+ public void setUp() throws Exception {
+ RecreateToDoItemsForCurrentUser fixtureScript = // <4>
+ new RecreateToDoItemsForCurrentUser();
+ fixtureScripts.runFixtureScript(fixtureScript, null);
+ final List<ToDoItem> all = toDoItems.notYetComplete(); // <5>
+ toDoItem = wrap(all.get(0)); // <6>
+ }
+ ...
+}
+----
+<1> the xref:rg.adoc#_rg_classes_super_manpage-FixtureScripts[`FixtureScripts`] domain service is injected, providing us with the ability to run fixture scripts
+<2> likewise, an instance of the `ToDoItems` domain service is injected. We'll use this to lookup...
+<3> the object under test, held as a field
+<4> the fixture script for this test; it deletes all existing todo items (for the current user only) and then recreates them
+<5> we lookup one of the just-created todo items...
+<6> and then wrap it so that our interactions with it are as if through the UI
+
+
+
+The following code tests the happy case, that a not-yet-completed `ToDoItem` can be completed by invoking the `completed()` action:
+
+[source,java]
+----
+public class ToDoItemIntegTest ... {
+ ...
+ public static class Completed extends ToDoItemIntegTest { // <1>
+ @Test
+ public void happyCase() throws Exception {
+ // given
+ assertThat(toDoItem.isComplete()).isFalse(); // <2>
+ // when
+ toDoItem.completed();
+ // then
+ assertThat(toDoItem.isComplete()).isTrue();
+ }
+ ...
+ }
+}
+----
+<1> the idiom we follow is to use nested static classes to identify the class responsibility being tested
+<2> the http://github.com/isisaddons/isis-app-todoapp[todoapp] uses link:http://joel-costigliola.github.io/assertj[AssertJ].
+
+What about when a todo item is already completed? The `disableCompleted()` method in the class says that it shouldn't be allowed (the action would be greyed out in the UI with an appropriate tooltip). The following test verifies this:
+
+[source,java]
+----
+ @Test
+ public void cannotCompleteIfAlreadyCompleted() throws Exception {
+ // given
+ unwrap(toDoItem).setComplete(true); // <1>
+ // expect
+ expectedExceptions.expectMessage("Already completed"); // <2>
+ // when
+ toDoItem.completed();
+ }
+----
+<1> we unwrap the domain object in order to set its state directly
+<2> the expectedExceptions link:http://junit.org/apidocs/org/junit/rules/ExpectedException.html[JUnit rule] (defined by a superclass) verifies that the appropiate exception is indeed thrown (in the "when")
+
+
+And what about the fact that the underlying "complete" property is disabled (the `@Disabled` annotation?). If the `ToDoItem` is put into edit mode in the UI, the complete checkbox should remain read-only. Here's a verify similar test that verifies this also:
+
+[source,java]
+----
+ @Test
+ public void cannotSetPropertyDirectly() throws Exception {
+ // expect
+ expectedExceptions.expectMessage("Always disabled"); // <1>
+ // when
+ toDoItem.setComplete(true);
+ }
+----
+<1> again we use the exceptedExceptions rule.
+
http://git-wip-us.apache.org/repos/asf/isis/blob/9c5dafab/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_wrapper-factory.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_wrapper-factory.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_wrapper-factory.adoc
new file mode 100644
index 0000000..c298dc1
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_integ-test-support_wrapper-factory.adoc
@@ -0,0 +1,162 @@
+[[_ug_testing_integ-test-support_wrapper-factory]]
+= Wrapper Factory
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+:_basedir: ../
+:_imagesdir: images/
+
+
+The xref:rg.adoc#_rg_services-api_manpage-WrapperFactory[`WrapperFactory`] service is responsible for wrapping a domain object in a dynamic proxy, of the same type as the object being proxied. And the role of this wrapper is to simulate the UI.
+
+[NOTE]
+====
+`WrapperFactory` uses link:http://www.javassist.org[javassist] to perform its magic; this is the same technology that ORMs such as link:http://hibernate.org/[Hibernate] use to manage lazy loading/dirty tracking (DataNucleus uses a different mechanism).
+====
+
+
+
+It does this by allowing through method invocations that would be allowed if the user were interacting with the domain object through one of the viewers, but throwing an exception if the user attempts to interact with the domain object in a way that would not be possible if using the UI.
+
+The mechanics are as follows:
+
+. the integration test calls the `WrapperFactory` to obtain a wrapper for the domain object under test. This is usually done in the test's `setUp()` method.
+
+. the test calls the methods on the wrapper rather than the domain object itself
+
+. the wrapper performs a reverse lookup from the method invoked (a regular `java.lang.reflect.Method` instance) into the Isis metamodel
+
+. (like a viewer), the wrapper then performs the "see it/use it/do it" checks, checking that the member is visible, that it is enabled and (if there are arguments) that the arguments are valid
+
+. if the business rule checks pass, then the underlying member is invoked. Otherwise an exception is thrown.
+
+The type of exception depends upon what sort of check failed. It's straightforward enough: if the member is invisible then a `HiddenException` is thrown; if it's not usable then you'll get a `DisabledException`, if the args are not valid then catch an `InvalidException`.
+
+image::{_imagesdir}testing/wrapper-factory.png[width="600px"]
+
+Let's look in a bit more detail at what the test can do with the wrapper.
+
+
+
+
+
+== Wrapping and Unwrapping
+
+Wrapping a domain object is very straightforward; simply call `WrapperFactory#wrap(...)`.
+
+For example:
+
+[source,java]
+----
+Customer customer = ...;
+Customer wrappedCustomer = wrapperFactory.wrap(wrappedCustomer);
+----
+
+
+Going the other way -- getting hold of the underlying (wrapped) domain object -- is just as easy; just call `WrapperFactory#unwrap(...)`.
+
+For example:
+
+[source,java]
+----
+Customer wrappedCustomer = ...;
+Customer customer = wrapperFactory.unwrap(wrappedCustomer);
+----
+
+If you prefer, you also can get the underlying object from the wrapper itself, by downcasting to `WrappingObject` and calling `__isis_wrapped()` method:
+
+[source,java]
+----
+Customer wrappedCustomer = ...;
+Customer customer = (Customer)((WrappingObject)wrappedCustomer).__isis_wrapped());
+----
+
+We're not sure that's any easier (in fact we're certain it looks rather obscure). Stick with calling `unwrap(...)`!
+
+
+
+
+== Using the wrapper
+
+As the wrapper is intended to simulate the UI, only those methods that correspond to the "primary" methods of the domain object's members are allowed to be called. That means:
+
+* for *_object properties_* the test can call the getter or setter method
+
+* for *_object collections_* the test can call the getter. +
++
+If there is a supporting `addTo...()` or `removeFrom...()` method, then these can be called. It can also call `add(...)` or `remove(...)` on the collection (returned by the gettter) itself. +
++
+[NOTE]
+====
+In this respect the wrapper is more functional than the xref:ug.adoc#_ug_wicket-viewer[Wicket viewer] (which does not expose the ability to mutate collections directly).
+====
+
+* for *_object actions_* the test can call the action method itself.
+
+As a convenience, we also allow the test to call any `default...()`,`choices...()` or `autoComplete...()` method. These are often useful for obtaining a valid value to use.
+
+What the test can't call is any of the remaining supporting methods, such as `hide...()`, `disable...()` or `validate...()`. That's because their value is implied by the exception being thrown.
+
+The wrapper _does_ also allow the object's `title()` method or its `toString()` , however this is little use for objects whose title is built up using the `@Title` annotation. Instead, we recommend that your test verifies an object's title by calling `DomainObjectContainer#titleOf(...)` method.
+
+
+
+
+
+== Firing Domain Events
+
+As well as enforcing business rules, the wrapper has another important feature, namely that it will cause domain events to be fired.
+
+For example, if we have an action annotated with `@Action(domainEvent=...`):
+
+[source,java]
+----
+public class ToDoItem ... {
+ @Action(
+ domainEvent =CompletedEvent.class
+ )
+ public ToDoItem completed() { ... }
+ ...
+}
+----
+
+then invoking the action through the proxy will cause the event (`CompletedEvent` above) to be fired to any subscribers. A test might therefore look like:
+
+[source,java]
+----
+@Inject
+private EventBusService eventBusService; // <1>
+
+@Test
+public void subscriberReceivesEvents() throws Exception {
+
+ // given
+ final ToDoItem.CompletedEvent[] evHolder = new ToDoItem.CompletedEvent[1]; // <2>
+ eventBusService.register(new Object() {
+ @Subscribe
+ public void on(final ToDoItem.CompletedEvent ev) { // <3>
+ evHolder[0] = ev;
+ }
+ });
+
+ // when
+ toDoItem.completed(); // <4>
+
+ // then
+ then(evHolder[0].getSource()).isEqualTo(unwrap(toDoItem)); // <5>
+ then(evHolder[0].getIdentifier().getMemberName()).isEqualTo("completed");
+}
+----
+<1> inject xref:rg.adoc#_rg_services-api_manpage-EventBusService[`EventBusService`] into this test
+<2> holder for subscriber to capture event to
+<3> subscriber's callback, using the guava subscriber syntax
+<4> invoking the domain object using the wrapper
+<5> assert that the event was populated
+
+
+The wrapper will also fire domain events for properties (if annotated with `@Property(domainEvent=...)`) or collections (if annotated with `@Collection(domainEvent=...)`).
+
+
+[NOTE]
+====
+It isn't possible to use the `WrapperFactory` in a unit test, because there needs to be a running instance of Isis that holds the metamodel.
+====
+
http://git-wip-us.apache.org/repos/asf/isis/blob/9c5dafab/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support.adoc
new file mode 100644
index 0000000..2cb5ff8
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support.adoc
@@ -0,0 +1,13 @@
+[[_ug_testing_unit-test-support]]
+= Unit Test Support
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+:_basedir: ../
+:_imagesdir: images/
+
+Isis Core provides a number of unit test helpers for you to use (if you wish) to unit test your domain objects.
+
+
+include::_ug_testing_unit-test-support_contract-tests.adoc[leveloffset=+1]
+include::_ug_testing_unit-test-support_jmock-extensions.adoc[leveloffset=+1]
+include::_ug_testing_unit-test-support_maven-configuration.adoc[leveloffset=+1]
+
http://git-wip-us.apache.org/repos/asf/isis/blob/9c5dafab/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support_contract-tests.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support_contract-tests.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support_contract-tests.adoc
new file mode 100644
index 0000000..75f9447
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support_contract-tests.adoc
@@ -0,0 +1,171 @@
+[[_ug_testing_unit-test-support_contract-tests]]
+= Contract Tests
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+:_basedir: ../
+:_imagesdir: images/
+
+
+
+
+Contract tests ensure that all instances of a particular idiom/pattern that occur within your codebase are implemented correctly. You could think of them as being a way to enforce a certain type of coding standard. Implementation-wise they use link:https://code.google.com/p/reflections/[Reflections] library to scan for classes.
+
+
+
+== ``SortedSet``s Contract Test
+
+This contract test automatically checks that all fields of type `java.util.Collection` are declared as `java.util.SortedSet`. In other words, it precludes either `java.util.List` or `java.util.Set` from being used as a collection.
+
+For example, the following passes the contract test:
+
+[source,java]
+----
+public class Department {
+ private SortedSet<Employee> employees = new TreeSet<Employee>();
+ ...
+}
+----
+
+whereas this would not:
+
+[source,java]
+----
+public class SomeDomainObject {
+ private List<Employee> employees = new ArrayList<Employee>();
+ ...
+}
+----
+
+If using DataNucleus against an RDBMS (as you probably are) then we strongly recommend that you implement this test, for several reasons:
+
+* first, ``Set``s align more closely to the relational model than do `List`s. A `List` must have an additional index to specify order.
+
+* second, `SortedSet` is preferable to `Set` because then the order is well-defined and predictable (to an end user, to the programmer). +
++
+The <<ObjectContracts>> utility class substantially simplifies the task of implementing `Comparable` in your domain classes.
+
+* third, if the relationship is bidirectional then JDO/Objectstore will automatically maintain the relationship.
+
+To use the contract test, subclass `SortedSetsContractTestAbstract`, specifying the root package to search for domain classes.
+
+For example:
+
+[source,java]
+----
+public class SortedSetsContractTestAll extends SortedSetsContractTestAbstract {
+
+ public SortedSetsContractTestAll() {
+ super("org.estatio.dom");
+ withLoggingTo(System.out);
+ }
+}
+----
+
+
+
+== Bidirectional Contract Test
+
+This contract test automatically checks that bidirectional 1:m or 1:1 associations are being maintained correctly (assuming that they follow the xref:ug.adoc#_ug_how-tos_entity-relationships_managed-1-to-m-bidirectional-relationships[mutual registration pattern]
+
+[TIP]
+====
+(If using the JDO objectstore, then) there is generally no need to programmatically maintain 1:m relationships (indeed it may introduce subtle errors). For more details, see xref:ug.adoc#_ug_how-tos_entity-relationships_managed-1-to-m-bidirectional-relationships[here]. Also check out the xref:dg.adoc[IDE templates] for further guidance.
+====
+
+For example, suppose that `ParentDomainObject` and `ChildDomainObject` have a 1:m relationship (`ParentDomainObject#children` / `ChildDomainObject#parent`), and also `PeerDomainObject` has a 1:1 relationship with itself (`PeerDomainObject#next` / `PeerDomainObject#previous`).
+
+The following will exercise these relationships:
+
+[source,java]
+----
+public class BidirectionalRelationshipContractTestAll
+ extends BidirectionalRelationshipContractTestAbstract {
+
+ public BidirectionalRelationshipContractTestAll() {
+ super("org.apache.isis.core.unittestsupport.bidir",
+ ImmutableMap.<Class<?>,Instantiator>of(
+ ChildDomainObject.class, new InstantiatorForChildDomainObject(),
+ PeerDomainObject.class, new InstantiatorSimple(PeerDomainObjectForTesting.class)
+ ));
+ withLoggingTo(System.out);
+ }
+}
+----
+
+The first argument to the constructor scopes the search for domain objects; usually this would be something like `"com.mycompany.dom"`.
+
+The second argument provides a map of `Instantiator` for certain of the domain object types. This has two main purposes. First, for abstract classes, it nominates an alternative concrete class to be instantiated. Second, for classes (such as `ChildDomainObject`) that are `Comparable` and are held in a `SortedSet`), it provides the ability to ensure that different instances are unique when compared against each other. If no `Instantiator` is provided, then the contract test simply attempts to instantiates the class.
+
+If any of the supporting methods (`addToXxx()`, `removeFromXxx()`, `modifyXxx()` or `clearXxx()`) are missing, the relationship is skipped.
+
+To see what's going on (and to identify any skipped relationships), use the `withLoggingTo()` method call. If any assertion fails then the error should be descriptive enough to figure out the problem (without enabling logging).
+
+The example tests can be found https://github.com/apache/isis/tree/master/core/unittestsupport/src/test/java/org/apache/isis/core/unittestsupport/bidir[here].
+
+
+
+== Injected Services Method Contract Test
+
+It is quite common for some basic services to be injected in a project-specific domain object superclass; for example a `ClockService` might generally be injected everywhere:
+
+[source,java]
+----
+public abstract class EstatioDomainObject {
+ @javax.inject.Inject
+ protected ClockService clockService;
+}
+----
+
+If a subclass inadvertantly overrides this method and provides its own `ClockService` field, then the field in the superclass will never initialized. As you might imagine, ``NullPointerException``s could then arise.
+
+This contract test automatically checks that the `injectXxx(...)` method, to allow for injected services, is not overridable, ie `final`.
+
+[NOTE]
+====
+This contract test is semi-obsolete; most of the time you will want to use `@javax.inject.Inject` on fields rather than the `injectXxx()` method. The feature dates from a time before Isis supported the `@Inject` annotation.
+====
+
+
+To use the contract test, , subclass `SortedSetsContractTestAbstract`, specifying the root package to search for domain classes.
+
+For example:
+
+[source,java]
+----
+public class InjectServiceMethodMustBeFinalContractTestAll extends InjectServiceMethodMustBeFinalContractTestAbstract {
+
+ public InjectServiceMethodMustBeFinalContractTestAll() {
+ super("org.estatio.dom");
+ withLoggingTo(System.out);
+ }
+}
+----
+
+
+
+
+== Value Objects Contract Test
+
+The `ValueTypeContractTestAbstract` automatically tests that a custom value type implements `equals()` and `hashCode()` correctly.
+
+For example, testing JDK's own `java.math.BigInteger` can be done as follows:
+
+[source,java]
+----
+public class ValueTypeContractTestAbstract_BigIntegerTest extends ValueTypeContractTestAbstract<BigInteger> {
+
+ @Override
+ protected List<BigInteger> getObjectsWithSameValue() {
+ return Arrays.asList(new BigInteger("1"), new BigInteger("1"));
+ }
+
+ @Override
+ protected List<BigInteger> getObjectsWithDifferentValue() {
+ return Arrays.asList(new BigInteger("2"));
+ }
+}
+----
+
+The example unit tests can be found https://github.com/apache/isis/tree/master/core/unittestsupport/src/test/java/org/apache/isis/core/unittestsupport/value[here].
+
+
+
http://git-wip-us.apache.org/repos/asf/isis/blob/9c5dafab/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support_jmock-extensions.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support_jmock-extensions.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support_jmock-extensions.adoc
new file mode 100644
index 0000000..4bf309f
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support_jmock-extensions.adoc
@@ -0,0 +1,59 @@
+[[_ug_testing_unit-test-support_jmock-extensions]]
+= JMock Extensions
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+:_basedir: ../
+:_imagesdir: images/
+
+
+As noted earlier, for unit tests we tend to use link:http://www.jmock.org[JMock] as our mocking library. The usual given/when/then format gets an extra step:
+
+* *given* the system is in this state
+* *expecting* these interactions (set up the mock expectations here)
+* *when* I poke it with a stick
+* *then* these state changes and interactions with Mocks should have occurred.
+
+If using JMock then the interactions (in the "then") are checked automatically by a JUnit rule. However, you probably will still have some state changes to assert upon.
+
+[TIP]
+.Distinguish between queries vs mutators
+====
+For mock interactions that simply retrieve some data, your test should not need to verify that it occurred. If the system were to be refactored and starts caching some data, you don't really want your tests to start breaking because they are no longer performing a query that once they did. If using JMock API this means using the `allowing(..)` method to set up the expectation.
+
+On the other hand mocks that mutate the state of the system you probably should assert have occurred. If using JMock this typically means using the `oneOf(...)` method.
+
+For more tips on using JMock and mocking in general, check out the link:http://www.growing-object-oriented-software.com/[GOOS] book, written by JMock's authors, Steve Freeman and Nat Pryce and also link:http://natpryce.com/articles.html[Nat's blog].
+====
+
+Apache Isis' unit test support provides `JUnitRuleMockery2` which is an extension to the link:http://www.jmock.org/[JMock]'s `JunitRuleMockery`. It provides a simpler API and also providing support for autowiring.
+
+
+For example, here we see that the class under test, an instance of `CollaboratingUsingSetterInjection`, is automatically wired up with its `Collaborator`:
+
+[source,java]
+----
+public class JUnitRuleMockery2Test_autoWiring_setterInjection_happyCase {
+
+ @Rule
+ public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
+
+ @Mock
+ private Collaborator collaborator;
+
+ @ClassUnderTest
+ private CollaboratingUsingSetterInjection collaborating;
+
+ @Test
+ public void wiring() {
+ assertThat(collaborating.collaborator, is(not(nullValue())));
+ }
+}
+----
+
+[NOTE]
+====
+Isis also includes (and automatically uses) a link:http://www.javassist.org[Javassist]-based implementation of JMock's link:http://www.jmock.org/mocking-classes.html[`ClassImposteriser`] interface, so that you can mock out concrete classes as well as interfaces. We've provided this rather than JMock's own cglib-based implementation (which is problematic for us given its own dependencies on link:http://asm.ow2.org/[asm]).
+====
+
+
+The example tests can be found https://github.com/apache/isis/tree/master/core/unittestsupport/src/test/java/org/apache/isis/core/unittestsupport/jmocking[here]
+
http://git-wip-us.apache.org/repos/asf/isis/blob/9c5dafab/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support_maven-configuration.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support_maven-configuration.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support_maven-configuration.adoc
new file mode 100644
index 0000000..0205920
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_unit-test-support_maven-configuration.adoc
@@ -0,0 +1,46 @@
+[[_ug_testing_unit-test-support_maven-configuration]]
+= Maven Configuration
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+:_basedir: ../
+:_imagesdir: images/
+
+
+Apache Isis' unit test support is automatically configured if you use the xref:ug.adoc#_ug_getting-started_simpleapp-archetype[SimpleApp archetype]. To set it up manually, update the `pom.xml` of your domain object model module:
+
+[source,xml]
+----
+<dependency>
+ <groupId>org.apache.isis.core</groupId>
+ <artifactId>isis-core-unittestsupport</artifactId>
+ <scope>test</scope> // <1>
+</dependency>
+----
+<1> Normally `test`; usual Maven scoping rules apply.
+
+
+
+We also recommend that you configure the `maven-surefire-plugin` to pick up the following class patterns:
+
+[source,xml]
+----
+<plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ <include>**/*Test_*.java</include>
+ <include>**/*Spec*.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/Test*.java</exclude>
+ <exclude>**/*ForTesting.java</exclude>
+ <exclude>**/*Abstract*.java</exclude>
+ </excludes>
+ <useFile>true</useFile>
+ <printSummary>true</printSummary>
+ <outputDirectory>${project.build.directory}/surefire-reports</outputDirectory>
+ </configuration>
+</plugin>
+----
http://git-wip-us.apache.org/repos/asf/isis/blob/9c5dafab/adocs/documentation/src/main/asciidoc/guides/_ug_troubleshooting.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_troubleshooting.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_troubleshooting.adoc
new file mode 100644
index 0000000..39384d2
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_troubleshooting.adoc
@@ -0,0 +1,14 @@
+[[_ug_troubleshooting]]
+= Troubleshooting
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+:_basedir: ../
+:_imagesdir: images/
+
+IMPORTANT: TODO
+
+## Logging
+
+include::_ug_troubleshooting_enabling-logging.adoc[leveloffset=+1]
+
+
+
http://git-wip-us.apache.org/repos/asf/isis/blob/9c5dafab/adocs/documentation/src/main/asciidoc/guides/_ug_troubleshooting_enabling-logging.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_troubleshooting_enabling-logging.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_troubleshooting_enabling-logging.adoc
new file mode 100644
index 0000000..712ea17
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_troubleshooting_enabling-logging.adoc
@@ -0,0 +1,39 @@
+[[_ug_troubleshooting_enabling-logging]]
+= Enabling Logging
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+:_basedir: ../
+:_imagesdir: images/
+
+Sometimes you just need to see what is going on. There are various ways in which logging can be enabled, here are the ones we tend to use.
+
+== In Apache Isis
+
+Modify `WEB-INF/logging.properties` (a log4j config file)
+
+== In DataNucleus
+
+As per the http://www.datanucleus.org/products/accessplatform/logging.html[DN logging page]
+
+== In the JDBC Driver
+
+Configure log4jdbc JDBC rather than the vanilla driver (see `WEB-INF/persistor_datanucleus.properties`) and configure log4j logging (see `WEB-INF/logging.properties`).
+
+There are examples of both in the xref:ug.adoc#_ug_getting-started_simpleapp-archetype[SimpleApp archetype].
+
+== In the Database
+
+=== HSQLDB Logging
+
+Add `;sqllog=3` to the end of the JDBC URL.
+
+=== PostgreSQL Logging
+
+In `postgresql\9.2\data\postgresql.conf`:
+
+Will then log to `postgresql\9.2\data\pg_log` directory.
+
+Note that you must restart the service for this to be picked up.
+
+=== MS SQL Server Logging
+
+Use the excellent SQL Profiler tool.
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/isis/blob/9c5dafab/adocs/documentation/src/main/asciidoc/guides/_ug_tutorials.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_tutorials.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_tutorials.adoc
new file mode 100644
index 0000000..a4045ce
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_tutorials.adoc
@@ -0,0 +1,18 @@
+[[_ug_tutorials]]
+= Tutorials
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+:_basedir: ../
+:_imagesdir: images/
+
+
+
+This chapter contains a couple of tutorials for you to follow.
+
+* the "petclinic" tutorial takes you step-by-step through building a simple application of just three classes. There are example solutions in the github repo in case you get lost.
+
+* the "stop scaffolding, start coding" tutorial is taken from a conference workshop. It has less hand-holding, but lists out the steps for you to follow. It's a good cookbook to follow when you're readng to take things further.
+
+Have fun!
+
+include::_ug_tutorials_pet-clinic.adoc[leveloffset=+1]
+include::_ug_tutorials_stop-scaffolding-start-coding.adoc[leveloffset=+1]
http://git-wip-us.apache.org/repos/asf/isis/blob/9c5dafab/adocs/documentation/src/main/asciidoc/guides/_ug_tutorials_pet-clinic.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_tutorials_pet-clinic.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_tutorials_pet-clinic.adoc
new file mode 100644
index 0000000..dccc025
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_tutorials_pet-clinic.adoc
@@ -0,0 +1,557 @@
+[[_ug_tutorials_pet-clinic]]
+= Pet Clinic
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+:_basedir: ../
+:_imagesdir: images/
+
+
+This is a step-by-step tutorial to build up a simple "petclinic" application, starting from the xref:ug.adoc#_ug_getting-started_simpleapp-archetype[SimpleApp archetype].
+
+It consists of just three domain classes (http://yuml.me/edit/3db2078c[http://yuml.me/3db2078c]):
+
+image::{_imagesdir}tutorials/pet-clinic/domain-model.png[link="{_imagesdir}tutorials/pet-clinic/domain-model.png"]
+
+
+This supports the following use cases:
+
+* register a Pet
+* register an Owner
+* maintain a Pet's details
+* check in a Pet to visit the clinic
+* enter a diagnosis
+
+check out a Pet to visit the clinic
+
+Either follow along or check out the tags from the corresponding https://github.com/danhaywood/isis-app-petclinic[github repo].
+
+== Prerequisites
+
+You'll need:
+
+* Java 7 JDK
+* http://maven.apache.org/[Maven] 3.2.x
+* an IDE, such as http://www.eclipse.org/[Eclipse] or https://www.jetbrains.com/idea/[IntelliJ IDEA].
+
+
+
+
+== Run the archetype
+
+Throughout this tutorial you can, if you wish, just checkout from the github repo wherever you see a "git checkout" note:
+
+[TIP]
+====
+[source,bash]
+----
+git checkout https://github.com/danhaywood/isis-app-petclinic/commit/249abe476797438d83faa12ff88365da2c362451
+----
+
+====
+
+[NOTE]
+====
+This tutorial was developed against Apache Isis 1.8.0-SNAPSHOT. Since then 1.8.0 has been released, so simply replace "1.8.0-SNAPSHOT" for "1.8.0" wherever it appears in the `pom.xml` files.
+====
+
+
+As per the http://isis.apache.org/intro/getting-started/simpleapp-archetype.html[Isis website], run the simpleapp archetype to build an empty Isis application:
+
+
+[source,bash]
+----
+mvn archetype:generate \
+ -D archetypeGroupId=org.apache.isis.archetype \
+ -D archetypeArtifactId=simpleapp-archetype \
+ -D archetypeVersion=1.8.0 \
+ -D groupId=com.mycompany \
+ -D artifactId=petclinic \
+ -D version=1.0-SNAPSHOT \
+ -D archetypeRepository=http://repository-estatio.forge.cloudbees.com/snapshot/ \
+ -B
+----
+
+This will generate the app in a `petclinic` directory. Move the contents back:
+
+[source,bash]
+----
+mv petclinic/* .
+rmdir petclinic
+----
+
+
+
+
+== Build and run
+
+Start off by building the app from the command line:
+
+[source,bash]
+----
+mvn clean install
+----
+
+Once that's built then run using:
+
+[source,bash]
+----
+mvn antrun:run -P self-host
+----
+
+A splash screen should appear offering to start up the app. Go ahead and start; the web browser should be opened at http://localhost:8080[http://localhost:8080]
+
+Alternatively, you can run using the mvn-jetty-plugin:
+
+[source,bash]
+----
+mvn jetty:run
+----
+
+This will accomplish the same thing, though the webapp is mounted at a slightly different URL
+
+
+
+
+== Using the app
+
+Navigate to the Wicket UI (eg http://localhost:8080/wicket[http://localhost:8080/wicket]), and login (sven/pass).
+
+image::{_imagesdir}tutorials/pet-clinic/010-01-login-page.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/010-01-login-page.png"]
+
+
+
+The home page should be shown:
+
+image::{_imagesdir}tutorials/pet-clinic/010-02-home-page.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/010-02-home-page.png"]
+
+
+
+Install the fixtures (example test data) using the `Prototyping` menu:
+
+image::{_imagesdir}tutorials/pet-clinic/010-03-prototyping-menu.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/010-03-prototyping-menu.png"]
+
+
+
+List all objects using the `Simple Objects` menu:
+
+image::{_imagesdir}tutorials/pet-clinic/010-04-simpleobjects.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/010-04-simpleobjects.png"]
+
+
+To return the objects created:
+
+image::{_imagesdir}tutorials/pet-clinic/010-05-simpleobject-list.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/010-05-simpleobject-list.png"]
+
+
+
+Experiment some more, to:
+
+* create a new object
+* list all objects
+
+Go back to the splash screen, and quit the app. Note that the database runs in-memory (using HSQLDB) so any data created will be lost between runs.
+
+
+
+
+== Dev environment
+
+Set up xref:dg.adoc[an IDE] and import the project to be able to run and debug the app.
+
+Then set up a launch configuration so that you can run the app from within the IDE. To save having to run the fixtures
+every time, specify the following system properties:
+
+[source,bash]
+----
+-Disis.persistor.datanucleus.install-fixtures=true -Disis.fixtures=fixture.simple.scenario.SimpleObjectsFixture
+----
+
+For example, here's what a launch configuration in IntelliJ idea looks like:
+
+image::{_imagesdir}tutorials/pet-clinic/020-01-idea-configuration.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/020-01-idea-configuration.png"]
+
+
+
+where the "before launch" maven goal (to run the DataNucleus enhancer) is defined as:
+
+
+image::{_imagesdir}tutorials/pet-clinic/020-02-idea-configuration.png[width="400px",link="{_imagesdir}tutorials/pet-clinic/020-02-idea-configuration.png"]
+
+
+
+
+== Explore codebase
+
+Apache Isis applications are organized into several Maven modules. Within your IDE navigate to the various classes and correlate back to the generated UI:
+
+* `petclinic` : parent module
+* `petclinic-dom`: domain objects module
+** entity: `dom.simple.SimpleObject`
+** repository: `dom.simple.SimpleObjects`
+* `petclinic-fixture`: fixtures module
+** fixture script:`fixture.simple.SimpleObjectsFixture`
+* `petclinic-integtests`: integration tests module
+* `petclinic-webapp`: webapp module
+** (builds the WAR file)
+
+
+
+
+== Testing
+
+Testing is of course massively important, and Isis makes both unit testing and (end-to-end) integration testing easy. Building the app from the Maven command line ("mvn clean install") will run all tests, but you should also run the tests from within the IDE.
+
+* `myapp-dom` unit tests
+* run
+* inspect, eg
+ - `SimpleObjectTest`
+* `myapp-integtests` integration tests
+* run
+* inspect, eg:
+** `integration.tests.smoke.SimpleObjectsTest`
+** `integration.specs.simple.SimpleObjectSpec_listAllAndCreate.feature`
+* generated report, eg
+ - `myapp/integtests/target/cucumber-html-report/index.html`
+** change test in IDE, re-run (in Maven)
+
+If you have issues with the integration tests, make sure that the domain classes have been enhanced by the DataNucleus enhancer. (The exact mechanics depends on the IDE being used).
+
+
+
+
+== Update POM files
+
+[TIP]
+====
+[source,bash]
+----
+git checkout https://github.com/danhaywood/isis-app-petclinic/commit/68904752bc2de9ebb3c853b79236df2b3ad2c944
+----
+
+====
+
+The POM files generated by the simpleapp archetype describe the app as "SimpleApp". Update them to say "PetClinic" instead.
+
+
+
+
+== Delete the BDD specs
+
+[TIP]
+====
+[source,bash]
+----
+git checkout https://github.com/danhaywood/isis-app-petclinic/commit/9046226249429b269325dfa2baccf03635841c20
+----
+
+====
+
+
+During this tutorial we're going to keep the integration tests in-sync with the code, but we're going to stop short of writing BDD/Cucumber specs.
+
+Therefore delete the BDD feature spec and glue in the `integtest` module:
+
+* `integration/specs/*`
+* `integration/glue/*`
+
+
+
+
+== Rename artifacts
+
+[TIP]
+====
+[source,bash]
+----
+git checkout https://github.com/danhaywood/isis-app-petclinic/commit/bee3629c0b64058f939b6dd20f226be31810fc66
+----
+
+====
+
+
+Time to start refactoring the app. The heart of the PetClinic app is the `Pet` concept, so go through the code and refactor. While we're at it, refactor the app itself from "SimpleApp" to "PetClinicApp".
+
+See the git commit for more detail, but in outline, the renames required are:
+
+* in the `dom` module's production code
+** `SimpleObject` -> `Pet` (entity)
+** `SimpleObjects` -> `Pets` (repository domain service)
+** `SimpleObject.layout.json` -> `Pet.layout.json` (layout hints for the `Pet` entity)
+** delete the `SimpleObject.png`, and add a new `Pet.png` (icon shown against all `Pet` instances).
+* in the `dom` module's unit test code
+** `SimpleObjectTest` -> `PetTest` (unit tests for `Pet` entity)
+** `SimpleObjectsTest` -> `PetsTest` (unit tests for `Pets` domain service)
+* in the `fixture` module:
+** `SimpleObjectsFixturesService` -> `PetClinicAppFixturesService` (rendered as the prototyping menu in the UI)
+** `SimpleObjectsTearDownService` -> `PetClinicAppTearDownService` (tear down all objects between integration tests)
+** `SimpleObjectAbstract` -> `PetAbstract` (abstract class for setting up a single pet object
+*** and corresponding subclasses to set up sample data (eg `PetForFido`)
+** `SimpleObjectsFixture` -> `PetsFixture` (tear downs system and then sets up all pets)
+* in the `integtest` module:
+** `SimpleAppSystemInitializer` -> `PetClinicAppSystemInitializer` (bootstraps integration tests with domain service/repositories)
+** `SimpleAppIntegTest` -> `PetClinicAppIntegTest` (base class for integration tests)
+** `SimpleObjectTest` -> `PetTest` (integration test for `Pet` entity)
+** `SimpleObjectsTest` -> `PetsTest` (integration test for `Pets` domain service)
+* in the `webapp` module:
+** `SimpleApplication` -> `PetClinicApplication`
+** update `isis.properties`
+** update `web.xml`
+
+
+Note that `Pet` has both both Isis and JDO annotations:
+
+[source,java]
+----
+@javax.jdo.annotations.PersistenceCapable(identityType=IdentityType.DATASTORE) // <1>
+@javax.jdo.annotations.DatastoreIdentity( // <2>
+ strategy=javax.jdo.annotations.IdGeneratorStrategy.IDENTITY,
+ column="id")
+@javax.jdo.annotations.Version( // <3>
+ strategy=VersionStrategy.VERSION_NUMBER,
+ column="version")
+@javax.jdo.annotations.Unique(name="Pet_name_UNQ", members = {"name"}) // <4>
+@ObjectType("PET") // <5>
+@Bookmarkable // <6>
+public class Pet implements Comparable<Pet> {
+ ...
+}
+----
+
+where:
+
+<1> `@PersistenceCapable` and
+<2> `@DatastoreIdentity` specify a surrogate `Id` column to be used as the primary key
+<3> `@Version` provides support for optimistic locking
+<4> `@Unique` enforces a uniqueness constraint so that no two `Pet`s can have the same name (unrealistic, but can refactor later)
+<5> `@ObjectType` is used by Isis for its own internal "OID" identifier; this also appears in the URL in Isis' Wicket viewer and REST API
+<6> `@Bookmarkable` indicates that the object can be automatically bookmarked in Isis' Wicket viewer
+
+[NOTE]
+====
+The `@ObjectType` and `@Bookmarkable` annotations have since been deprecated, replaced with `@DomainObject(objectType=...)` and `@DomainObjectLayout(bookmarking=...)`
+====
+
+
+The `Pets` domain service also has Isis annotations:
+
+[source,java]
+----
+@DomainService(repositoryFor = Pet.class)
+@DomainServiceLayout(menuOrder = "10")
+public class Pets {
+ ...
+}
+----
+
+where:
+
+* `DomainService` indicates that the service should be instantiated automatically (as a singleton)
+* `DomainServiceLayout` provides UI hints, in this case the positioning of the menu for the actions provided by the service
+
+To run the application will require an update to the IDE configuration, for the changed name of the fixture class:
+
+
+image::{_imagesdir}tutorials/pet-clinic/030-01-idea-configuration-updated.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/030-01-idea-configuration-updated.png"]
+
+
+Running the app should now show `Pet`s:
+
+image::{_imagesdir}tutorials/pet-clinic/030-02-updated-app.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/030-02-updated-app.png"]
+
+
+
+
+
+== Update package names
+
+[TIP]
+====
+[source,bash]
+----
+git checkout https://github.com/danhaywood/isis-app-petclinic/commit/55ec36e520191f5fc8fe7f5b89956814eaf13317
+----
+
+====
+
+
+
+The classes created by the simpleapp archetype are by default in the `simple` package. Move these classes to `pets` package instead. Also adjust package names where they appear as strings:
+
+* in `PetClinicAppFixturesService`, change the package name from "fixture.simple" to "fixture.pets".
+* in `PetClinicAppSystemInitializer`, change the package name "dom.simple" to "dom.pets", and similarly "fixture.simple" to "fixture.pets"
+* in `WEB-INF/isis.properties`, similarly change the package name "dom.simple" to "dom.pets", and similarly "fixture.simple" to "fixture.pets"
+
+To run the application will require a further update to the IDE configuration, for the changed package of the fixture class:
+
+
+image::{_imagesdir}tutorials/pet-clinic/040-01-idea-configuration-updated.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/040-01-idea-configuration-updated.png"]
+
+
+
+== Add `PetSpecies` enum
+
+[TIP]
+====
+[source,bash]
+----
+git checkout https://github.com/danhaywood/isis-app-petclinic/commit/55c9cd28ff960220719b3dc7cb8abadace8d0829
+----
+
+====
+
+
+Each `Pet` is of a particular species. Model these as an enum called `PetSpecies`:
+
+[source,java]
+----
+public enum PetSpecies {
+ Cat,
+ Dog,
+ Budgie,
+ Hamster,
+ Tortoise
+}
+----
+
+Introduce a new property on `Pet` of this type:
+
+[source,java]
+----
+public class Pet {
+ ...
+ private PetSpecies species;
+ @javax.jdo.annotations.Column(allowsNull = "false")
+ public PetSpecies getSpecies() { return species; }
+ public void setSpecies(final PetSpecies species) { this.species = species; }
+ ...
+}
+----
+
+Update fixtures, unit tests and integration tests.
+
+
+
+
+== Icon to reflect pet species
+
+[TIP]
+====
+[source,bash]
+----
+git checkout https://github.com/danhaywood/isis-app-petclinic/commit/2212765694693eb463f8fa88bab1bad154add0cb
+----
+
+====
+
+
+Rather than using a single icon for a domain class, instead a different icon can be supplied for each instance. We can therefore have different icon files for each pet, reflecting that pet's species.
+
+[source,java]
+----
+public class Pet {
+ ...
+ public String iconName() {
+ return getSpecies().name();
+ }
+ ...
+}
+----
+
+Download corresponding icon files (`Dog.png`, `Cat.png` etc)
+
+Running the app shows the `Pet` and its associated icon:
+
+image::{_imagesdir}tutorials/pet-clinic/050-01-list-all.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/050-01-list-all.png"]
+
+
+
+with the corresponding view of the `Pet`:
+
+image::{_imagesdir}tutorials/pet-clinic/050-02-view-pet.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/050-02-view-pet.png"]
+
+
+== Add pet's `Owner`
+
+[TIP]
+====
+[source,bash]
+----
+git checkout https://github.com/danhaywood/isis-app-petclinic/commit/6f92a8ee8e76696d005da2a8b7a746444d017546
+----
+
+====
+
+
+Add the `Owner` entity and corresponding `Owners` domain service (repository). Add a query to find `Order`s by name:
+
+[source,java]
+----
+...
+@javax.jdo.annotations.Queries( {
+ @javax.jdo.annotations.Query(
+ name = "findByName", language = "JDOQL",
+ value = "SELECT "
+ + "FROM dom.owners.Owner "
+ + "WHERE name.matches(:name)")
+})
+public class Owner ... {
+ ...
+}
+----
+
+and `findByName(...)` in `Owners`:
+
+[source,java]
+----
+public class Owners {
+ ...
+ public List<Owner> findByName(
+ @ParameterLayout(named = "Name")
+ final String name) {
+ final String nameArg = String.format(".*%s.*", name);
+ final List<Owner> owners = container.allMatches(
+ new QueryDefault<>(
+ Owner.class,
+ "findByName",
+ "name", nameArg));
+ return owners;
+ }
+ ...
+}
+----
+
+Add an `owner` property to `Pet`, with supporting `autoCompleteXxx()` method (so that available owners are shown in a drop-down list box):
+
+[source,java]
+----
+public class Pet ... {
+ ...
+ private Owner owner;
+ @javax.jdo.annotations.Column(allowsNull = "false")
+ public Owner getOwner() { return owner; }
+ public void setOwner(final Owner owner) { this.owner = owner; }
+ public Collection<Owner> autoCompleteOwner(final @MinLength(1) String name) {
+ return owners.findByName(name);
+ }
+ ...
+}
+----
+
+Also updated fixture data to set up a number of `Owner`s, and associate each `Pet` with an `Owner`. Also add unit tests and integration tests for `Owner`/`Owners` and updated for `Pet`/`Pets`.
+
+When running the app, notice the new `Owners` menu:
+
+image::{_imagesdir}tutorials/pet-clinic/060-01-owners-menu.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/060-01-owners-menu.png"]
+
+which when invoked returns all `Owner` objects:
+
+image::{_imagesdir}tutorials/pet-clinic/060-02-owners-list.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/060-02-owners-list.png"]
+
+
+Each `Pet` also indicates its corresponding `Owner`:
+
+image::{_imagesdir}tutorials/pet-clinic/060-03-pets-list.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/060-03-pets-list.png"]
+
+
+And, on editing a `Pet`, a new `Owner` can be specified using the autoComplete:
+
+image::{_imagesdir}tutorials/pet-clinic/060-04-pet-owner-autoComplete.png[width="600px",link="{_imagesdir}tutorials/pet-clinic/060-04-pet-owner-autoComplete.png"]
+