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/26 12:17:33 UTC

[6/8] isis git commit: ISIS-1164: pretty printing support for RO viewer if the ContentNegotiationServiceViaXRoDomainType is in use, and in prototype mode.

ISIS-1164: pretty printing support for RO viewer if the ContentNegotiationServiceViaXRoDomainType is in use, and in prototype mode.

Can override using a configuration property (one way or the other).

Minor tidy-up of other docs on config properties.


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/c1fe0feb
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/c1fe0feb
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/c1fe0feb

Branch: refs/heads/master
Commit: c1fe0feb264178f60086dbd4d270db3bbc0730be
Parents: f3839ec
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Fri Jun 26 11:50:38 2015 +0200
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Fri Jun 26 11:50:38 2015 +0200

----------------------------------------------------------------------
 ...s-spi_manpage-ContentNegotiationService.adoc |  16 ++
 ...g_deployment_externalized-configuration.adoc | 236 ++++++++++++++++++-
 .../asciidoc/guides/_ug_deployment_gae.adoc     |  10 +-
 .../guides/_ug_deployment_jvm-flags.adoc        |  45 +++-
 .../guides/_ug_runtime_configuration-files.adoc |   6 +-
 .../guides/_ug_runtime_configuring-core.adoc    |  19 +-
 .../conneg/IsisPrettyPrintingProcessor.java     |  68 ++++++
 .../service/conneg/PrettyPrinting.java          |  31 +++
 .../DomainObjectResourceServerside.java         |  12 +-
 .../DomainServiceResourceServerside.java        |   6 +
 10 files changed, 439 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/c1fe0feb/adocs/documentation/src/main/asciidoc/guides/_rg_services-spi_manpage-ContentNegotiationService.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_rg_services-spi_manpage-ContentNegotiationService.adoc b/adocs/documentation/src/main/asciidoc/guides/_rg_services-spi_manpage-ContentNegotiationService.adoc
index eac2dc7..4320fbc 100644
--- a/adocs/documentation/src/main/asciidoc/guides/_rg_services-spi_manpage-ContentNegotiationService.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/_rg_services-spi_manpage-ContentNegotiationService.adoc
@@ -168,6 +168,22 @@ image::{_imagesdir}reference-services-spi/ContentNegotiationService/accept-json.
 
 
 
+[_rg_services-spi_manpage-ContentNegotiationService_Configuration]]
+== Configuration
+
+The default `ContentNegotiationServiceXRoDomainType` implementation provides a xref:ug.adoc#_ug_runtime_configuring-core[configuration property] which controls whether a mapped domain object is pretty-printed (formatted, indented) or not:
+
+[source,ini]
+----
+isis.services.ContentNegotiationServiceXRoDomainType.prettyPrint=true
+----
+
+If the property is not set, then the default depends on the xref:_ug_runtime_deployment-types[deployment type]; production mode will disable pretty printing, while prototyping mode will enable it.
+
+
+
+
+
 == Registering the Services
 
 Assuming that the `configuration-and-annotation` services installer is configured:

http://git-wip-us.apache.org/repos/asf/isis/blob/c1fe0feb/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_externalized-configuration.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_externalized-configuration.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_externalized-configuration.adoc
index f710b30..75e87a3 100644
--- a/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_externalized-configuration.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_externalized-configuration.adoc
@@ -4,6 +4,240 @@
 :_basedir: ../
 :_imagesdir: images/
 
