You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2018/06/03 08:52:03 UTC

[isis] 01/02: ISIS-1959: Update to Wicket 8

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 9ec61c0c3a9ec47b9488ce8c6ac37ebcc8abb060
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sat Jun 2 14:46:45 2018 +0200

    ISIS-1959: Update to Wicket 8
    
    tabs don't work yet
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-1959
---
 core/pom.xml                                       |   14 +-
 .../background/BackgroundServiceDefault.java       |    4 +
 .../wicket/viewer/IsisWicketApplication.java       | 1647 ++++++++++----------
 .../ActionResultResponseHandlingStrategy.java      |    7 +-
 .../serviceactions/TertiaryActionsPanel.java       |   26 +-
 .../ajaxtable/IsisAjaxFallbackHeadersToolbar.java  |   29 +-
 .../ajaxtable/IsisAjaxFallbackOrderByBorder.java   |   13 +-
 .../ajaxtable/IsisAjaxNavigationToolbar.java       |    6 +-
 .../components/tree/IsisToWicketTreeAdapter.java   |    5 +-
 .../widgets/buttons/ContainedButtonPanel.java      |    2 +-
 .../select2/providers/EmptyChoiceProvider.java     |   11 +-
 .../wicket/ui/panels/PromptFormAbstract.java       |   31 +-
 12 files changed, 910 insertions(+), 885 deletions(-)

diff --git a/core/pom.xml b/core/pom.xml
index 880991d..cfcafa9 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -154,12 +154,17 @@
 
         <jetty.version>9.4.3.v20170317</jetty.version>
 
-        <wicket.version>7.9.0</wicket.version>
-        <wicketstuff.version>7.8.1</wicketstuff.version>
+        <wicket.version>8.0.0</wicket.version>
+        <wicketstuff.version>8.0.0</wicketstuff.version>
+        <wicket-source.version>7.0.0</wicket-source.version>
 
+<!-- [ahuber] update to newer versions just does not work as a drop in replacement
+        <wicket-webjars.version>2.0.7</wicket-webjars.version>
+        <wicket-bootstrap.version>2.0.1</wicket-bootstrap.version>
+-->     
         <wicket-webjars.version>0.5.4</wicket-webjars.version>
         <wicket-bootstrap.version>0.10.16</wicket-bootstrap.version>
-        <wicket-source.version>7.0.0</wicket-source.version>
+        
 
         <select2.version>4.0.3</select2.version>
 
@@ -1984,7 +1989,8 @@ ${license.additional-notes}
 
 
             <dependency>