-IMPORTANT: TODO
 
 
+As described xref:_ug_runtime_configuration-files[here], by default Apache Isis itself bootstraps from the `isis.properties` configuration file.  It will also read configuration from the (optional) component/implementation-specific configuration files (such as
+`persistor_datanucleus.properties` or `viewer_wicket.properties`), and also (optional) component-specific configuration
+files (such as `persistor.properties` or `viewer.properties`).
+
+
+By default these are read from the `WEB-INF` directory. Having this configuration "baked into" the application is
+okay in a development environment, but when the app needs to be deployed to a test or production environment, this
+configuration should be read from an external location.
+
+There are in fact three frameworks involved here, all of which need to be pointed to this external location:
+
+* Apache Isis itself
+
+which as already discussed reads `isis.properties` and optional component-specific config files.
+
+* http://shiro.apache.org[Apache Shiro] (if using the Isis' link:../components/security/shiro/about.html[Shiro integration] for authentication and/or authorization
+
+which reads the `shiro.ini` file (and may read other files referenced from that file)
+
+* http://logging.apache.org/log4j/1.2[Apache log4j 1.2], for logging
+
+which reads `logging.properties` file
+
+Each of these frameworks has its own way of externalizing its configuration.
+
+
+
+
+
+
+[[_ug_deployment_externalized-configuration_Isis]]
+== Apache Isis' Config
+
+To tell Apache Isis to load configuration from an external directory, specify the `isis.config.dir` context parameter.
+
+
+If the external configuration directory is fixed for all environments (systest, UAT, prod etc), then you can specify within the `web.xml` itself:
+
+[source,xml]
+----
+<context-param>
+    <param-name>isis.config.dir</param-name>
+    <param-value>location of external config directory</param-value>
+</context-param>
+----
+
+If however the configuration directory varies by environment, then the context parameter will be specified to each installation of your servlet container. Most (if not all) servlet containers will provide a means to define context parameters through proprietary config files.
+
+For example, if using Tomcat 7.0, you would typically copy the empty `$TOMCAT_HOME/webapps/conf/context.xml` to a file specific to the webapp, for example `$TOMCAT_HOME/webapps/conf/todo.xml`. The context parameter would then be specified by adding the following:
+
+[source,xml]
+----
+<Parameter name="isis.config.dir"
+           value="/usr/local/tomcat/myapp/conf/"
+           override="true"/>
+----
+
+For more detail, see the Tomcat documentation on http://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Defining_a_context[defining a context] and on http://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Context_Parameters[context parameters].
+
+[NOTE]
+====
+Note that running the app using Isis' `org.apache.isis.WebServer` bootstrapper currently does not externalized Isis configuration.
+====
+
+
+
+
+
+
+[[_ug_deployment_externalized-configuration_Shiro]]
+== Externalizing Shiro's Config
+
+If using Isis' xref:_ug_security_configuring-isis-to-use-shiro[Shiro integration] for authentication and/or authorization, note that it reads from the `shiro.ini` configuration file. By default this also resides in `WEB-INF`.
+
+Similar to Isis, Shiro lets this configuration directory be altered, by specifying the `shiroConfigLocations` context parameter.
+
+You can therefore override the default location using the same technique as described above for Isis' `isis.config.dir` context parameter. For example:
+
+[source,xml]
+----
+<Parameter name="shiroConfigLocations"
+           value="file:/usr/local/myapp/conf/shiro.ini"
+           override="true" />
+----
+
+[TIP]
+====
+Note that Shiro is more flexible than Isis; it will read its configuration from any URL, not just a directory on the local filesystem.
+====
+
+
+
+
+[[_ug_deployment_externalized-configuration_Log4j]]
+== Log4j Config
+
+By default Isis configures log4j to read the `logging.properties` file in the `WEB-INF` directory. This can be overridden by setting the `log4j.properties` system property to the URL of the log4j properties file.
+
+For example, if deploying to Tomcat7, this amounts to adding the following to the `CATALINA_OPTS` flags:
+
+[source,bash]
+----
+export CATALINA_OPTS="-Dlog4j.configuration=/usr/local/tomcat/myapp/conf/logging.properties"
+----
+
+[TIP]
+====
+`CATALINA_OPTS` was called `TOMCAT_OPTS` in earlier versions of Tomcat.
+====
+
+Further details an be found in the link:https://logging.apache.org/log4j/1.2/manual.html#Example_Configurations[log4j documentation].
+
+
+
+
+== Externalizing Spring's Config
+
+Although Isis does not use Spring, it's possible that your app may use other components that do use Spring.  For example, the (non-ASF) http://github.com/isisaddons/isis-module-publishmq[Isis addons' publishmq] module uses ActiveMQ and Camel to support publishing; both of these leverage Spring.
+
+There are several ways to externalized Spring config, but the mechanism described here is similar in nature to those that we use for externalizing Isis' and Shiro's configuration.  In your `web.xml`, you will probably load the Spring application context using code such as:
+
+[source,xml]
+----
+<listener>
+    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+</listener>
+<context-param>
+    <param-name>contextConfigLocation</param-name>
+    <param-value>
+        classpath:my-application-context-config.xml
+    </param-value>
+</context-param>
+----
+
+Add a new application context `propertyPlaceholderConfigurer-config.xml` defining a `PropertyPlaceholderConfigurer` bean.
+
+[source,xml]
+----
+<beans
+  xmlns="http://www.springframework.org/schema/beans"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
+    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+        <property name="locations">
+            <list>
+                <value>${spring.config.file}</value>
+            </list>
+        </property>
+    </bean>
+</beans>
+----
+
+This reads the properties from a `spring.config.file`, defined as a context-param in the `web.xml`:
+
+[source,xml]
+----
+<context-param>
+    <param-name>spring.config.file</param-name>
+    <param-value>classpath:spring.properties</param-value>
+</context-param>
+
+----
+
+Then update the bootstrapping in `web.xml` to use this new application context, eg:
+
+[source,xml]
+----
+<context-param>
+    <param-name>contextConfigLocation</param-name>
+    <param-value>
+        classpath:my-application-context-config.xml,
+        classpath:propertyPlaceholderConfigurer-config.xml
+    </param-value>
+</context-param>
+----
+
+To use some other externalized configuration, override the `spring.config.file` property, eg using Tomcat's config file:
+
+[source,xml]
+----
+<Parameter name="spring.config.dir"
+           value="file:/usr/local/myapp/conf/spring.properties"
+           override="true" />
+----
+
+
+
+=== An alternative approach
+
+As mentioned, there are several other ways to externalize Spring's config; one approach is to use Spring's profile support.
+
+For example, in the application context you could have:
+
+[source,xml]
+----
+<beans profile="default">
+    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+        <property name="locations">
+            <list>
+                <value>classpath:dev.properties</value>
+            </list>
+        </property>
+    </bean>
+</beans>
+<beans profile="externalized">
+    <bean id="propertyPlaceHolder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+        <property name="locations">
+            <list>
+                <value>classpath:prod.properties</value>
+            </list>
+        </property>
+    </bean>
+</beans>
+----
+
+The idea being that specifying the "prod" profile rather than the "default" profile would cause a different set of configuration properties to be read.
+
+The active profile can be overridden with a system property, eg:
+
+[source,bash]
+----
+-Dspring.active.profiles=prod
+----
+
+
+take a look at link:http://stackoverflow.com/a/10041835/56880[this SO answer] on using Spring profiles.
+
+
+
+
+
+== See also
+
+See link:./_ug_deployment_jvm-flags[JVM args] for other JVM args and system properties that you might want to consider setting.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/c1fe0feb/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_gae.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_gae.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_gae.adoc
index d06d75c..a208414 100644
--- a/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_gae.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_gae.adoc
@@ -4,13 +4,13 @@
 :_basedir: ../
 :_imagesdir: images/
 
-IMPORTANT: TODO
-
-The Google App Engine (GAE) provides a JDO API, meaning that you can deploy Isis onto GAE using the JDO objectstore.
+The link:https://cloud.google.com/appengine/docs[Google App Engine] (GAE) provides a JDO API, meaning that you can deploy Isis onto GAE using the JDO objectstore.
 
 However, GAE is not an RDBMS, and so there are some limitations that it imposes. This page gathers together various hints, tips and workarounds.
 
 
+
+
 == Primary Keys and Owned/Unowned Relationships
 
 All entities must have a `@PrimaryKey`. Within GAE, the type of this key matters.
@@ -25,6 +25,8 @@ Note: if you store a relationship with a String key it means that the parent obj
 
 
 
+
+
 == Custom Types
 
 Currently Isis' `Blob` and `Clob` types and the JODA types (`LocalDate` et al) are _not_ supported in GAE.
@@ -41,7 +43,7 @@ On further investigation, it seems that the GAE implementation performs a type c
 [source,java]
 ----
 if (!supportedTypes.contains(value.getClass())) {
-     throw new IllegalArgumentException(prefix + value.getClass().getName() + " is not a supported property type.");
+    throw new IllegalArgumentException(prefix + value.getClass().getName() + " is not a supported property type.");
 }
 ----
 