-                <groupId>net.ftlines.wicket-source</groupId>
+            	<groupId>net.ftlines.wicket-source</groupId>
+<!-- [ahuber] for version 8.0.0 we might consider<groupId>com.github.jennybrown8.wicket-source</groupId> -->
                 <artifactId>wicket-source</artifactId>
                 <version>${wicket-source.version}</version>
                 <exclusions>
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundServiceDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundServiceDefault.java
index d3010fe..3f11b89 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundServiceDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundServiceDefault.java
@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
@@ -193,6 +194,9 @@ public class BackgroundServiceDefault implements BackgroundService2 {
                 final Command command = commandContext.getCommand();
 
                 final BackgroundCommandService2 bcs2 = (BackgroundCommandService2) backgroundCommandService;
+                Objects.requireNonNull(bcs2, 
+                		()->String.format("You need to provide a domain-service implementing '%s'!", 
+                				BackgroundCommandService2.class.getName()));
 
                 final List<ObjectAdapter> targetList = Collections.singletonList(domainObjectAdapter);
                 final CommandDto dto =
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
index b60ee44..94af982 100644
--- a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
@@ -30,6 +30,7 @@ import java.util.UUID;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.function.Function;
 
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.context._Context;
@@ -85,6 +86,7 @@ import org.apache.wicket.Page;
 import org.apache.wicket.RuntimeConfigurationType;
 import org.apache.wicket.SharedResources;
 import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.AjaxRequestTarget.IListener;
 import org.apache.wicket.authentication.IAuthenticationStrategy;
 import org.apache.wicket.authentication.strategy.DefaultAuthenticationStrategy;
 import org.apache.wicket.authroles.authentication.AuthenticatedWebApplication;
@@ -98,9 +100,9 @@ import org.apache.wicket.devutils.debugbar.VersionDebugContributor;
 import org.apache.wicket.devutils.diskstore.DebugDiskDataStore;
 import org.apache.wicket.guice.GuiceComponentInjector;
 import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.ResourceAggregator;
 import org.apache.wicket.markup.head.filter.JavaScriptFilteredIntoFooterHeaderResponse;
 import org.apache.wicket.markup.html.IHeaderContributor;
-import org.apache.wicket.markup.html.IHeaderResponseDecorator;
 import org.apache.wicket.markup.html.WebPage;
 import org.apache.wicket.request.cycle.IRequestCycleListener;
 import org.apache.wicket.request.cycle.PageRequestHandlerTracker;
@@ -108,15 +110,12 @@ import org.apache.wicket.request.cycle.RequestCycleListenerCollection;
 import org.apache.wicket.request.resource.CssResourceReference;
 import org.apache.wicket.settings.DebugSettings;
 import org.apache.wicket.settings.RequestCycleSettings;
-import org.apache.wicket.util.IContextProvider;
 import org.apache.wicket.util.time.Duration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.wicketstuff.select2.ApplicationSettings;
 
-import com.google.common.base.Function;
 import com.google.common.base.Joiner;
-import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import com.google.common.io.Resources;
 import com.google.inject.Guice;
@@ -156,823 +155,827 @@ import net.ftlines.wicketsource.WicketSource;
  * This mechanism allows a number of other aspects to be customized.
  */
 public class IsisWicketApplication
-        extends AuthenticatedWebApplication
-        implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, WicketViewerSettingsAccessor {
-
-    private static final long serialVersionUID = 1L;
-    
-    private static final Logger LOG = LoggerFactory.getLogger(IsisWicketApplication.class);
-
-    private static final String STRIP_WICKET_TAGS_KEY = "isis.viewer.wicket.stripWicketTags";
-    private static final boolean STRIP_WICKET_TAGS_DEFAULT = true;
-    private static final String AJAX_DEBUG_MODE_KEY = "isis.viewer.wicket.ajaxDebugMode";
-    private static final boolean AJAX_DEBUG_MODE_DEFAULT = false;
-    private static final String WICKET_SOURCE_PLUGIN_KEY = "isis.viewer.wicket.wicketSourcePlugin";
-    private static final boolean WICKET_SOURCE_PLUGIN_DEFAULT = false;
-
-    private static final String WICKET_REMEMBER_ME_COOKIE_KEY = "isis.viewer.wicket.rememberMe.cookieKey";
-    private static final String WICKET_REMEMBER_ME_COOKIE_KEY_DEFAULT = "isisWicketRememberMe";
-    private static final String WICKET_REMEMBER_ME_ENCRYPTION_KEY = "isis.viewer.wicket.rememberMe.encryptionKey";
-
-    /**
-     * A configuration setting which value determines whether debug bar and other stuff influenced by {@link DebugSettings#isDevelopmentUtilitiesEnabled()} is enabled or not.
-     *
-     * <p>
-     *     By default, depends on the mode (prototyping = enabled, server = disabled).  This property acts as an override.
-     * </p>
-     */
-    public static final String ENABLE_DEVELOPMENT_UTILITIES_KEY = "isis.viewer.wicket.developmentUtilities.enable";
-    public static final boolean ENABLE_DEVELOPMENT_UTILITIES_DEFAULT = false;
-
-
-
-    private final IsisLoggingConfigurer loggingConfigurer = new IsisLoggingConfigurer();
-
-    /**
-     * Convenience locator, downcasts inherited functionality.
-     */
-    public static IsisWicketApplication get() {
-        return (IsisWicketApplication) AuthenticatedWebApplication.get();
-    }
-
-    /**
-     * {@link com.google.inject.Inject Inject}ed when {@link #init() initialized}.
-     */
-    @com.google.inject.Inject
-    private ComponentFactoryRegistry componentFactoryRegistry;
-
-    /**
-     * {@link com.google.inject.Inject Inject}ed when {@link #init() initialized}.
-     */
-    @SuppressWarnings("unused")
-    @com.google.inject.Inject
-    private ImageResourceCache imageCache;
-
-    /**
-     * {@link com.google.inject.Inject Inject}ed when {@link #init() initialized}.
-     */
-    @SuppressWarnings("unused")
-    @com.google.inject.Inject
-    private WicketViewerSettings wicketViewerSettings;
-
-    /**
-     * {@link com.google.inject.Inject Inject}ed when {@link #init() initialized}.
-     */
-    @com.google.inject.Inject
-    private PageClassRegistry pageClassRegistry;
-
-    /**
-     * {@link com.google.inject.Inject Inject}ed when {@link #init() initialized}.
-     */
-    @com.google.inject.Inject
-    private IsisSessionFactory isisSessionFactory;
-
-    /**
-     * {@link com.google.inject.Inject Inject}ed when {@link #init() initialized}.
-     */
-    @com.google.inject.Inject
-    private IsisConfiguration configuration;
-
-    /**
-     * {@link com.google.inject.Inject Inject}ed when {@link #init() initialized}.
-     */
-    @com.google.inject.Inject
-    private DeploymentCategory deploymentCategory;
-
-    @com.google.inject.Inject
-    private WicketViewerSettings settings;
-
-
-    private boolean determiningConfigurationType;
-    private DeploymentTypeWicketAbstract deploymentType;
-
-
-    // /////////////////////////////////////////////////
-    // constructor, init
-    // /////////////////////////////////////////////////
-
-    public IsisWicketApplication() {
-    }
-
-
-    /**
-     * Although there are warnings about not overriding this method, it doesn't seem possible
-     * to call {@link #setResourceSettings(org.apache.wicket.settings.ResourceSettings)} in the
-     * {@link #init()} method.
-     */
-    @Override
-    protected void internalInit() {
-        // replace with custom implementation of ResourceSettings that changes the order
-        // in which search for i18n properties, to search for the application-specific
-        // settings before any other.
-        setResourceSettings(new IsisResourceSettings(this));
-
-        // this doesn't seem to accomplish anything
-        // addListenerToStripRemovedComponentsFromAjaxTargetResponse();
-
-        super.internalInit();
-    }
-
-    @Override
-    public Application setAjaxRequestTargetProvider(final IContextProvider<AjaxRequestTarget, Page> ajaxRequestTargetProvider) {
-        final Application application = super.setAjaxRequestTargetProvider(new IContextProvider<AjaxRequestTarget, Page>(){
-            @Override
-            public AjaxRequestTarget get(final Page context) {
-                return decorate(ajaxRequestTargetProvider.get(context));
-            }
-
-            AjaxRequestTarget decorate(final AjaxRequestTarget ajaxRequestTarget) {
-                ajaxRequestTarget.registerRespondListener(
-                        new TargetRespondListenerToResetQueryResultCache());
-                return ajaxRequestTarget;
-            }
-        } );
-        return application;
-    }
-
-    // idea here is to avoid XmlPartialPageUpdate spitting out warnings, eg:
-    //
-    // 13:08:36,642  [XmlPartialPageUpdate qtp1988859660-18 WARN ]  Component '[AjaxLink [Component id = copyLink]]' with markupid: 'copyLink94c' not rendered because it was already removed from page
-    //  13:08:36,642  [XmlPartialPageUpdate qtp1988859660-18 WARN ]  Component '[SimpleClipboardModalWindow [Component id = simpleClipboardModalWindow]]' with markupid: 'simpleClipboardModalWindow94e' not rendered because it was already removed from page
-    // 13:08:36,643  [XmlPartialPageUpdate qtp1988859660-18 WARN ]  Component '[AjaxFallbackLink [Component id = link]]' with markupid: 'link951' not rendered because it was already removed from page
-    // 13:08:36,643  [XmlPartialPageUpdate qtp1988859660-18 WARN ]  Component '[AjaxFallbackLink [Component id = link]]' with markupid: 'link952' not rendered because it was already removed from page
-    // 13:08:36,655  [XmlPartialPageUpdate qtp1988859660-18 WARN ]  Component '[AjaxLink [Component id = clearBookmarkLink]]' with markupid: 'clearBookmarkLink953' not rendered because it was already removed from page
-    //
-    // however, doesn't seem to work (even though the provided map is mutable).
-    // must be some other sort of side-effect which causes the enqueued component(s) to be removed from page between
-    // this listener firing and XmlPartialPageUpdate actually attempting to render the change components
-    //
-    private boolean addListenerToStripRemovedComponentsFromAjaxTargetResponse() {
-        return getAjaxRequestTargetListeners().add(new AjaxRequestTarget.AbstractListener(){
-
-            @Override
-            public void onBeforeRespond(Map<String, Component> map, AjaxRequestTarget target)
-            {
-
-                List<String> idsToRemove = Lists.newArrayList();
-                final Set<Map.Entry<String, Component>> entries = map.entrySet();
-                for (Map.Entry<String, Component> entry : entries) {
-                    final Component component = entry.getValue();
-                    final Page page = component.findParent(Page.class);
-                    if(page == null) {
-                        idsToRemove.add(entry.getKey());
-                    }
-                }
-                for (String id : idsToRemove) {
-                    map.remove(id);
-                }
-
-            }
-        });
-    }
-
-    /**
-     * Initializes the application; in particular, bootstrapping the Isis
-     * backend, and initializing the {@link ComponentFactoryRegistry} to be used
-     * for rendering.
-     */
-    @Override
-    protected void init() {
-        List<Future<Object>> futures = null;
-        try {
-            super.init();
-            
-            _Context.setDefaultClassLoader(this.getClass().getClassLoader(), true);
-
-            futures = startBackgroundInitializationThreads();
-
-            String isisConfigDir = getServletContext().getInitParameter("isis.config.dir");
-
-            configureLogging(isisConfigDir);
-    
-            getRequestCycleSettings().setRenderStrategy(RequestCycleSettings.RenderStrategy.REDIRECT_TO_RENDER);
-
-            getResourceSettings().setParentFolderPlaceholder("$up$");
-
-            final IsisConfigurationBuilder isisConfigurationBuilder = obtainConfigBuilder();
-            isisConfigurationBuilder.addDefaultConfigurationResourcesAndPrimers();
-
-            _Resource.putContextPathIfPresent(getServletContext().getContextPath());
-
-            final IsisConfigurationDefault configuration = isisConfigurationBuilder.getConfiguration();
-
-            DeploymentTypeWicketAbstract deploymentType =
-                    determineDeploymentType(configuration.getString("isis.deploymentType"));
-
-            RequestCycleListenerCollection requestCycleListeners = getRequestCycleListeners();
-            IRequestCycleListener requestCycleListenerForIsis = newWebRequestCycleForIsis();
-            requestCycleListeners.add(requestCycleListenerForIsis);
-            requestCycleListeners.add(new PageRequestHandlerTracker());
-
-            //
-            // create IsisSessionFactory
-            //
-            final DeploymentCategory deploymentCategory = deploymentType.getDeploymentCategory();
-            final IsisInjectModule isisModule = newIsisModule(deploymentCategory, configuration);
-            final Injector injector = Guice.createInjector(isisModule, newIsisWicketModule());
-            initWicketComponentInjection(injector);
-
-            injector.injectMembers(this); // populates this.isisSessionFactory
-
-            getServletContext().setAttribute(WebAppConstants.ISIS_SESSION_FACTORY, this.isisSessionFactory);
-
-
-            if (requestCycleListenerForIsis instanceof WebRequestCycleForIsis) {
-                WebRequestCycleForIsis webRequestCycleForIsis = (WebRequestCycleForIsis) requestCycleListenerForIsis;
-                webRequestCycleForIsis.setPageClassRegistry(pageClassRegistry);
-            }
-            
-            this.getMarkupSettings().setStripWicketTags(determineStripWicketTags(configuration));
-
-            configureSecurity(configuration);
-
-            getDebugSettings().setAjaxDebugModeEnabled(determineAjaxDebugModeEnabled(configuration));
-
-            // must be done after injected componentFactoryRegistry into the app itself
-            buildCssBundle();
-
-            filterJavascriptContributions();
-
-            configureWicketSourcePluginIfNecessary();
-
-            // TODO ISIS-987 Either make the API better (no direct access to the map) or use DB records
-            int maxEntries = 1000;
-            setMetaData(AccountConfirmationMap.KEY, new AccountConfirmationMap(maxEntries, Duration.days(1)));
-
-            mountPages();
-
-            @SuppressWarnings("unused")
-            SharedResources sharedResources = getSharedResources();
-
-            final MetaModelInvalidException mmie = IsisContext.getMetaModelInvalidExceptionIfAny();
-            if(mmie != null) {
-                log(mmie.getValidationErrors());
-            }
-
-            if(getDeploymentCategory().isPrototyping()) {
-                DebugDiskDataStore.register(this);
-                LOG.info("DebugDiskDataStore registered; access via ~/wicket/internal/debug/diskDataStore");
-                LOG.info("DebugDiskDataStore: eg, http://localhost:8080/wicket/wicket/internal/debug/diskDataStore");
-            }
-
-            if(!getDebugSettings().isDevelopmentUtilitiesEnabled()) {
-                boolean enableDevUtils = configuration
-                        .getBoolean(ENABLE_DEVELOPMENT_UTILITIES_KEY, ENABLE_DEVELOPMENT_UTILITIES_DEFAULT);
-                if(enableDevUtils) {
-                    getDebugSettings().setDevelopmentUtilitiesEnabled(true);
-
-                    // copied from DebugBarInitializer
-                    // this is hacky, but need to do this because IInitializer#init() called before
-                    // the Application's #init() is called.
-                    // an alternative, better, design might be to move Isis' own initialization into an
-                    // implementation of IInitializer?
-                    DebugBar.registerContributor(VersionDebugContributor.DEBUG_BAR_CONTRIB, this);
-                    DebugBar.registerContributor(InspectorDebugPanel.DEBUG_BAR_CONTRIB, this);
-                    DebugBar.registerContributor(SessionSizeDebugPanel.DEBUG_BAR_CONTRIB, this);
-                    DebugBar.registerContributor(PageSizeDebugPanel.DEBUG_BAR_CONTRIB, this);
-                }
-            }
-
-            LOG.info("storeSettings.inmemoryCacheSize        : {}", getStoreSettings().getInmemoryCacheSize());
-            LOG.info("storeSettings.asynchronousQueueCapacity: {}", getStoreSettings().getAsynchronousQueueCapacity());
-            LOG.info("storeSettings.maxSizePerSession        : {}", getStoreSettings().getMaxSizePerSession());
-            LOG.info("storeSettings.fileStoreFolder          : {}", getStoreSettings().getFileStoreFolder());
-
-        } catch(RuntimeException ex) {
-            // because Wicket's handling in its WicketFilter (that calls this method) does not log the exception.
-            LOG.error("Failed to initialize", ex);
-            throw ex;
-        } finally {
-            ThreadPoolSupport.join(futures);
-        }
-    }
-
-    protected List<Future<Object>> startBackgroundInitializationThreads() {
-        return ThreadPoolSupport.getInstance().invokeAll(_Lists.<Callable<Object>>of(
-        		
-        		Executors.callable(this::configureWebJars),
-        		Executors.callable(this::configureWicketBootstrap),
-        		Executors.callable(this::configureWicketSelect2),
-        		Executors.callable(ChangesDtoUtils::init),
-        		Executors.callable(InteractionDtoUtils::init),
-        		Executors.callable(CommandDtoUtils::init)
-        ));
-    }
-
-    /**
-     * protected visibility to allow ad-hoc overriding of some other authentication strategy.
-     */
-    protected void configureSecurity(final IsisConfiguration configuration) {
-        getSecuritySettings().setAuthenticationStrategy(newAuthenticationStrategy(configuration));
-    }
-
-    /**
-     * protected visibility to allow ad-hoc overriding of some other authentication strategy.
-     */
-    protected IAuthenticationStrategy newAuthenticationStrategy(final IsisConfiguration configuration) {
-        final String cookieKey = configuration.getString(WICKET_REMEMBER_ME_COOKIE_KEY,
-                WICKET_REMEMBER_ME_COOKIE_KEY_DEFAULT);
-        final String encryptionKey = configuration.getString(WICKET_REMEMBER_ME_ENCRYPTION_KEY, defaultEncryptionKeyIfNotConfigured());
-        return new DefaultAuthenticationStrategy(cookieKey, encryptionKey);
-    }
-
-    /**
-     * As called by {@link #newAuthenticationStrategy(IsisConfiguration)}; if an encryption key for the 'rememberMe'
-     * cookie hasn't been configured, then use a different encryption key for the 'rememberMe' cookie each time the
-     * app is restarted.
-     */
-    protected String defaultEncryptionKeyIfNotConfigured() {
-        return getDeploymentCategory().isProduction()
-                ? UUID.randomUUID().toString()
-                : "PrototypingEncryptionKey";
-    }
-
-    private void log(final Set<String> validationErrors) {
-        log("");
-        logBanner();
-        log("");
-        for (String validationError : validationErrors) {
-            logError(validationError);
-        }
-        log("");
-        log("Please inspect the above messages and correct your domain model.");
-        log("");
-        logBanner();
-        log("");
-    }
-
-    private void configureWicketSelect2() {
-        ApplicationSettings select2Settings = ApplicationSettings.get();
-        select2Settings.setCssReference(new Select2BootstrapCssReference());
-        select2Settings.setJavaScriptReference(new Select2JsReference());
-    }
-
-    protected void configureWicketSourcePluginIfNecessary() {
-        if(isWicketSourcePluginEnabled(this.configuration)) {
-            configureWicketSourcePlugin();
-        }
-    }
-
-    protected void configureWicketSourcePlugin() {
-        if(!deploymentCategory.isProduction()) {
-            WicketSource.configure(this);
-        }
-    }
-
-    /**
-     * For convenience of subclasses.
-     */
-    protected static String readLines(final Class<?> contextClass, final String resourceName, final String fallback) {
-        try {
-            List<String> readLines = Resources.readLines(Resources.getResource(contextClass, resourceName), Charset.defaultCharset());
-            final String aboutText = Joiner.on("\n").join(readLines);
-            return aboutText;
-        } catch (IOException e) {
-            return fallback;
-        }
-    }
-
-
-    // //////////////////////////////////////
-
-    /**
-     * Install 2 default collector instances: (FileAssetPathCollector(WEBJARS_PATH_PREFIX), JarAssetPathCollector),
-     * and a webjars resource finder.
-     *
-     * <p>
-     * Factored out for easy (informal) pluggability.
-     * </p>
-     */
-    protected void configureWebJars() {
-        IWebjarsSettings settings = new WebjarsSettings();
-        WicketWebjars.install(this, settings);
-    }
-
-    protected void configureWicketBootstrap() {
-        final IBootstrapSettings settings = new BootstrapSettings();
-        settings.setDeferJavascript(false);
-        Bootstrap.install(this, settings);
-
-        getHeaderContributorListeners().add(new IHeaderContributor() {
-            @Override
-            public void renderHead(IHeaderResponse response) {
-                BootstrapBaseBehavior bootstrapBaseBehavior = new BootstrapBaseBehavior();
-                bootstrapBaseBehavior.renderHead(settings, response);
-            }
-        });
-    }
-
-    // //////////////////////////////////////
-
-    /**
-     * Factored out for easy (informal) pluggability.
-     */
-    protected void configureLogging(String isisConfigDir) {
-        final String loggingPropertiesDir;
-        if(isisConfigDir != null) {
-            loggingPropertiesDir = isisConfigDir;
-        } else {
-            loggingPropertiesDir = getServletContext().getRealPath("/WEB-INF");
-        }
-
-        loggingConfigurer.configureLogging(loggingPropertiesDir, new String[0]);
-    }
-
-    // //////////////////////////////////////
-
-    /**
-     * Factored out for easy (informal) pluggability.
-     */
-    protected IRequestCycleListener newWebRequestCycleForIsis() {
-        return new WebRequestCycleForIsis();
-    }
-
-    // //////////////////////////////////////
-
-    /**
-     * Made protected visibility for easy (informal) pluggability.
-     */
-    protected void determineDeploymentTypeIfRequired() {
-        if(deploymentType != null) {
-            return;
-        }
-
-        determiningConfigurationType = true;
-        try {
-            final IsisConfigurationBuilder isisConfigurationBuilder = obtainConfigBuilder();
-
-            final IsisConfiguration configuration = isisConfigurationBuilder.peekConfiguration();
-            String deploymentTypeFromConfig = configuration.getString("isis.deploymentType");
-            deploymentType = determineDeploymentType(deploymentTypeFromConfig);
-        } finally {
-            determiningConfigurationType = false;
-        }
-    }
-
-    /**
-     * Made protected visibility for easy (informal) pluggability.
-     */
-    protected DeploymentTypeWicketAbstract determineDeploymentType(String deploymentTypeFromConfig) {
-        final DeploymentTypeWicketAbstract prototype = new WicketServerPrototype();
-        final DeploymentTypeWicketAbstract deployment = new WicketServer();
-
-        if(deploymentTypeFromConfig != null) {
-            final DeploymentType deploymentType = DeploymentType.lookup(deploymentTypeFromConfig);
-            return !deploymentType.getDeploymentCategory().isProduction()
-                    ? prototype
-                    : deployment;
-        } else {
-            return usesDevelopmentConfig()
-                    ? prototype
-                    : deployment;
-        }
-    }
-
-
-    // //////////////////////////////////////
-
-    private IsisConfigurationBuilder isisConfigurationBuilder;
-
-    protected IsisConfigurationBuilder obtainConfigBuilder() {
-        return isisConfigurationBuilder != null
-                    ? isisConfigurationBuilder
-                    : (isisConfigurationBuilder = IsisWebAppBootstrapper.obtainConfigBuilderFrom(getServletContext()));
-    }
-
-    // //////////////////////////////////////
-
-    /**
-     * Override if required
-     */
-    protected Module newIsisWicketModule() {
-        return new IsisWicketModule();
-    }
-
-    // //////////////////////////////////////
-
-    /**
-     * Made protected visibility for easy (informal) pluggability.
-     */
-    protected void buildCssBundle() {
-        // get the css for all components built by component factories
-        final Set<CssResourceReference> references = cssResourceReferencesForAllComponents();
-
-        // some additional special cases.
-        addSpecialCasesToCssBundle(references);
-
-        // create the bundle
-        getResourceBundles().addCssBundle(
-                IsisWicketApplication.class, "isis-wicket-viewer-bundle.css",
-                references.toArray(new CssResourceReference[]{}));
-    }
-
-    /**
-     * Additional special cases to be included in the main CSS bundle.
-     *
-     * <p>
-     * These are typically either superclasses or components that don't have their own ComponentFactory, or
-     * for {@link ComponentFactory}s (such as <tt>StringPanelFactory</tt>) that don't quite follow the usual pattern
-     * (because they create different types of panels).
-     *
-     * <p>
-     * Note that it doesn't really matter if we miss one or two; their CSS will simply be served up individually.
-     */
-    protected void addSpecialCasesToCssBundle(final Set<CssResourceReference> references) {
-
-        // abstract classes
-
-        // ... though it turns out we cannot add this particular one to the bundle, because
-        // it has CSS image links intended to be resolved relative to LinksSelectorPanelAbstract.class.
-        // Adding them into the bundle would mean these CSS links are resolved relative to IsisWicketApplication.class
-        // instead.
-        // references.add(PanelUtil.cssResourceReferenceFor(LinksSelectorPanelAbstract.class));
-
-        // components without factories
-        references.add(PanelUtil.cssResourceReferenceFor(AdditionalLinksPanel.class));
-
-        // non-conforming component factories
-        references.add(PanelUtil.cssResourceReferenceFor(MultiLineStringPanel.class));
-    }
-
-    protected final static Function<ComponentFactory, Iterable<CssResourceReference>> getCssResourceReferences =
-            new Function<ComponentFactory, Iterable<CssResourceReference>>(){
-                @Override
-                public Iterable<CssResourceReference> apply(final ComponentFactory input) {
-                    final CssResourceReference cssResourceReference = input.getCssResourceReference();
-                    return cssResourceReference != null?
-                            Collections.singletonList(cssResourceReference):
-                            Collections.<CssResourceReference>emptyList();
-                }
-            };
-
-
-    protected Set<CssResourceReference> cssResourceReferencesForAllComponents() {
-        // TODO mgrigorov: ISIS-537 temporary disabled to not mess up with Bootstrap styles
-//        Collection<ComponentFactory> componentFactories = getComponentFactoryRegistry().listComponentFactories();
-        return Sets.newLinkedHashSet(
-//                Iterables.concat(
-//                        Iterables.transform(
-//                                componentFactories,
-//                                getCssResourceReferences))
-        );
-    }
-
-    // //////////////////////////////////////
-
-    /**
-     * filters Javascript header contributions so rendered to bottom of page.
-     *
-     * <p>
-     * Factored out for easy (informal) pluggability.
-     * </p>
-     */
-    protected void filterJavascriptContributions() {
-        setHeaderResponseDecorator(new IHeaderResponseDecorator()
-        {
-            @Override
-            public IHeaderResponse decorate(IHeaderResponse response)
-            {
-                // use this header resource decorator to load all JavaScript resources in the page
-                // footer (after </body>)
-                return new JavaScriptFilteredIntoFooterHeaderResponse(response, "footerJS");
-            }
-        });
-    }
-
-    // //////////////////////////////////////
-
-    /**
-     * Map entity and action to provide prettier URLs.
-     *
-     * <p>
-     * Factored out for easy (informal) pluggability.
-     * </p>
-     */
-    protected void mountPages() {
-
-        mountPage("/signin", PageType.SIGN_IN);
-        mountPage("/signup", PageType.SIGN_UP);
-        mountPage("/signup/verify", PageType.SIGN_UP_VERIFY);
-        mountPage("/password/reset", PageType.PASSWORD_RESET);
-
-        mountPage("/entity/#{objectOid}", PageType.ENTITY);
-
-        // nb: action mount cannot contain {actionArgs}, because the default
-        // parameters encoder doesn't seem to be able to handle multiple args
-        mountPage("/action/${objectOid}/${actionOwningSpec}/${actionId}/${actionType}", PageType.ACTION_PROMPT);
-
-        mountPage("/logout", WicketLogoutPage.class);
-    }
-
-    protected void mountPage(final String mountPath, final PageType pageType) {
-        final Class<? extends Page> pageClass = this.pageClassRegistry.getPageClass(pageType);
-        mount(new MountedMapper(mountPath, pageClass));
-    }
-
-
-    // //////////////////////////////////////
-
-    private void logError(String validationError) {
-        log(validationError);
-    }
-
-    private static void logBanner() {
-        String msg = "################################################ ISIS METAMODEL VALIDATION ERRORS ################################################################";
-        log(msg);
-    }
-
-    private static void log(String msg) {
-        System.err.println(msg);
-        LOG.error(msg);
-    }
-
-    // //////////////////////////////////////
-
-    /**
-     * Whether Wicket tags should be stripped from the markup, as specified by configuration settings..
-     * 
-     * <p>
-     * If the <tt>isis.viewer.wicket.stripWicketTags</tt> is set, then this is used, otherwise the default is to strip 
-     * the tags because they may break some CSS rules.
-     */
-    private boolean determineStripWicketTags(IsisConfiguration configuration) {
-        final boolean strip = configuration.getBoolean(STRIP_WICKET_TAGS_KEY, STRIP_WICKET_TAGS_DEFAULT);
-        return strip;
-    }
-
-    // //////////////////////////////////////
-
-    /**
-     * Whether the Ajax debug should be shown, as specified by configuration settings.
-     *
-     * <p>
-     * If the <tt>isis.viewer.wicket.ajaxDebugMode</tt> is set, then this is used, otherwise the default is to disable.
-     */
-    private boolean determineAjaxDebugModeEnabled(IsisConfiguration configuration) {
-        final boolean debugModeEnabled = configuration.getBoolean(AJAX_DEBUG_MODE_KEY, AJAX_DEBUG_MODE_DEFAULT);
-        return debugModeEnabled;
-    }
-
-    /**
-     * Whether the Wicket source plugin should be enabled, as specified by configuration settings.
-     *
-     * <p>
-     * If the <tt>isis.viewer.wicket.wicketSourcePlugin</tt> is set, then this is used, otherwise the default is to disable.
-     */
-    private boolean isWicketSourcePluginEnabled(IsisConfiguration configuration) {
-        final boolean pluginEnabled = configuration.getBoolean(WICKET_SOURCE_PLUGIN_KEY, WICKET_SOURCE_PLUGIN_DEFAULT);
-        return pluginEnabled;
-    }
-
-    // //////////////////////////////////////
-
-    @Override
-    protected void onDestroy() {
-        try {
-            if (isisSessionFactory != null) {
-                isisSessionFactory.destroyServicesAndShutdown();
-            }
-            getServletContext().setAttribute(WebAppConstants.ISIS_SESSION_FACTORY, null);
-            super.onDestroy();
-            IsisContext.clear();
-        } catch(final RuntimeException ex) {
-            // symmetry with #init()
-            LOG.error("Failed to destroy", ex);
-            throw ex;
-        }
-    }
-
-    // //////////////////////////////////////
-
-    @Override
-    public RuntimeConfigurationType getConfigurationType() {
-        if(determiningConfigurationType) {
-            // avoiding an infinite loop; have already passed through here once before
-            // this time around, just delegate to web-inf
-            return super.getConfigurationType();
-        }
-        determineDeploymentTypeIfRequired();
-        return deploymentType.getConfigurationType();
-    }
-    
-    protected IsisInjectModule newIsisModule(
-            final DeploymentCategory deploymentCategory,
-            final IsisConfigurationDefault isisConfiguration) {
-        return new IsisInjectModule(deploymentCategory, isisConfiguration);
-    }
-
-    // //////////////////////////////////////
-
-
-    protected void initWicketComponentInjection(final Injector injector) {
-        getComponentInstantiationListeners().add(new GuiceComponentInjector(this, injector, false));
-    }
-
-    // /////////////////////////////////////////////////
-    // Wicket Hooks
-    // /////////////////////////////////////////////////
-
-    /**
-     * Installs a {@link AuthenticatedWebSessionForIsis custom implementation}
-     * of Wicket's own {@link AuthenticatedWebSession}, effectively associating
-     * the Wicket session with the Isis's equivalent session object.
-     *
-     * <p>
-     * In general, it shouldn't be necessary to override this method.
-     */
-    @Override
-    protected Class<? extends AuthenticatedWebSession> getWebSessionClass() {
-        return AuthenticatedWebSessionForIsis.class;
-    }
-
-    /**
-     * Installs a {@link ConverterLocator} preconfigured with a number of
-     * implementations to support Isis specific objects.
-     */
-    @Override
-    protected IConverterLocator newConverterLocator() {
-        final ConverterLocator converterLocator = new ConverterLocator();
-        converterLocator.set(ObjectAdapter.class, new ConverterForObjectAdapter());
-        converterLocator.set(ObjectAdapterMemento.class, new ConverterForObjectAdapterMemento());
-        return converterLocator;
-    }
-
-    // /////////////////////////////////////////////////
-    // Component Factories
-    // /////////////////////////////////////////////////
-
-    @Override
-    public final ComponentFactoryRegistry getComponentFactoryRegistry() {
-        return componentFactoryRegistry;
-    }
-
-    // /////////////////////////////////////////////////
-    // Page Registry
-    // /////////////////////////////////////////////////
-
-    /**
-     * Access to other page types.
-     *
-     * <p>
-     * Non-final only for testing purposes; should not typically be overridden.
-     */
-    @Override
-    public PageClassRegistry getPageClassRegistry() {
-        return pageClassRegistry;
-    }
-
-    /**
-     * Delegates to the {@link #getPageClassRegistry() PageClassRegistry}.
-     */
-    @Override
-    public Class<? extends Page> getHomePage() {
-        return getPageClassRegistry().getPageClass(PageType.HOME);
-    }
-
-    /**
-     * Delegates to the {@link #getPageClassRegistry() PageClassRegistry}.
-     */
-    @SuppressWarnings("unchecked")
-    @Override
-    public Class<? extends WebPage> getSignInPageClass() {
-        return (Class<? extends WebPage>) getPageClassRegistry().getPageClass(PageType.SIGN_IN);
-    }
-
-    /**
-     * Delegates to the {@link #getPageClassRegistry() PageClassRegistry}.
-     */
-    @SuppressWarnings("unchecked")
-    public Class<? extends WebPage> getSignUpPageClass() {
-        return (Class<? extends WebPage>) getPageClassRegistry().getPageClass(PageType.SIGN_UP);
-    }
-
-    /**
-     * Delegates to the {@link #getPageClassRegistry() PageClassRegistry}.
-     */
-    @SuppressWarnings("unchecked")
-    public Class<? extends WebPage> getSignUpVerifyPageClass() {
-        return (Class<? extends WebPage>) getPageClassRegistry().getPageClass(PageType.SIGN_UP_VERIFY);
-    }
-
-    /**
-     * Delegates to the {@link #getPageClassRegistry() PageClassRegistry}.
-     */
-    @SuppressWarnings("unchecked")
-    public Class<? extends WebPage> getForgotPasswordPageClass() {
-        return (Class<? extends WebPage>) getPageClassRegistry().getPageClass(PageType.PASSWORD_RESET);
-    }
-
-    public AuthenticationSession getAuthenticationSession() {
-        return isisSessionFactory.getCurrentSession().getAuthenticationSession();
-    }
-
-    public DeploymentCategory getDeploymentCategory() {
-        return deploymentCategory;
-    }
-
-    @Override
-    public WicketViewerSettings getSettings() {
-        return settings;
-    }
+extends AuthenticatedWebApplication
+implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, WicketViewerSettingsAccessor {
+
+	private static final long serialVersionUID = 1L;
+
+	private static final Logger LOG = LoggerFactory.getLogger(IsisWicketApplication.class);
+
+	private static final String STRIP_WICKET_TAGS_KEY = "isis.viewer.wicket.stripWicketTags";
+	private static final boolean STRIP_WICKET_TAGS_DEFAULT = true;
+	private static final String AJAX_DEBUG_MODE_KEY = "isis.viewer.wicket.ajaxDebugMode";
+	private static final boolean AJAX_DEBUG_MODE_DEFAULT = false;
+	private static final String WICKET_SOURCE_PLUGIN_KEY = "isis.viewer.wicket.wicketSourcePlugin";
+	private static final boolean WICKET_SOURCE_PLUGIN_DEFAULT = false;
+
+	private static final String WICKET_REMEMBER_ME_COOKIE_KEY = "isis.viewer.wicket.rememberMe.cookieKey";
+	private static final String WICKET_REMEMBER_ME_COOKIE_KEY_DEFAULT = "isisWicketRememberMe";
+	private static final String WICKET_REMEMBER_ME_ENCRYPTION_KEY = "isis.viewer.wicket.rememberMe.encryptionKey";
+
+	/**
+	 * A configuration setting which value determines whether debug bar and other stuff influenced by {@link DebugSettings#isDevelopmentUtilitiesEnabled()} is enabled or not.
+	 *
+	 * <p>
+	 *     By default, depends on the mode (prototyping = enabled, server = disabled).  This property acts as an override.
+	 * </p>
+	 */
+	public static final String ENABLE_DEVELOPMENT_UTILITIES_KEY = "isis.viewer.wicket.developmentUtilities.enable";
+	public static final boolean ENABLE_DEVELOPMENT_UTILITIES_DEFAULT = false;
+
+
+
+	private final IsisLoggingConfigurer loggingConfigurer = new IsisLoggingConfigurer();
+
+	/**
+	 * Convenience locator, downcasts inherited functionality.
+	 */
+	public static IsisWicketApplication get() {
+		return (IsisWicketApplication) AuthenticatedWebApplication.get();
+	}
+
+	/**
+	 * {@link com.google.inject.Inject Inject}ed when {@link #init() initialized}.
+	 */
+	@com.google.inject.Inject
+	private ComponentFactoryRegistry componentFactoryRegistry;
+
+	/**
+	 * {@link com.google.inject.Inject Inject}ed when {@link #init() initialized}.
+	 */
+	@SuppressWarnings("unused")
+	@com.google.inject.Inject
+	private ImageResourceCache imageCache;
+
+	/**
+	 * {@link com.google.inject.Inject Inject}ed when {@link #init() initialized}.
+	 */
+	@SuppressWarnings("unused")
+	@com.google.inject.Inject
+	private WicketViewerSettings wicketViewerSettings;
+
+	/**
+	 * {@link com.google.inject.Inject Inject}ed when {@link #init() initialized}.
+	 */
+	@com.google.inject.Inject
+	private PageClassRegistry pageClassRegistry;
+
+	/**
+	 * {@link com.google.inject.Inject Inject}ed when {@link #init() initialized}.
+	 */
+	@com.google.inject.Inject
+	private IsisSessionFactory isisSessionFactory;
+
+	/**
+	 * {@link com.google.inject.Inject Inject}ed when {@link #init() initialized}.
+	 */
+	@com.google.inject.Inject
+	private IsisConfiguration configuration;
+
+	/**
+	 * {@link com.google.inject.Inject Inject}ed when {@link #init() initialized}.
+	 */
+	@com.google.inject.Inject
+	private DeploymentCategory deploymentCategory;
+
+	@com.google.inject.Inject
+	private WicketViewerSettings settings;
+
+
+	private boolean determiningConfigurationType;
+	private DeploymentTypeWicketAbstract deploymentType;
+
+
+	// /////////////////////////////////////////////////
+	// constructor, init
+	// /////////////////////////////////////////////////
+
+	public IsisWicketApplication() {
+	}
+
+
+	/**
+	 * Although there are warnings about not overriding this method, it doesn't seem possible
+	 * to call {@link #setResourceSettings(org.apache.wicket.settings.ResourceSettings)} in the
+	 * {@link #init()} method.
+	 */
+	@Override
+	protected void internalInit() {
+		// replace with custom implementation of ResourceSettings that changes the order
+		// in which search for i18n properties, to search for the application-specific
+		// settings before any other.
+		setResourceSettings(new IsisResourceSettings(this));
+
+		// this doesn't seem to accomplish anything
+		// addListenerToStripRemovedComponentsFromAjaxTargetResponse();
+
+		super.internalInit();
+
+	}
+
+	private static AjaxRequestTarget decorate(final AjaxRequestTarget ajaxRequestTarget) {
+		ajaxRequestTarget.registerRespondListener( new TargetRespondListenerToResetQueryResultCache() );
+		return ajaxRequestTarget;
+	}
+
+	
+	@Override
+	public Application setAjaxRequestTargetProvider(Function<Page, AjaxRequestTarget> ajaxRequestTargetProvider) {
+		final Application application = super.setAjaxRequestTargetProvider(
+				(Page context) -> decorate(ajaxRequestTargetProvider.apply(context)) );
+		return application;
+	}
+
+	// idea here is to avoid XmlPartialPageUpdate spitting out warnings, eg:
+	//
+	// 13:08:36,642  [XmlPartialPageUpdate qtp1988859660-18 WARN ]  Component '[AjaxLink [Component id = copyLink]]' with markupid: 'copyLink94c' not rendered because it was already removed from page
+	//  13:08:36,642  [XmlPartialPageUpdate qtp1988859660-18 WARN ]  Component '[SimpleClipboardModalWindow [Component id = simpleClipboardModalWindow]]' with markupid: 'simpleClipboardModalWindow94e' not rendered because it was already removed from page
+	// 13:08:36,643  [XmlPartialPageUpdate qtp1988859660-18 WARN ]  Component '[AjaxFallbackLink [Component id = link]]' with markupid: 'link951' not rendered because it was already removed from page
+	// 13:08:36,643  [XmlPartialPageUpdate qtp1988859660-18 WARN ]  Component '[AjaxFallbackLink [Component id = link]]' with markupid: 'link952' not rendered because it was already removed from page
+	// 13:08:36,655  [XmlPartialPageUpdate qtp1988859660-18 WARN ]  Component '[AjaxLink [Component id = clearBookmarkLink]]' with markupid: 'clearBookmarkLink953' not rendered because it was already removed from page
+	//
+	// however, doesn't seem to work (even though the provided map is mutable).
+	// must be some other sort of side-effect which causes the enqueued component(s) to be removed from page between
+	// this listener firing and XmlPartialPageUpdate actually attempting to render the change components
+	//
+	private boolean addListenerToStripRemovedComponentsFromAjaxTargetResponse() {
+		return getAjaxRequestTargetListeners().add(new IListener(){
+
+			@Override
+			public void onBeforeRespond(Map<String, Component> map, AjaxRequestTarget target) {
+
+				System.out.println("=====================================");
+				System.out.println("=== on before respond");
+				System.out.println("map="+map);
+				System.out.println("=====================================");
+				System.out.println("=== removals");
+				map.entrySet().removeIf(entry->{
+					final Component component = entry.getValue();
+					final Page page = component.findParent(Page.class);
+					if(page==null) {
+						System.out.println("id: "+entry.getKey()+": page="+page);
+					}
+					return page==null;
+				});
+
+				System.out.println("=====================================");
+
+			}
+		});
+	}
+
+	/**
+	 * Initializes the application; in particular, bootstrapping the Isis
+	 * backend, and initializing the {@link ComponentFactoryRegistry} to be used
+	 * for rendering.
+	 */
+	@Override
+	protected void init() {
+		List<Future<Object>> futures = null;
+		try {
+			super.init();
+
+			_Context.setDefaultClassLoader(this.getClass().getClassLoader(), true);
+
+			futures = startBackgroundInitializationThreads();
+
+			String isisConfigDir = getServletContext().getInitParameter("isis.config.dir");
+
+			configureLogging(isisConfigDir);
+
+			getRequestCycleSettings().setRenderStrategy(RequestCycleSettings.RenderStrategy.REDIRECT_TO_RENDER);
+
+			getResourceSettings().setParentFolderPlaceholder("$up$");
+
+			final IsisConfigurationBuilder isisConfigurationBuilder = obtainConfigBuilder();
+			isisConfigurationBuilder.addDefaultConfigurationResourcesAndPrimers();
+
+			_Resource.putContextPathIfPresent(getServletContext().getContextPath());
+
+			final IsisConfigurationDefault configuration = isisConfigurationBuilder.getConfiguration();
+
+			DeploymentTypeWicketAbstract deploymentType =
+					determineDeploymentType(configuration.getString("isis.deploymentType"));
+
+			RequestCycleListenerCollection requestCycleListeners = getRequestCycleListeners();
+			IRequestCycleListener requestCycleListenerForIsis = newWebRequestCycleForIsis();
+			requestCycleListeners.add(requestCycleListenerForIsis);
+			requestCycleListeners.add(new PageRequestHandlerTracker());
+
+			//
+			// create IsisSessionFactory
+			//
+			final DeploymentCategory deploymentCategory = deploymentType.getDeploymentCategory();
+			final IsisInjectModule isisModule = newIsisModule(deploymentCategory, configuration);
+			final Injector injector = Guice.createInjector(isisModule, newIsisWicketModule());
+			initWicketComponentInjection(injector);
+
+			injector.injectMembers(this); // populates this.isisSessionFactory
+
+			getServletContext().setAttribute(WebAppConstants.ISIS_SESSION_FACTORY, this.isisSessionFactory);
+
+
+			if (requestCycleListenerForIsis instanceof WebRequestCycleForIsis) {
+				WebRequestCycleForIsis webRequestCycleForIsis = (WebRequestCycleForIsis) requestCycleListenerForIsis;
+				webRequestCycleForIsis.setPageClassRegistry(pageClassRegistry);
+			}
+
+			this.getMarkupSettings().setStripWicketTags(determineStripWicketTags(configuration));
+
+			configureSecurity(configuration);
+
+			getDebugSettings().setAjaxDebugModeEnabled(determineAjaxDebugModeEnabled(configuration));
+
+			// must be done after injected componentFactoryRegistry into the app itself
+			buildCssBundle();
+
+			filterJavascriptContributions();
+
+			configureWicketSourcePluginIfNecessary();
+
+			// TODO ISIS-987 Either make the API better (no direct access to the map) or use DB records
+			int maxEntries = 1000;
+			setMetaData(AccountConfirmationMap.KEY, new AccountConfirmationMap(maxEntries, Duration.days(1)));
+
+			mountPages();
+
+			@SuppressWarnings("unused")
+			SharedResources sharedResources = getSharedResources();
+
+			final MetaModelInvalidException mmie = IsisContext.getMetaModelInvalidExceptionIfAny();
+			if(mmie != null) {
+				log(mmie.getValidationErrors());
+			}
+
+			if(getDeploymentCategory().isPrototyping()) {
+				DebugDiskDataStore.register(this);
+				LOG.info("DebugDiskDataStore registered; access via ~/wicket/internal/debug/diskDataStore");
+				LOG.info("DebugDiskDataStore: eg, http://localhost:8080/wicket/wicket/internal/debug/diskDataStore");
+			}
+
+			if(!getDebugSettings().isDevelopmentUtilitiesEnabled()) {
+				boolean enableDevUtils = configuration
+						.getBoolean(ENABLE_DEVELOPMENT_UTILITIES_KEY, ENABLE_DEVELOPMENT_UTILITIES_DEFAULT);
+				if(enableDevUtils) {
+					getDebugSettings().setDevelopmentUtilitiesEnabled(true);
+
+					// copied from DebugBarInitializer
+					// this is hacky, but need to do this because IInitializer#init() called before
+					// the Application's #init() is called.
+					// an alternative, better, design might be to move Isis' own initialization into an
+					// implementation of IInitializer?
+					DebugBar.registerContributor(VersionDebugContributor.DEBUG_BAR_CONTRIB, this);
+					DebugBar.registerContributor(InspectorDebugPanel.DEBUG_BAR_CONTRIB, this);
+					DebugBar.registerContributor(SessionSizeDebugPanel.DEBUG_BAR_CONTRIB, this);
+					DebugBar.registerContributor(PageSizeDebugPanel.DEBUG_BAR_CONTRIB, this);
+				}
+			}
+
+			LOG.info("storeSettings.inmemoryCacheSize        : {}", getStoreSettings().getInmemoryCacheSize());
+			LOG.info("storeSettings.asynchronousQueueCapacity: {}", getStoreSettings().getAsynchronousQueueCapacity());
+			LOG.info("storeSettings.maxSizePerSession        : {}", getStoreSettings().getMaxSizePerSession());
+			LOG.info("storeSettings.fileStoreFolder          : {}", getStoreSettings().getFileStoreFolder());
+
+		} catch(RuntimeException ex) {
+			// because Wicket's handling in its WicketFilter (that calls this method) does not log the exception.
+			LOG.error("Failed to initialize", ex);
+			throw ex;
+		} finally {
+			ThreadPoolSupport.join(futures);
+		}
+	}
+
+	protected List<Future<Object>> startBackgroundInitializationThreads() {
+		return ThreadPoolSupport.getInstance().invokeAll(_Lists.<Callable<Object>>of(
+
+				Executors.callable(this::configureWebJars),
+				Executors.callable(this::configureWicketBootstrap),
+				Executors.callable(this::configureWicketSelect2),
+				Executors.callable(ChangesDtoUtils::init),
+				Executors.callable(InteractionDtoUtils::init),
+				Executors.callable(CommandDtoUtils::init)
+				));
+	}
+
+	/**
+	 * protected visibility to allow ad-hoc overriding of some other authentication strategy.
+	 */
+	protected void configureSecurity(final IsisConfiguration configuration) {
+		getSecuritySettings().setAuthenticationStrategy(newAuthenticationStrategy(configuration));
+	}
+
+	/**
+	 * protected visibility to allow ad-hoc overriding of some other authentication strategy.
+	 */
+	protected IAuthenticationStrategy newAuthenticationStrategy(final IsisConfiguration configuration) {
+		final String cookieKey = configuration.getString(WICKET_REMEMBER_ME_COOKIE_KEY,
+				WICKET_REMEMBER_ME_COOKIE_KEY_DEFAULT);
+		final String encryptionKey = configuration.getString(WICKET_REMEMBER_ME_ENCRYPTION_KEY, defaultEncryptionKeyIfNotConfigured());
+		return new DefaultAuthenticationStrategy(cookieKey, encryptionKey);
+	}
+
+	/**
+	 * As called by {@link #newAuthenticationStrategy(IsisConfiguration)}; if an encryption key for the 'rememberMe'
+	 * cookie hasn't been configured, then use a different encryption key for the 'rememberMe' cookie each time the
+	 * app is restarted.
+	 */
+	protected String defaultEncryptionKeyIfNotConfigured() {
+		return getDeploymentCategory().isProduction()
+				? UUID.randomUUID().toString()
+						: "PrototypingEncryptionKey";
+	}
+
+	private void log(final Set<String> validationErrors) {
+		log("");
+		logBanner();
+		log("");
+		for (String validationError : validationErrors) {
+			logError(validationError);
+		}
+		log("");
+		log("Please inspect the above messages and correct your domain model.");
+		log("");
+		logBanner();
+		log("");
+	}
+
+	private void configureWicketSelect2() {
+		ApplicationSettings select2Settings = ApplicationSettings.get();
+		select2Settings.setCssReference(new Select2BootstrapCssReference());
+		select2Settings.setJavaScriptReference(new Select2JsReference());
+	}
+
+	protected void configureWicketSourcePluginIfNecessary() {
+		if(isWicketSourcePluginEnabled(this.configuration)) {
+			configureWicketSourcePlugin();
+		}
+	}
+
+	protected void configureWicketSourcePlugin() {
+		if(!deploymentCategory.isProduction()) {
+			WicketSource.configure(this);
+		}
+	}
+
+	/**
+	 * For convenience of subclasses.
+	 */
+	protected static String readLines(final Class<?> contextClass, final String resourceName, final String fallback) {
+		try {
+			List<String> readLines = Resources.readLines(Resources.getResource(contextClass, resourceName), Charset.defaultCharset());
+			final String aboutText = Joiner.on("\n").join(readLines);
+			return aboutText;
+		} catch (IOException e) {
+			return fallback;
+		}
+	}
+
+
+	// //////////////////////////////////////
+
+	/**
+	 * Install 2 default collector instances: (FileAssetPathCollector(WEBJARS_PATH_PREFIX), JarAssetPathCollector),
+	 * and a webjars resource finder.
+	 *
+	 * <p>
+	 * Factored out for easy (informal) pluggability.
+	 * </p>
+	 */
+	protected void configureWebJars() {
+		IWebjarsSettings settings = new WebjarsSettings();
+		WicketWebjars.install(this, settings);
+	}
+
+	protected void configureWicketBootstrap() {
+		final IBootstrapSettings settings = new BootstrapSettings();
+		settings.setDeferJavascript(false);
+		Bootstrap.install(this, settings);
+
+		getHeaderContributorListeners().add(new IHeaderContributor() {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void renderHead(IHeaderResponse response) {
+				BootstrapBaseBehavior bootstrapBaseBehavior = new BootstrapBaseBehavior();
+				bootstrapBaseBehavior.renderHead(settings, response);
+			}
+		});
+	}
+
+	// //////////////////////////////////////
+
+	/**
+	 * Factored out for easy (informal) pluggability.
+	 */
+	protected void configureLogging(String isisConfigDir) {
+		final String loggingPropertiesDir;
+		if(isisConfigDir != null) {
+			loggingPropertiesDir = isisConfigDir;
+		} else {
+			loggingPropertiesDir = getServletContext().getRealPath("/WEB-INF");
+		}
+
+		loggingConfigurer.configureLogging(loggingPropertiesDir, new String[0]);
+	}
+
+	// //////////////////////////////////////
+
+	/**
+	 * Factored out for easy (informal) pluggability.
+	 */
+	protected IRequestCycleListener newWebRequestCycleForIsis() {
+		return new WebRequestCycleForIsis();
+	}
+
+	// //////////////////////////////////////
+
+	/**
+	 * Made protected visibility for easy (informal) pluggability.
+	 */
+	protected void determineDeploymentTypeIfRequired() {
+		if(deploymentType != null) {
+			return;
+		}
+
+		determiningConfigurationType = true;
+		try {
+			final IsisConfigurationBuilder isisConfigurationBuilder = obtainConfigBuilder();
+
+			final IsisConfiguration configuration = isisConfigurationBuilder.peekConfiguration();
+			String deploymentTypeFromConfig = configuration.getString("isis.deploymentType");
+			deploymentType = determineDeploymentType(deploymentTypeFromConfig);
+		} finally {
+			determiningConfigurationType = false;
+		}
+	}
+
+	/**
+	 * Made protected visibility for easy (informal) pluggability.
+	 */
+	protected DeploymentTypeWicketAbstract determineDeploymentType(String deploymentTypeFromConfig) {
+		final DeploymentTypeWicketAbstract prototype = new WicketServerPrototype();
+		final DeploymentTypeWicketAbstract deployment = new WicketServer();
+
+		if(deploymentTypeFromConfig != null) {
+			final DeploymentType deploymentType = DeploymentType.lookup(deploymentTypeFromConfig);
+			return !deploymentType.getDeploymentCategory().isProduction()
+					? prototype
+							: deployment;
+		} else {
+			return usesDevelopmentConfig()
+					? prototype
+							: deployment;
+		}
+	}
+
+
+	// //////////////////////////////////////
+
+	private IsisConfigurationBuilder isisConfigurationBuilder;
+
+	protected IsisConfigurationBuilder obtainConfigBuilder() {
+		return isisConfigurationBuilder != null
+				? isisConfigurationBuilder
+						: (isisConfigurationBuilder = IsisWebAppBootstrapper.obtainConfigBuilderFrom(getServletContext()));
+	}
+
+	// //////////////////////////////////////
+
+	/**
+	 * Override if required
+	 */
+	protected Module newIsisWicketModule() {
+		return new IsisWicketModule();
+	}
+
+	// //////////////////////////////////////
+
+	/**
+	 * Made protected visibility for easy (informal) pluggability.
+	 */
+	protected void buildCssBundle() {
+		// get the css for all components built by component factories
+		final Set<CssResourceReference> references = cssResourceReferencesForAllComponents();
+
+		// some additional special cases.
+		addSpecialCasesToCssBundle(references);
+
+		// create the bundle
+		getResourceBundles().addCssBundle(
+				IsisWicketApplication.class, "isis-wicket-viewer-bundle.css",
+				references.toArray(new CssResourceReference[]{}));
+	}
+
+	/**
+	 * Additional special cases to be included in the main CSS bundle.
+	 *
+	 * <p>
+	 * These are typically either superclasses or components that don't have their own ComponentFactory, or
+	 * for {@link ComponentFactory}s (such as <tt>StringPanelFactory</tt>) that don't quite follow the usual pattern
+	 * (because they create different types of panels).
+	 *
+	 * <p>
+	 * Note that it doesn't really matter if we miss one or two; their CSS will simply be served up individually.
+	 */
+	protected void addSpecialCasesToCssBundle(final Set<CssResourceReference> references) {
+
+		// abstract classes
+
+		// ... though it turns out we cannot add this particular one to the bundle, because
+		// it has CSS image links intended to be resolved relative to LinksSelectorPanelAbstract.class.
+		// Adding them into the bundle would mean these CSS links are resolved relative to IsisWicketApplication.class
+		// instead.
+		// references.add(PanelUtil.cssResourceReferenceFor(LinksSelectorPanelAbstract.class));
+
+		// components without factories
+		references.add(PanelUtil.cssResourceReferenceFor(AdditionalLinksPanel.class));
+
+		// non-conforming component factories
+		references.add(PanelUtil.cssResourceReferenceFor(MultiLineStringPanel.class));
+	}
+
+	protected final static Function<ComponentFactory, Iterable<CssResourceReference>> getCssResourceReferences =
+			(ComponentFactory input) -> {
+				final CssResourceReference cssResourceReference = input.getCssResourceReference();
+				return cssResourceReference != null?
+						Collections.singletonList(cssResourceReference):
+							Collections.<CssResourceReference>emptyList();
+			};
+
+
+	protected Set<CssResourceReference> cssResourceReferencesForAllComponents() {
+		// TODO mgrigorov: ISIS-537 temporary disabled to not mess up with Bootstrap styles
+		//        Collection<ComponentFactory> componentFactories = getComponentFactoryRegistry().listComponentFactories();
+		return Sets.newLinkedHashSet(
+				//                Iterables.concat(
+				//                        Iterables.transform(
+				//                                componentFactories,
+				//                                getCssResourceReferences))
+				);
+	}
+
+	// //////////////////////////////////////
+
+	/**
+	 * filters Javascript header contributions so rendered to bottom of page.
+	 *
+	 * <p>
+	 * Factored out for easy (informal) pluggability.
+	 * </p>
+	 */
+	protected void filterJavascriptContributions() {
+		
+		setHeaderResponseDecorator(response -> {
+            return new ResourceAggregator(new JavaScriptFilteredIntoFooterHeaderResponse(response, "footerJS"));
+		});
+		
+		//[ahuber] no longer supported since wicket 8
+//		setHeaderResponseDecorator(new IHeaderResponseDecorator()
+//		{
+//			@Override
+//			public IHeaderResponse decorate(IHeaderResponse response)
+//			{
+//				// use this header resource decorator to load all JavaScript resources in the page
+//				// footer (after </body>)
+//				return new JavaScriptFilteredIntoFooterHeaderResponse(response, "footerJS");
+//			}
+//		});
+	}
+
+	// //////////////////////////////////////
+
+	/**
+	 * Map entity and action to provide prettier URLs.
+	 *
+	 * <p>
+	 * Factored out for easy (informal) pluggability.
+	 * </p>
+	 */
+	protected void mountPages() {
+
+		mountPage("/signin", PageType.SIGN_IN);
+		mountPage("/signup", PageType.SIGN_UP);
+		mountPage("/signup/verify", PageType.SIGN_UP_VERIFY);
+		mountPage("/password/reset", PageType.PASSWORD_RESET);
+
+		mountPage("/entity/#{objectOid}", PageType.ENTITY);
+
+		// nb: action mount cannot contain {actionArgs}, because the default
+		// parameters encoder doesn't seem to be able to handle multiple args
+		mountPage("/action/${objectOid}/${actionOwningSpec}/${actionId}/${actionType}", PageType.ACTION_PROMPT);
+
+		mountPage("/logout", WicketLogoutPage.class);
+	}
+
+	protected void mountPage(final String mountPath, final PageType pageType) {
+		final Class<? extends Page> pageClass = this.pageClassRegistry.getPageClass(pageType);
+		mount(new MountedMapper(mountPath, pageClass));
+	}
+
+
+	// //////////////////////////////////////
+
+	private void logError(String validationError) {
+		log(validationError);
+	}
+
+	private static void logBanner() {
+		String msg = "################################################ ISIS METAMODEL VALIDATION ERRORS ################################################################";
+		log(msg);
+	}
+
+	private static void log(String msg) {
+		System.err.println(msg);
+		LOG.error(msg);
+	}
+
+	// //////////////////////////////////////
+
+	/**
+	 * Whether Wicket tags should be stripped from the markup, as specified by configuration settings..
+	 * 
+	 * <p>
+	 * If the <tt>isis.viewer.wicket.stripWicketTags</tt> is set, then this is used, otherwise the default is to strip 
+	 * the tags because they may break some CSS rules.
+	 */
+	private boolean determineStripWicketTags(IsisConfiguration configuration) {
+		final boolean strip = configuration.getBoolean(STRIP_WICKET_TAGS_KEY, STRIP_WICKET_TAGS_DEFAULT);
+		return strip;
+	}
+
+	// //////////////////////////////////////
+
+	/**
+	 * Whether the Ajax debug should be shown, as specified by configuration settings.
+	 *
+	 * <p>
+	 * If the <tt>isis.viewer.wicket.ajaxDebugMode</tt> is set, then this is used, otherwise the default is to disable.
+	 */
+	private boolean determineAjaxDebugModeEnabled(IsisConfiguration configuration) {
+		final boolean debugModeEnabled = configuration.getBoolean(AJAX_DEBUG_MODE_KEY, AJAX_DEBUG_MODE_DEFAULT);
+		return debugModeEnabled;
+	}
+
+	/**
+	 * Whether the Wicket source plugin should be enabled, as specified by configuration settings.
+	 *
+	 * <p>
+	 * If the <tt>isis.viewer.wicket.wicketSourcePlugin</tt> is set, then this is used, otherwise the default is to disable.
+	 */
+	private boolean isWicketSourcePluginEnabled(IsisConfiguration configuration) {
+		final boolean pluginEnabled = configuration.getBoolean(WICKET_SOURCE_PLUGIN_KEY, WICKET_SOURCE_PLUGIN_DEFAULT);
+		return pluginEnabled;
+	}
+
+	// //////////////////////////////////////
+
+	@Override
+	protected void onDestroy() {
+		try {
+			if (isisSessionFactory != null) {
+				isisSessionFactory.destroyServicesAndShutdown();
+			}
+			getServletContext().setAttribute(WebAppConstants.ISIS_SESSION_FACTORY, null);
+			super.onDestroy();
+			IsisContext.clear();
+		} catch(final RuntimeException ex) {
+			// symmetry with #init()
+			LOG.error("Failed to destroy", ex);
+			throw ex;
+		}
+	}
+
+	// //////////////////////////////////////
+
+	@Override
+	public RuntimeConfigurationType getConfigurationType() {
+		if(determiningConfigurationType) {
+			// avoiding an infinite loop; have already passed through here once before
+			// this time around, just delegate to web-inf
+			return super.getConfigurationType();
+		}
+		determineDeploymentTypeIfRequired();
+		return deploymentType.getConfigurationType();
+	}
+
+	protected IsisInjectModule newIsisModule(
+			final DeploymentCategory deploymentCategory,
+			final IsisConfigurationDefault isisConfiguration) {
+		return new IsisInjectModule(deploymentCategory, isisConfiguration);
+	}
+
+	// //////////////////////////////////////
+
+
+	protected void initWicketComponentInjection(final Injector injector) {
+		getComponentInstantiationListeners().add(new GuiceComponentInjector(this, injector, false));
+	}
+
+	// /////////////////////////////////////////////////
+	// Wicket Hooks
+	// /////////////////////////////////////////////////
+
+	/**
+	 * Installs a {@link AuthenticatedWebSessionForIsis custom implementation}
+	 * of Wicket's own {@link AuthenticatedWebSession}, effectively associating
+	 * the Wicket session with the Isis's equivalent session object.
+	 *
+	 * <p>
+	 * In general, it shouldn't be necessary to override this method.
+	 */
+	@Override
+	protected Class<? extends AuthenticatedWebSession> getWebSessionClass() {
+		return AuthenticatedWebSessionForIsis.class;
+	}
+
+	/**
+	 * Installs a {@link ConverterLocator} preconfigured with a number of
+	 * implementations to support Isis specific objects.
+	 */
+	@Override
+	protected IConverterLocator newConverterLocator() {
+		final ConverterLocator converterLocator = new ConverterLocator();
+		converterLocator.set(ObjectAdapter.class, new ConverterForObjectAdapter());
+		converterLocator.set(ObjectAdapterMemento.class, new ConverterForObjectAdapterMemento());
+		return converterLocator;
+	}
+
+	// /////////////////////////////////////////////////
+	// Component Factories
+	// /////////////////////////////////////////////////
+
+	@Override
+	public final ComponentFactoryRegistry getComponentFactoryRegistry() {
+		return componentFactoryRegistry;
+	}
+
+	// /////////////////////////////////////////////////
+	// Page Registry
+	// /////////////////////////////////////////////////
+
+	/**
+	 * Access to other page types.
+	 *
+	 * <p>
+	 * Non-final only for testing purposes; should not typically be overridden.
+	 */
+	@Override
+	public PageClassRegistry getPageClassRegistry() {
+		return pageClassRegistry;
+	}
+
+	/**
+	 * Delegates to the {@link #getPageClassRegistry() PageClassRegistry}.
+	 */
+	@Override
+	public Class<? extends Page> getHomePage() {
+		return getPageClassRegistry().getPageClass(PageType.HOME);
+	}
+
+	/**
+	 * Delegates to the {@link #getPageClassRegistry() PageClassRegistry}.
+	 */
+	@SuppressWarnings("unchecked")
+	@Override
+	public Class<? extends WebPage> getSignInPageClass() {
+		return (Class<? extends WebPage>) getPageClassRegistry().getPageClass(PageType.SIGN_IN);
+	}
+
+	/**
+	 * Delegates to the {@link #getPageClassRegistry() PageClassRegistry}.
+	 */
+	@SuppressWarnings("unchecked")
+	public Class<? extends WebPage> getSignUpPageClass() {
+		return (Class<? extends WebPage>) getPageClassRegistry().getPageClass(PageType.SIGN_UP);
+	}
+
+	/**
+	 * Delegates to the {@link #getPageClassRegistry() PageClassRegistry}.
+	 */
+	@SuppressWarnings("unchecked")
+	public Class<? extends WebPage> getSignUpVerifyPageClass() {
+		return (Class<? extends WebPage>) getPageClassRegistry().getPageClass(PageType.SIGN_UP_VERIFY);
+	}
+
+	/**
+	 * Delegates to the {@link #getPageClassRegistry() PageClassRegistry}.
+	 */
+	@SuppressWarnings("unchecked")
+	public Class<? extends WebPage> getForgotPasswordPageClass() {
+		return (Class<? extends WebPage>) getPageClassRegistry().getPageClass(PageType.PASSWORD_RESET);
+	}
+
+	public AuthenticationSession getAuthenticationSession() {
+		return isisSessionFactory.getCurrentSession().getAuthenticationSession();
+	}
+
+	public DeploymentCategory getDeploymentCategory() {
+		return deploymentCategory;
+	}
+
+	@Override
+	public WicketViewerSettings getSettings() {
+		return settings;
+	}
 
 }
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseHandlingStrategy.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseHandlingStrategy.java
index c3f91ce..34e9ed0 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseHandlingStrategy.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseHandlingStrategy.java
@@ -64,7 +64,7 @@ public enum ActionResultResponseHandlingStrategy {
                 final ActionResultResponse resultResponse,
                 final IsisSessionFactory isisSessionFactory) {
             final RequestCycle requestCycle = RequestCycle.get();
-            AjaxRequestTarget target = requestCycle.find(AjaxRequestTarget.class);
+            AjaxRequestTarget target = requestCycle.find(AjaxRequestTarget.class).orElse(null);
 
             if (target == null) {
                 // non-Ajax request => just stream the Lob to the browser
@@ -134,8 +134,9 @@ public enum ActionResultResponseHandlingStrategy {
      * an Ajax request.
      */
     private static class StreamAfterAjaxResponseBehavior extends AbstractAjaxBehavior {
-
-        private final String fileName;
+		private static final long serialVersionUID = 1L;
+		
+		private final String fileName;
         private final IResourceStream resourceStream;
         private final Duration cacheDuration;
 
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/serviceactions/TertiaryActionsPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/serviceactions/TertiaryActionsPanel.java
index 88d2090..17b5e5b 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/serviceactions/TertiaryActionsPanel.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/serviceactions/TertiaryActionsPanel.java
@@ -20,8 +20,8 @@ package org.apache.isis.viewer.wicket.ui.components.actionmenu.serviceactions;
 
 import java.util.List;
 
-import com.google.common.collect.Lists;
-
+import org.apache.isis.viewer.wicket.model.models.PageType;
+import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistry;
 import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.Page;
 import org.apache.wicket.markup.head.CssHeaderItem;
@@ -33,8 +33,7 @@ import org.apache.wicket.markup.html.list.ListView;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.request.resource.CssResourceReference;
 
-import org.apache.isis.viewer.wicket.model.models.PageType;
-import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistry;
+import com.google.common.collect.Lists;
 
 /**
  * A panel responsible to render the application actions as menu in a navigation bar.
@@ -46,12 +45,16 @@ import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistry;
  */
 public class TertiaryActionsPanel extends Panel {
 
-    public TertiaryActionsPanel(String id, List<CssMenuItem> menuItems) {
+	private static final long serialVersionUID = 1L;
+
+	public TertiaryActionsPanel(String id, List<CssMenuItem> menuItems) {
         super(id);
         addLogoutLink(this);
         final List<CssMenuItem> subMenuItems = flatten(menuItems);
         final ListView<CssMenuItem> subMenuItemsView = new ListView<CssMenuItem>("subMenuItems", subMenuItems) {
-            @Override
+			private static final long serialVersionUID = 1L;
+
+			@Override
             protected void populateItem(ListItem<CssMenuItem> listItem) {
                 CssMenuItem subMenuItem = listItem.getModelObject();
                 if (subMenuItem.hasSubMenuItems()) {
@@ -63,7 +66,9 @@ public class TertiaryActionsPanel extends Panel {
         };
 
         WebComponent divider = new WebComponent("divider") {
-            @Override
+			private static final long serialVersionUID = 1L;
+
+			@Override
             protected void onConfigure() {
                 super.onConfigure();
 
@@ -84,13 +89,16 @@ public class TertiaryActionsPanel extends Panel {
     }
 
     private void addLogoutLink(MarkupContainer themeDiv) {
-        Link logoutLink = new Link("logoutLink") {
+        Link<Void> logoutLink = new Link<Void>("logoutLink") {
+
+			private static final long serialVersionUID = 1L;
 
-            @Override
+			@Override
             public void onClick() {
                 getSession().invalidate();
                 setResponsePage(getSignInPage());
             }
+
         };
         themeDiv.add(logoutLink);
     }
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackHeadersToolbar.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackHeadersToolbar.java
index 425a6da..6892cff 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackHeadersToolbar.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackHeadersToolbar.java
@@ -16,15 +16,14 @@
  */
 package org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
 
-import org.apache.wicket.ajax.attributes.IAjaxCallListener;
+import org.apache.isis.commons.internal.base._Casts;
+import org.apache.isis.viewer.wicket.model.hints.UiHintContainer;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackHeadersToolbar;
 import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortStateLocator;
 import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 
-import org.apache.isis.viewer.wicket.model.hints.UiHintContainer;
-import org.apache.isis.viewer.wicket.model.models.EntityModel;
-
 /**
  * Adapted from Wicket's own {@link AjaxFallbackHeadersToolbar}.
  */
@@ -38,7 +37,7 @@ public class IsisAjaxFallbackHeadersToolbar<S> extends IsisAjaxHeadersToolbar<S>
             final IsisAjaxFallbackDataTable<?, S> table,
             final CollectionContentsSortableDataProvider stateLocator)
     {
-        super(table, (ISortStateLocator<S>)stateLocator);
+        super(table, _Casts.uncheckedCast(stateLocator));
         this.table = table;
         table.setOutputMarkupId(true);
         this.stateLocator = stateLocator;
@@ -55,18 +54,18 @@ public class IsisAjaxFallbackHeadersToolbar<S> extends IsisAjaxHeadersToolbar<S>
     protected WebMarkupContainer newSortableHeader(final String borderId, final S property,
         final ISortStateLocator<S> locator)
     {
-        return new IsisAjaxFallbackOrderByBorder<S>(borderId, table, property, locator, getAjaxCallListener());
+        return new IsisAjaxFallbackOrderByBorder<S>(borderId, table, property, locator/*, getAjaxCallListener()*/);
     }
 
-    /**
-     * Returns a decorator that will be used to decorate ajax links used in sortable headers
-     * 
-     * @return decorator or null for none
-     */
-    protected IAjaxCallListener getAjaxCallListener()
-    {
-        return null;
-    }
+//    /**
+//     * Returns a decorator that will be used to decorate ajax links used in sortable headers
+//     * 
+//     * @return decorator or null for none
+//     */
+//    protected IAjaxCallListener getAjaxCallListener()
+//    {
+//        return null;
+//    }
     
     // //////////////////////////////////////
 
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackOrderByBorder.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackOrderByBorder.java
index 92f1b7a..f0fdfac 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackOrderByBorder.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackOrderByBorder.java
@@ -16,15 +16,13 @@
  */
 package org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
 
+import org.apache.isis.viewer.wicket.model.hints.UiHintContainer;
 import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.ajax.attributes.IAjaxCallListener;
 import org.apache.wicket.extensions.ajax.markup.html.repeater.data.sort.AjaxFallbackOrderByBorder;
 import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortState;
 import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortStateLocator;
 import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
 
-import org.apache.isis.viewer.wicket.model.hints.UiHintContainer;
-
 public class IsisAjaxFallbackOrderByBorder<T> extends AjaxFallbackOrderByBorder<T> {
 
     private static final long serialVersionUID = 1L;
@@ -34,8 +32,13 @@ public class IsisAjaxFallbackOrderByBorder<T> extends AjaxFallbackOrderByBorder<
 
     private final ISortStateLocator<T> stateLocator;
     
-    public IsisAjaxFallbackOrderByBorder(String id, IsisAjaxFallbackDataTable<?, ?> dataTable, T sortProperty, ISortStateLocator<T> stateLocator, IAjaxCallListener ajaxCallListener) {
-        super(id, sortProperty, stateLocator, ajaxCallListener);
+    public IsisAjaxFallbackOrderByBorder(
+    		String id, 
+    		IsisAjaxFallbackDataTable<?, ?> dataTable, 
+    		T sortProperty, 
+    		ISortStateLocator<T> stateLocator
+    		/* removed in wicket 8, IAjaxCallListener ajaxCallListener*/) {
+        super(id, sortProperty, stateLocator/* removed in wicket 8, ajaxCallListener*/);
         this.dataTable = dataTable;
         this.stateLocator = stateLocator;
         this.sortProperty = sortProperty;
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxNavigationToolbar.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxNavigationToolbar.java
index 189b48b..e837cf3 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxNavigationToolbar.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxNavigationToolbar.java
@@ -45,9 +45,11 @@ public class IsisAjaxNavigationToolbar extends AjaxNavigationToolbar {
     private void addShowAllButton(final DataTable<?, ?> table) {
         table.setOutputMarkupId(true);
 
-        ((MarkupContainer)get("span")).add(new AjaxLink(ID_SHOW_ALL) {
+        ((MarkupContainer)get("span")).add(new AjaxLink<Void>(ID_SHOW_ALL) {
 
-            @Override
+			private static final long serialVersionUID = 1L;
+
+			@Override
             public void onClick(AjaxRequestTarget target) {
                 showAllItemsOn(table);
 
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
index 46cf5d2..c615cbd 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
@@ -36,7 +36,6 @@ import org.apache.wicket.extensions.markup.html.repeater.tree.ITreeProvider;
 import org.apache.wicket.extensions.markup.html.repeater.tree.NestedTree;
 import org.apache.wicket.extensions.markup.html.repeater.tree.Node;
 import org.apache.wicket.extensions.markup.html.repeater.tree.theme.WindowsTheme;
-import org.apache.wicket.model.AbstractReadOnlyModel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.LoadableDetachableModel;
 import org.apache.wicket.model.Model;
@@ -102,7 +101,7 @@ class IsisToWicketTreeAdapter {
 						private static final long serialVersionUID = 1L;
 						
 						@Override
-						public void onClick(AjaxRequestTarget target) {
+						public void onClick(Optional<AjaxRequestTarget> target) {
 							toggleExpandCollapse.run();
 						}
 
@@ -416,7 +415,7 @@ class IsisToWicketTreeAdapter {
 	/**
 	 * Wicket's model for collapse/expand state
 	 */
-	private static class TreeExpansionModel extends AbstractReadOnlyModel<Set<TreeModel>> {
+	private static class TreeExpansionModel implements IModel<Set<TreeModel>> {
 		private static final long serialVersionUID = 648152234030889164L;
 
 		public static TreeExpansionModel of(Set<TreePath> expandedTreePaths) {
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/buttons/ContainedButtonPanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/buttons/ContainedButtonPanel.java
index 5319a87..f3f7a9f 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/buttons/ContainedButtonPanel.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/buttons/ContainedButtonPanel.java
@@ -55,7 +55,7 @@ public class ContainedButtonPanel extends PanelAbstract<Model<String>> {
             private static final long serialVersionUID = 1L;
 
             @Override
-            protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+            protected void onSubmit(final AjaxRequestTarget target) {
                 setDefaultFormProcessing(false);
                 ContainedButtonPanel.this.onSubmit();
                 if (target != null) {
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/EmptyChoiceProvider.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/EmptyChoiceProvider.java
index aaf752d..93d83d2 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/EmptyChoiceProvider.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/EmptyChoiceProvider.java
@@ -18,16 +18,15 @@ package org.apache.isis.viewer.wicket.ui.components.widgets.select2.providers;
 
 import java.util.Collection;
 
-import org.apache.wicket.ajax.json.JSONException;
-import org.apache.wicket.ajax.json.JSONStringer;
 import org.wicketstuff.select2.ChoiceProvider;
 import org.wicketstuff.select2.Response;
 
 import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
 
 public class EmptyChoiceProvider extends ChoiceProvider<ObjectAdapterMemento> {
-
-    public static final EmptyChoiceProvider INSTANCE = new EmptyChoiceProvider();
+	private static final long serialVersionUID = 1L;
+	
+	public static final EmptyChoiceProvider INSTANCE = new EmptyChoiceProvider();
 
     @Override
     public String getDisplayValue(ObjectAdapterMemento object) {
@@ -44,10 +43,6 @@ public class EmptyChoiceProvider extends ChoiceProvider<ObjectAdapterMemento> {
     }
 
     @Override
-    public void toJson(ObjectAdapterMemento choice, JSONStringer writer) throws JSONException {
-    }
-
-    @Override
     public Collection<ObjectAdapterMemento> toChoices(Collection<String> ids) {
         return null;
     }
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/PromptFormAbstract.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/PromptFormAbstract.java
index ee31549..bd9629e 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/PromptFormAbstract.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/PromptFormAbstract.java
@@ -63,7 +63,9 @@ public abstract class PromptFormAbstract<T extends BookmarkableModel<ObjectAdapt
         extends FormAbstract<ObjectAdapter>
         implements ScalarModelSubscriber2 {
 
-    private static final String ID_OK_BUTTON = "okButton";
+	private static final long serialVersionUID = 1L;
+	
+	private static final String ID_OK_BUTTON = "okButton";
     public static final String ID_CANCEL_BUTTON = "cancelButton";
 
     private static final String ID_FEEDBACK = "feedback";
@@ -117,8 +119,8 @@ public abstract class PromptFormAbstract<T extends BookmarkableModel<ObjectAdapt
             private static final long serialVersionUID = 1L;
 
             @Override
-            public void onSubmit(AjaxRequestTarget target, Form<?> form) {
-                onOkSubmittedOf(target, form, this);
+            public void onSubmit(AjaxRequestTarget target) {
+                onOkSubmittedOf(target, getForm(), this);
             }
 
             @Override
@@ -129,16 +131,16 @@ public abstract class PromptFormAbstract<T extends BookmarkableModel<ObjectAdapt
             }
 
             @Override
-            protected void onError(AjaxRequestTarget target, Form<?> form) {
-                target.add(form);
+            protected void onError(AjaxRequestTarget target) {
+                target.add(getForm());
             }
         }
         : new AjaxButton(ID_OK_BUTTON, new ResourceModel("okLabel")) {
             private static final long serialVersionUID = 1L;
 
             @Override
-            public void onSubmit(AjaxRequestTarget target, Form<?> form) {
-                onOkSubmittedOf(target, form, this);
+            public void onSubmit(AjaxRequestTarget target) {
+                onOkSubmittedOf(target, getForm(), this);
             }
 
             @Override
@@ -149,8 +151,8 @@ public abstract class PromptFormAbstract<T extends BookmarkableModel<ObjectAdapt
             }
 
             @Override
-            protected void onError(AjaxRequestTarget target, Form<?> form) {
-                target.add(form);
+            protected void onError(AjaxRequestTarget target) {
+                target.add(getForm());
             }
         };
         okButton.add(new JGrowlBehaviour());
@@ -164,7 +166,7 @@ public abstract class PromptFormAbstract<T extends BookmarkableModel<ObjectAdapt
             private static final long serialVersionUID = 1L;
 
             @Override
-            public void onSubmit(final AjaxRequestTarget target, Form<?> form) {
+            public void onSubmit(final AjaxRequestTarget target) {
                 closePromptIfAny(target);
 
                 onCancelSubmitted(target);
@@ -175,7 +177,9 @@ public abstract class PromptFormAbstract<T extends BookmarkableModel<ObjectAdapt
 
         if (formExecutorContext.getPromptStyle().isInlineOrInlineAsIfEdit()) {
             cancelButton.add(new FireOnEscapeKey() {
-                @Override
+				private static final long serialVersionUID = 1L;
+
+				@Override
                 protected void respond(final AjaxRequestTarget target) {
                     onCancelSubmitted(target);
                 }
@@ -335,8 +339,9 @@ public abstract class PromptFormAbstract<T extends BookmarkableModel<ObjectAdapt
     }
 
     static abstract class FireOnEscapeKey extends AbstractDefaultAjaxBehavior {
-
-        private static final String PRE_JS =
+		private static final long serialVersionUID = 1L;
+		
+		private static final String PRE_JS =
                 "" + "$(document).ready( function() { \n"
                         + "  $(document).bind('keyup', function(evt) { \n"
                         + "    if (evt.keyCode == 27) { \n";

-- 
To stop receiving notification emails like this one, please contact
ahuber@apache.org.