http://git-wip-us.apache.org/repos/asf/isis/blob/c1fe0feb/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_jvm-flags.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_jvm-flags.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_jvm-flags.adoc
index d3edc30..75683cb 100644
--- a/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_jvm-flags.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_deployment_jvm-flags.adoc
@@ -4,6 +4,49 @@
 :_basedir: ../
 :_imagesdir: images/
 
-IMPORTANT: TODO
+NOTE: TODO
 
 
+The default JVM configuration will most likely not be appropriate for running Isis as a webapp.  The table below suggests some JVM args that you will probably want to modify:
+
+.JVM args
+[cols="1,1", options="header"]
+|===
+
+|Flag
+|Description
+
+|-server
+|Run the JVM in server mode, meaning that the JVM should spend more time on the optimization of the fragments of codes that are most often used (hotspots). This leads to better performance at the price of a higher overhead at startup.
+
+|-Xms128m
+Minimum heap size
+
+
+|-Xmx768m
+|Maximum heap size
+
+
+|-XX:PermSize=64m
+|Minimum perm size (for class definitions)
+
+
+|-XX:MaxPermSize=256m
+|Maximum perm size (for class definitions)
+
+
+|-XX:+DisableExplicitGC
+|Causes any explicit calls to <tt>System.gc()</tt> to be ignored.  +
++
+See link:http://stackoverflow.com/questions/12847151/setting-xxdisableexplicitgc-in-production-what-could-go-wrong[this stackoverflow] question.
+
+|===
+
+There are also a whole bunch of GC-related flags, that you might want to explore; see this detailed link:http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html[Hotspot JVM] documentation and also this link:http://blog.ragozin.info/2011/09/hotspot-jvm-garbage-collection-options.html[blog post].
+
+
+
+## Configuring in Tomcat
+
+If using Tomcat, update the `CATALINA_OPTS` variable.  (This variable is also updated if xref:_ug_deployment_externalized-configuration_Log4j[configuring logging to run externally]).
+

http://git-wip-us.apache.org/repos/asf/isis/blob/c1fe0feb/adocs/documentation/src/main/asciidoc/guides/_ug_runtime_configuration-files.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_runtime_configuration-files.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_runtime_configuration-files.adoc
index 04b8d82..e8c45ba 100644
--- a/adocs/documentation/src/main/asciidoc/guides/_ug_runtime_configuration-files.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_runtime_configuration-files.adoc
@@ -19,7 +19,9 @@ In addition, the following other properties are searched for and if present also
 
 * `persistor_datanucleus.properties` - assuming the JDO/DataNucleus objectstore is in use
 
-* `persistor.properties` - for any other objectstore configuration.  This typically is used to hold `JDBC` ``URL``s
+* `persistor.properties` - for any other objectstore configuration.  +
++
+This typically is used to hold `JDBC` ``URL``s, which is arguably a slight violation of the file (because there's nothing in Isis to say that persistors have to use `JDBC`.  However, it is generally convenient to put these `JDBC` settings into a single location.  If you want, they could reside inin any of `persistor_datanucleus.properties`, `persistor.properties` or (even) `isis.properties`
 
 * `authentication_shiro.properties`, `authorization_shiro.properties`
 +
@@ -34,3 +36,5 @@ You can if you wish simply store all properties in the `isis.properties` file; b
 
 
 
+
+

http://git-wip-us.apache.org/repos/asf/isis/blob/c1fe0feb/adocs/documentation/src/main/asciidoc/guides/_ug_runtime_configuring-core.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_runtime_configuring-core.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_runtime_configuring-core.adoc
index 9f2fdd0..b1d7b8e 100644
--- a/adocs/documentation/src/main/asciidoc/guides/_ug_runtime_configuring-core.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_runtime_configuring-core.adoc
@@ -107,14 +107,31 @@ Each entry can be optionally prefixed by "n:" specifying the relative order on t
 
 `ignoreQueryOnly` is an alias for `ignoreSafe`.
 
+
+|`isis.services.` +
+`container.disableAutoFlush`
+| `true`,`false` (`_false_`)
+|Whether the `DomainObjectContainer` should automatically flush pending changes prior to querying (via `allMatches()`, `firstMatch()` and so on).
+
 |`isis.services.` +
 `container.disableAutoFlush`
 | `true`,`false` (`_false_`)
 |Whether the `DomainObjectContainer` should automatically flush pending changes prior to querying (via `allMatches()`, `firstMatch()` and so on).
 
 
+
+|`ContentNegotiation-` +
+`ServiceXRoDomainType` +
+.prettyPrint
+| `true`,`false` (depends)
+|If a domain object has been mapped to the specified JAXB `x-ro-domain-type`, then determines whether the result is pretty-printed or not. +
++
+If no configuration property is available, then the defaults is determined by the xref:_ug_runtime_deployment-types[deployment type]: production mode disables pretty printing, while prototype mode enables it.
+
+
+
 | `isis.service.` +
-`email.tls.enabled` +
+`email.tls.enabled`
 | `true`,`false` (`_true_`)
 |Whether to enable TLS for the email SMTP connection (used by xref:rg.adoc#_rg_services-api_manpage-EmailService[`EmailService`]).  +
 

http://git-wip-us.apache.org/repos/asf/isis/blob/c1fe0feb/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/conneg/IsisPrettyPrintingProcessor.java
----------------------------------------------------------------------
diff --git a/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/conneg/IsisPrettyPrintingProcessor.java b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/conneg/IsisPrettyPrintingProcessor.java
new file mode 100644
index 0000000..e2af847
--- /dev/null
+++ b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/conneg/IsisPrettyPrintingProcessor.java
@@ -0,0 +1,68 @@
+/**
+ *  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.
+ */
+package org.apache.isis.viewer.restfulobjects.rendering.service.conneg;
+
+import java.lang.annotation.Annotation;
+
+import javax.ws.rs.core.MediaType;
+import javax.xml.bind.Marshaller;
+
+import org.jboss.resteasy.annotations.DecorateTypes;
+import org.jboss.resteasy.spi.interception.DecoratorProcessor;
+
+import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.runtime.system.DeploymentType;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+
+@DecorateTypes({"text/*+xml", "application/*+xml"})
+public class IsisPrettyPrintingProcessor implements DecoratorProcessor<Marshaller, PrettyPrinting> {
+
+    public static final String KEY_PRETTY_PRINT = "isis.services." + ContentNegotiationServiceXRoDomainType.class.getSimpleName() + ".prettyPrint";
+
+    @Override
+    public Marshaller decorate(final Marshaller target, final PrettyPrinting annotation, final Class type, final Annotation[] annotations, final MediaType mediaType) {
+        return shouldPrettyPrint()
+                ? doDecorate(target, annotation, type, annotations, mediaType)
+                : target;
+    }
+
+    protected boolean shouldPrettyPrint() {
+        try {
+            final DeploymentType deploymentType = getDeploymentType();
+            return getConfiguration().getBoolean(KEY_PRETTY_PRINT, !deploymentType.isProduction());
+        } catch (Exception e) {
+            return true;
+        }
+    }
+
+    protected Marshaller doDecorate(Marshaller target, PrettyPrinting annotation, Class type, Annotation[] annotations, MediaType mediaType) {
+        try {
+            target.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+            return target;
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    protected DeploymentType getDeploymentType() {
+        return IsisContext.getDeploymentType();
+    }
+
+    protected IsisConfiguration getConfiguration() {
+        return IsisContext.getConfiguration();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c1fe0feb/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/conneg/PrettyPrinting.java
----------------------------------------------------------------------
diff --git a/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/conneg/PrettyPrinting.java b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/conneg/PrettyPrinting.java
new file mode 100644
index 0000000..46ef491
--- /dev/null
+++ b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/service/conneg/PrettyPrinting.java
@@ -0,0 +1,31 @@
+/**
+ *  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.
+ */
+package org.apache.isis.viewer.restfulobjects.rendering.service.conneg;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.xml.bind.Marshaller;
+
+import org.jboss.resteasy.annotations.Decorator;
+
+@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Decorator(processor = IsisPrettyPrintingProcessor.class, target = Marshaller.class)
+public @interface PrettyPrinting {}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/c1fe0feb/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainObjectResourceServerside.java
----------------------------------------------------------------------
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainObjectResourceServerside.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainObjectResourceServerside.java
index e3efc60..1c09e77 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainObjectResourceServerside.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainObjectResourceServerside.java
@@ -46,6 +46,7 @@ import org.apache.isis.viewer.restfulobjects.applib.client.RestfulResponse.HttpS
 import org.apache.isis.viewer.restfulobjects.applib.domainobjects.DomainObjectResource;
 import org.apache.isis.viewer.restfulobjects.rendering.RestfulObjectsApplicationException;
 import org.apache.isis.viewer.restfulobjects.rendering.domainobjects.MemberReprMode;
+import org.apache.isis.viewer.restfulobjects.rendering.service.conneg.PrettyPrinting;
 import org.apache.isis.viewer.restfulobjects.rendering.util.Util;
 
 @Path("/objects")
@@ -112,6 +113,7 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
             MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_OBJECT, RestfulMediaType.APPLICATION_JSON_ERROR,
             MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_OBJECT, RestfulMediaType.APPLICATION_XML_ERROR
     })
+    @PrettyPrinting
     public Response object(@PathParam("domainType") String domainType, @PathParam("instanceId") final String instanceId) {
         init(RepresentationType.DOMAIN_OBJECT, Where.OBJECT_FORMS);
 
@@ -132,6 +134,7 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
             MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_OBJECT, RestfulMediaType.APPLICATION_JSON_ERROR,
             MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_OBJECT, RestfulMediaType.APPLICATION_XML_ERROR
     })
+    @PrettyPrinting
     public Response object(@PathParam("domainType") String domainType, @PathParam("instanceId") final String instanceId, final InputStream object) {
 
         init(RepresentationType.DOMAIN_OBJECT, Where.OBJECT_FORMS);
@@ -179,6 +182,7 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
             MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_OBJECT_PROPERTY, RestfulMediaType.APPLICATION_JSON_ERROR,
             MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_OBJECT_PROPERTY, RestfulMediaType.APPLICATION_XML_ERROR
     })
+    @PrettyPrinting
     public Response propertyDetails(@PathParam("domainType") String domainType, @PathParam("instanceId") final String instanceId, @PathParam("propertyId") final String propertyId) {
         init(RepresentationType.OBJECT_PROPERTY, Where.OBJECT_FORMS);
 
@@ -274,13 +278,13 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
             MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_OBJECT_COLLECTION, RestfulMediaType.APPLICATION_JSON_ERROR,
             MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_OBJECT_COLLECTION, RestfulMediaType.APPLICATION_XML_ERROR
     })
+    @PrettyPrinting
     public Response accessCollection(@PathParam("domainType") String domainType, @PathParam("instanceId") final String instanceId, @PathParam("collectionId") final String collectionId) {
         init(RepresentationType.OBJECT_COLLECTION, Where.PARENTED_TABLES);
 
         final ObjectAdapter objectAdapter = getObjectAdapterElseThrowNotFound(domainType, instanceId);
-        final DomainResourceHelper helper = getDomainResourceHelper(objectAdapter);
 
-        return helper.collectionDetails(collectionId, MemberReprMode.READ);
+        return getDomainResourceHelper(objectAdapter).collectionDetails(collectionId, MemberReprMode.READ);
     }
 
     @Override
@@ -398,6 +402,7 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
             MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_OBJECT_ACTION, RestfulMediaType.APPLICATION_JSON_ERROR,
             MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_OBJECT_ACTION, RestfulMediaType.APPLICATION_XML_ERROR
     })
+    @PrettyPrinting
     public Response actionPrompt(@PathParam("domainType") String domainType, @PathParam("instanceId") final String instanceId, @PathParam("actionId") final String actionId) {
         init(RepresentationType.OBJECT_ACTION, Where.OBJECT_FORMS);
 
@@ -434,6 +439,7 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
             MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_ACTION_RESULT, RestfulMediaType.APPLICATION_JSON_ERROR,
             MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_ACTION_RESULT, RestfulMediaType.APPLICATION_XML_ERROR
     })
+    @PrettyPrinting
     public Response invokeActionQueryOnly(
             final @PathParam("domainType") String domainType,
             final @PathParam("instanceId") String instanceId,
@@ -459,6 +465,7 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
             MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_ACTION_RESULT, RestfulMediaType.APPLICATION_JSON_ERROR,
             MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_ACTION_RESULT, RestfulMediaType.APPLICATION_XML_ERROR
     })
+    @PrettyPrinting
     public Response invokeActionIdempotent(
             final @PathParam("domainType") String domainType,
             final @PathParam("instanceId") String instanceId,
@@ -483,6 +490,7 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
             MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_ACTION_RESULT, RestfulMediaType.APPLICATION_JSON_ERROR,
             MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_ACTION_RESULT, RestfulMediaType.APPLICATION_XML_ERROR
     })
+    @PrettyPrinting
     public Response invokeAction(@PathParam("domainType") String domainType, @PathParam("instanceId") final String instanceId, @PathParam("actionId") final String actionId, final InputStream body) {
         init(RepresentationType.ACTION_RESULT, Where.STANDALONE_TABLES, body);
 

http://git-wip-us.apache.org/repos/asf/isis/blob/c1fe0feb/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainServiceResourceServerside.java
----------------------------------------------------------------------
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainServiceResourceServerside.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainServiceResourceServerside.java
index 4c2b56e..62c1268 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainServiceResourceServerside.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainServiceResourceServerside.java
@@ -40,6 +40,7 @@ import org.apache.isis.viewer.restfulobjects.rendering.Responses;
 import org.apache.isis.viewer.restfulobjects.rendering.domainobjects.DomainObjectReprRenderer;
 import org.apache.isis.viewer.restfulobjects.rendering.domainobjects.DomainServiceLinkTo;
 import org.apache.isis.viewer.restfulobjects.rendering.RestfulObjectsApplicationException;
+import org.apache.isis.viewer.restfulobjects.rendering.service.conneg.PrettyPrinting;
 
 @Path("/services")
 public class DomainServiceResourceServerside extends ResourceAbstract implements DomainServiceResource {
@@ -106,6 +107,7 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
             MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_OBJECT, RestfulMediaType.APPLICATION_JSON_ERROR,
             MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_OBJECT, RestfulMediaType.APPLICATION_XML_ERROR
     })
+    @PrettyPrinting
     public Response service(@PathParam("serviceId") final String serviceId) {
         init(RepresentationType.DOMAIN_OBJECT, Where.OBJECT_FORMS);
 
@@ -146,6 +148,7 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
             MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_OBJECT_ACTION, RestfulMediaType.APPLICATION_JSON_ERROR,
             MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_OBJECT_ACTION, RestfulMediaType.APPLICATION_XML_ERROR
     })
+    @PrettyPrinting
     public Response actionPrompt(@PathParam("serviceId") final String serviceId, @PathParam("actionId") final String actionId) {
         init(RepresentationType.OBJECT_ACTION, Where.OBJECT_FORMS);
 
@@ -181,6 +184,7 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
             MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_ACTION_RESULT, RestfulMediaType.APPLICATION_JSON_ERROR,
             MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_ACTION_RESULT, RestfulMediaType.APPLICATION_XML_ERROR
     })
+    @PrettyPrinting
     public Response invokeActionQueryOnly(
             final @PathParam("serviceId") String serviceId,
             final @PathParam("actionId") String actionId,
@@ -208,6 +212,7 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
             MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_ACTION_RESULT, RestfulMediaType.APPLICATION_JSON_ERROR,
             MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_ACTION_RESULT, RestfulMediaType.APPLICATION_XML_ERROR
     })
+    @PrettyPrinting
     public Response invokeActionIdempotent(
             final @PathParam("serviceId") String serviceId,
             final @PathParam("actionId") String actionId,
@@ -231,6 +236,7 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
             MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_ACTION_RESULT, RestfulMediaType.APPLICATION_JSON_ERROR,
             MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_ACTION_RESULT, RestfulMediaType.APPLICATION_XML_ERROR
     })
+    @PrettyPrinting
     public Response invokeAction(@PathParam("serviceId") final String serviceId, @PathParam("actionId") final String actionId, final InputStream body) {
         init(RepresentationType.ACTION_RESULT, Where.STANDALONE_TABLES, body);