From f51b6e5c11bdc34d2c482fa6b96230d04442a674 Mon Sep 17 00:00:00 2001 From: Dan Haywood Date: Thu, 22 Feb 2018 19:22:58 +0000 Subject: [PATCH] #74, #75, #76, #62, #47, #8 - updates documentation. Also also - changes package for ErrorReportingForJira module - fixes generic type for ActionDomainEvent in userimpersonate module - updates SecurityModule, ServletApiModule so that they inherit from ModuleAbstract --- .../src/main/asciidoc/modules/lib/lib.adoc | 14 ++ .../modules/lib/pdfbox/lib-pdfbox.adoc | 8 +- .../lib/servletapi/lib-servletapi.adoc | 16 +- .../asciidoc/modules/lib/slack/lib-slack.adoc | 135 +++++++++++++ .../asciidoc/modules/lib/zip/lib-zip.adoc | 94 ++++++++++ .../spi/command/spi-command-replay.adoc | 4 +- .../spi/errorrptjira/spi-errorrptjira.adoc | 151 +++++++++++++++ .../spi/errorrptslack/spi-errorrptslack.adoc | 163 ++++++++++++++++ .../src/main/asciidoc/modules/spi/spi.adoc | 17 ++ .../userimpersonate/spi-userimpersonate.adoc | 177 ++++++++++++++++++ .../module/servletapi/ServletApiModule.java | 8 +- .../servletapi/dom/HttpSessionProvider.java | 6 +- .../module/slack/impl/SlackService.java | 3 +- .../incode/module/zip/impl/ZipService.java | 4 +- .../ErrorReportingJiraModule.java | 2 +- .../impl/ErrorReportingServiceForJira.java | 2 +- .../impl/HttpPoster.java | 2 +- .../impl/JiraMarshaller.java | 2 +- .../impl/JsonMarshaller.java | 2 +- .../ErrorReportingServiceForJira_Test.java | 4 +- .../ErrorReportingSlackModule.java | 24 +++ .../impl/ErrorReportingServiceForSlack.java | 6 +- .../slack/ErrorReportingSlackModule.java | 10 - .../ErrorReportingServiceForSlack_Test.java | 8 +- .../module/security/SecurityModule.java | 7 +- .../UserImpersonateModule.java | 14 ++ .../userimpersonate/app/ImpersonateMenu.java | 5 +- .../Object_stopImpersonating.java | 2 +- .../impl/UserServiceWithImpersonation.java | 12 +- 29 files changed, 855 insertions(+), 47 deletions(-) create mode 100644 adocs/documentation/src/main/asciidoc/modules/lib/slack/lib-slack.adoc create mode 100644 adocs/documentation/src/main/asciidoc/modules/lib/zip/lib-zip.adoc create mode 100644 adocs/documentation/src/main/asciidoc/modules/spi/errorrptjira/spi-errorrptjira.adoc create mode 100644 adocs/documentation/src/main/asciidoc/modules/spi/errorrptslack/spi-errorrptslack.adoc create mode 100644 adocs/documentation/src/main/asciidoc/modules/spi/userimpersonate/spi-userimpersonate.adoc rename modules/spi/errorrptjira/impl/src/main/java/org/incode/module/{jira => errorrptjira}/ErrorReportingJiraModule.java (83%) rename modules/spi/errorrptjira/impl/src/main/java/org/incode/module/{jira => errorrptjira}/impl/ErrorReportingServiceForJira.java (99%) rename modules/spi/errorrptjira/impl/src/main/java/org/incode/module/{jira => errorrptjira}/impl/HttpPoster.java (98%) rename modules/spi/errorrptjira/impl/src/main/java/org/incode/module/{jira => errorrptjira}/impl/JiraMarshaller.java (95%) rename modules/spi/errorrptjira/impl/src/main/java/org/incode/module/{jira => errorrptjira}/impl/JsonMarshaller.java (95%) rename modules/spi/errorrptjira/impl/src/test/java/org/incode/module/{jira => errorrptjira}/impl/ErrorReportingServiceForJira_Test.java (96%) create mode 100644 modules/spi/errorrptslack/impl/src/main/java/org/incode/module/errorrptslack/ErrorReportingSlackModule.java rename modules/spi/errorrptslack/impl/src/main/java/org/incode/module/{slack => errorrptslack}/impl/ErrorReportingServiceForSlack.java (98%) delete mode 100644 modules/spi/errorrptslack/impl/src/main/java/org/incode/module/slack/ErrorReportingSlackModule.java rename modules/spi/errorrptslack/impl/src/test/java/org/incode/module/{slack => errorrptslack}/impl/ErrorReportingServiceForSlack_Test.java (95%) diff --git a/adocs/documentation/src/main/asciidoc/modules/lib/lib.adoc b/adocs/documentation/src/main/asciidoc/modules/lib/lib.adoc index c3ffc0e2c..e4418e9ad 100644 --- a/adocs/documentation/src/main/asciidoc/modules/lib/lib.adoc +++ b/adocs/documentation/src/main/asciidoc/modules/lib/lib.adoc @@ -102,6 +102,13 @@ Note that this module is only available through the Wicket viewer, not the REST | (none) | (none) +| xref:slack/lib-slack.adoc#[Slack Library] +| Provides the ability to post to a Slack channel. + +| (none) +| (none) +| link:https://github.com/Ullink/simple-slack-api[Simple Slack API] + | xref:stringinterpolator/lib-stringinterpolator.adoc#[String Interpolator (OGNL) Library] |Provides a mechanism to interpolate string templates with either Isis system properties or values obtained from a domain object, using _OGNL_ library. @@ -121,6 +128,13 @@ Note that this module is only available through the Wicket viewer, not the REST | (none) | link:https://github.com/opensagres/xdocreport[XDocReport] +| xref:zip/lib-zip.adoc#[Zip Library] +| Zips up a collection of files. + +| (none) +| (none) +| (none) + |=== diff --git a/adocs/documentation/src/main/asciidoc/modules/lib/pdfbox/lib-pdfbox.adoc b/adocs/documentation/src/main/asciidoc/modules/lib/pdfbox/lib-pdfbox.adoc index d196d8e5b..19e7a4d7d 100644 --- a/adocs/documentation/src/main/asciidoc/modules/lib/pdfbox/lib-pdfbox.adoc +++ b/adocs/documentation/src/main/asciidoc/modules/lib/pdfbox/lib-pdfbox.adoc @@ -91,16 +91,18 @@ It has the following API: public class PdfBoxService { public byte[] merge(byte[]... pdfByteArrays) throws IOException { } // <1> + public byte[] merge(List fileList) throws IOException { ... } // <2> + public byte[] merge(File... files) throws IOException { ... } - public void merge( // <2> + public void merge( // <3> OutputStream outputStream, InputStream... inputStreams ) throws IOException { } } ---- <1> merge an arbitrary number of PDFs, represented as arrays of bytes, to another byte array -<2> merge an arbitrary number of PDFs, represented as an input stream, to an output stream - +<2> merge a list of files (to avoid memory issues) +<3> merge an arbitrary number of PDFs, represented as an input stream, to an output stream diff --git a/adocs/documentation/src/main/asciidoc/modules/lib/servletapi/lib-servletapi.adoc b/adocs/documentation/src/main/asciidoc/modules/lib/servletapi/lib-servletapi.adoc index 362a792da..8b1779b79 100644 --- a/adocs/documentation/src/main/asciidoc/modules/lib/servletapi/lib-servletapi.adoc +++ b/adocs/documentation/src/main/asciidoc/modules/lib/servletapi/lib-servletapi.adoc @@ -101,7 +101,7 @@ public class HttpServletRequestProvider { } ---- -And finally the `HttpServletResponseProvider` defines the following API: +The `HttpServletResponseProvider` defines the following API: [source,java] ---- @@ -110,6 +110,20 @@ public class HttpServletResponseProvider { } ---- +And finally, the `HttpSessionProvider` defines the following API: + +[source,java] +---- +@DomainService(nature = NatureOfService.DOMAIN) +public class HttpSessionProvider { + public Optional getHttpSession() { ... } + public Optional getAttribute(String key, Class clazz) { ... } // <1> + public void setAttribute( String key, T value) { ... } + public void removeAttribute(String key) { ... } +} +---- +<1> obtains an attribute (previous set) by key, cast to the specified class + These actions are all programmatic and do not appear in the UI. diff --git a/adocs/documentation/src/main/asciidoc/modules/lib/slack/lib-slack.adoc b/adocs/documentation/src/main/asciidoc/modules/lib/slack/lib-slack.adoc new file mode 100644 index 000000000..7d6374620 --- /dev/null +++ b/adocs/documentation/src/main/asciidoc/modules/lib/slack/lib-slack.adoc @@ -0,0 +1,135 @@ +[[dom-slack]] += Slack Library +:_basedir: ../../../ +:_imagesdir: images/ +:generate_pdf: +:toc: + +This module (`incode-module-slack-dom`) provides the ability to post to a Slack channel (with Slack running on the Cloud). + + + +== API & Implementation + +The `SlackService` defines the following API: + +[source,java] +---- +public class SlackService { + public boolean isConfigured() { ... } // <1> + public boolean channelExists(String channelName) { ... } // <2> + + public void sendMessage( // <3> + String channelName, + String message) { ... } + public SlackMessageHandle sendMessage( // <4> + String channelName, + SlackPreparedMessage preparedMessage) { ... } +} +---- +<1> whether the service is available for use. +If not configured, then the `sendMessage(...)` methods will silently no-op. +<2> allows consumers to check whether a channel exists (before attempting to use it in the `sendMessage(...)`. +If the servicew is not configured, then returns `false`. +<3> Sends a message to the specified channel. +If no such channel exists, then an `IllegalArgumentException` will be thrown. +<4> Allows more sophisticated messages to be sent (using the API of the underlying implementation library, link:https://github.com/Ullink/simple-slack-api[Simple Slack API]. + +These actions are all programmatic and do not appear in the UI. + + + +== How to configure/use + +=== Classpath + +Update your classpath by adding this dependency in your `dom` project's `pom.xml`: + +[source,xml] +---- + + org.incode.module.slack + incode-module-slack-dom + 1.16.1 + +---- + +Check for later releases by searching link:http://search.maven.org/#search|ga|1|incode-module-slack-dom[Maven Central Repo]. + +For instructions on how to use the latest `-SNAPSHOT`, see the xref:../../../pages/contributors-guide/contributors-guide.adoc#[contributors guide]. + + +=== Configuration Properties + +There is one mandatory configuration property. + +[source,properties] +---- +isis.service.slack.authToken=xxxxx +---- + +The `authToken` can be obtained by logging into your http://slack.com[slack.com] account, on the settings page for bots. +This token represents the credentials of the bot posting to the channel, so obviously should be kept private and not be shared around. + + +=== System Properties + +Optionally, an http/s proxy can be set, by setting two system properties: + +[source,properties] +---- +-Dhttp.proxyPort=... +-Dhttp.proxyHost=... +---- + +[NOTE] +==== +Note that the system properties for SSL (`https.proxyHost` and `https.proxyPort`) are *NOT* checked. +==== + + +=== Bootstrapping + +In the `AppManifest`, update its `getDependencies()` method, eg: + +[source,java] +---- +@Override +public Set getDependencies() { + return Sets.newHashSet( + ... + new org.incode.module.slack.SlackModule(), + ... + ); +} +---- + + + + +== Known issues + +None known at this time. + + + + +== Dependencies + + +Maven can report modules dependencies using: + + + +[source,bash] +---- +mvn dependency:list -o -pl modules/lib/slack/impl -D excludeTransitive=true +---- + +which, excluding Apache Isis itself, returns these compile/runtime dependencies: + +[source,bash] +---- +com.ullink.slack:simpleslackapi:jar:1.2.0 +---- + diff --git a/adocs/documentation/src/main/asciidoc/modules/lib/zip/lib-zip.adoc b/adocs/documentation/src/main/asciidoc/modules/lib/zip/lib-zip.adoc new file mode 100644 index 000000000..a32c006eb --- /dev/null +++ b/adocs/documentation/src/main/asciidoc/modules/lib/zip/lib-zip.adoc @@ -0,0 +1,94 @@ +[[dom-zip]] += Zip Library +:_basedir: ../../../ +:_imagesdir: images/ +:generate_pdf: +:toc: + +This module (`incode-module-zip-dom`) allows a zip to be created from a collection of files. + + +== API & Implementation + +The `ZipService` defines the following API: + +[source,java] +---- +public class ZipService { + + @lombok.Data // <1> + public static class FileAndName { + private final String name; + private final File file; + } + + public byte[] zip(final List fileAndNameList) { ... } // <2> + public byte[] zipFiles(final List fileList) { ... } // <3> +} +---- +<1> immutable value type +<2> Returns a byte array which is a zip of the collection of files. +Rather than use the name of the file (which might be temporary files, for example), the name of each file to use (in its zip "entry") is provided. +<3> Similar to `zip(...)`, but uses each file's name as the zip entry (rather than providing it explicitly). + +These actions are all programmatic and do not appear in the UI. + + + +== How to configure/use + +=== Classpath + +Update your classpath by adding this dependency in your `dom` project's `pom.xml`: + +[source,xml] +---- + + org.incode.module.zip + incode-module-zip-dom + 1.16.1 + +---- + +Check for later releases by searching link:http://search.maven.org/#search|ga|1|incode-module-zip-dom[Maven Central Repo]. + +For instructions on how to use the latest `-SNAPSHOT`, see the xref:../../../pages/contributors-guide/contributors-guide.adoc#[contributors guide]. + + + +=== Bootstrapping + +In the `AppManifest`, update its `getDependencies()` method, eg: + +[source,java] +---- +@Override +public Set getDependencies() { + return Sets.newHashSet( + ... + new org.incode.module.zip.ZipModule(), + ... + ); +} +---- + + + + +== Known issues + +None known at this time. + + + + +== Dependencies + +Maven can report modules dependencies using: + +[source,bash] +---- +mvn dependency:list -o -pl modules/lib/zip/impl -D excludeTransitive=true +---- + +This shows no additional compile/runtime dependencies (other than Apache Isis itself). diff --git a/adocs/documentation/src/main/asciidoc/modules/spi/command/spi-command-replay.adoc b/adocs/documentation/src/main/asciidoc/modules/spi/command/spi-command-replay.adoc index bc7c17d61..78e762495 100644 --- a/adocs/documentation/src/main/asciidoc/modules/spi/command/spi-command-replay.adoc +++ b/adocs/documentation/src/main/asciidoc/modules/spi/command/spi-command-replay.adoc @@ -455,6 +455,6 @@ org.isisaddons.module.quartz:isis-module-quartz-dom For further details on these dependencies, see: -* xref:../../lib/lib-jaxrsclient.adoc#[JAX-RS Client library] -* xref:../../ext/ext-quartz.adoc#[Quartz extension] +* xref:../../lib/jaxrsclient/lib-jaxrsclient.adoc#[JAX-RS Client library] +* xref:../../ext/quartz/ext-quartz.adoc#[Quartz extension] diff --git a/adocs/documentation/src/main/asciidoc/modules/spi/errorrptjira/spi-errorrptjira.adoc b/adocs/documentation/src/main/asciidoc/modules/spi/errorrptjira/spi-errorrptjira.adoc new file mode 100644 index 000000000..b5e4a460d --- /dev/null +++ b/adocs/documentation/src/main/asciidoc/modules/spi/errorrptjira/spi-errorrptjira.adoc @@ -0,0 +1,151 @@ +[[spi-errorrptslack]] += ErrorReporting SPI for Jira +:_basedir: ../../../ +:_imagesdir: images/ +:generate_pdf: +:toc: + +This module (`incode-module-errorrptjira-impl`) provides an implementation of Apache Isis' link:http://isis.apache.org/guides/rgsvc/rgsvc.html#_rgsvc_presentation-layer-spi_ErrorReportingService[`ErrorReportingService`] SPI. +Whenever an error page is displayed to the user, the implementation will automatically log the details in JIRA and provide the ticket reference to the end-user. + + +== API & Implementation + +This module provides `ErrorReportingServiceForJira` domain service as an implementation of the `ErrorReportingService`: + +[source,java] +---- +public interface ErrorReportingService { + Ticket reportError(final ErrorDetails errorDetails); +} +---- + +where the returned `Ticket` determines what is shown on the error page for the end-user. +In the case of this implementation: + +[source,java] +---- +public class Ticket implements Serializable { + private final String reference; // <1> + private final String userMessage; // <2> + private final String details; // <3> + private final StackTracePolicy stackTracePolicy; // <4> + private final String kittenUrl; // <5> + ... +} +---- +<1> the JIRA issue number, eg "SUP-1234" +<2> the main error message to display to the user. +This defaults to: + ++ +_"Our apologies, an error has occurred. Support has been notified."_ + ++ +but can be configured to something else if required (see below). + +<3> optionally, additional details (shown in a smaller font). +This defaults to: + ++ +_"For more details, see JIRA issue: %s"_ + ++ +(with the place holder holding the URL for the generated JIRA issue), but can be configured to something else if required (see below). + +<4> whether the end user should be able to view the stack trace. +This implementation ALWAYS HIDES the stack trace. +<5> the URL of an image to display, if any. +This implementation never shows any image. + + + + +== How to configure/use + +=== Classpath + +Update your classpath by adding this dependency in your `dom` project's `pom.xml`: + + +[source,xml] +---- + + org.incode.module.errorrptjira + incode-module-errorrptjira-impl + 1.16.1 + +---- + + +Check for later releases by searching link:http://search.maven.org/#search|ga|1|incode-module-errorrptjira-impl[Maven Central Repo]. + +For instructions on how to use the latest `-SNAPSHOT`, see the xref:../../../pages/contributors-guide/contributors-guide.adoc#[contributors guide]. + + + +=== Configuration Properties + +The following configuration properties are required (either in `isis.properties` or through the `AppManifest`); for example: + +[source,properties] +---- +isis.service.errorReporting.jira.username=XXXXXX +isis.service.errorReporting.jira.password=XXXXXX +isis.service.errorReporting.jira.base=https://mycompany.atlassian.net/ +isis.service.errorReporting.jira.projectKey=PRODSUP +isis.service.errorReporting.jira.issueType="IT Help" +---- + +Optionally the message text and details can be changed: + +[source,properties] +---- +isis.service.errorReporting.jira.userMessage=... +isis.service.errorReporting.jira.detailsFormat=... +---- + +There currently is no mechanism to localize the message. + +=== Bootstrapping + +In the `AppManifest`, update its `getDependencies()` method, eg: + +[source,java] +---- +@Override +public Set getDependencies() { + return Sets.newHashSet( + ... + new org.incode.module.errorrptjira.ErrorReportingJiraModule(), + ... + ); +} +---- + + + + +== Known issues + +None known at this time. + + + + +== Dependencies + +Maven can report modules dependencies using: + +[source,bash] +---- +mvn dependency:list -o -pl modules/spi/errorrptjira/impl -D excludeTransitive=true +---- + +which, excluding Apache Isis itself, returns these compile/runtime dependencies: + +[source,bash] +---- +com.fasterxml.jackson.core:jackson-databind:jar:2.8.0 +---- + diff --git a/adocs/documentation/src/main/asciidoc/modules/spi/errorrptslack/spi-errorrptslack.adoc b/adocs/documentation/src/main/asciidoc/modules/spi/errorrptslack/spi-errorrptslack.adoc new file mode 100644 index 000000000..7876fe62e --- /dev/null +++ b/adocs/documentation/src/main/asciidoc/modules/spi/errorrptslack/spi-errorrptslack.adoc @@ -0,0 +1,163 @@ +[[spi-errorrptslack]] += ErrorReporting SPI for Slack +:_basedir: ../../../ +:_imagesdir: images/ +:generate_pdf: +:toc: + +This module (`incode-module-errorrptslack-impl`) provides an implementation of Apache Isis' link:http://isis.apache.org/guides/rgsvc/rgsvc.html#_rgsvc_presentation-layer-spi_ErrorReportingService[`ErrorReportingService`] SPI. +Whenever an error page is displayed to the user, the implementation will generate a unique id (a guid) and post a message to a specified Slack channel (to notify production support). +It will also display a random image. + + +== API & Implementation + +This module provides `ErrorReportingServiceForSlack` domain service as an implementation of the `ErrorReportingService`: + +[source,java] +---- +public interface ErrorReportingService { + Ticket reportError(final ErrorDetails errorDetails); +} +---- + +where the returned `Ticket` determines what is shown on the error page for the end-user. +In the case of this implementation: + +[source,java] +---- +public class Ticket implements Serializable { + private final String reference; // <1> + private final String userMessage; // <2> + private final String details; // <3> + private final StackTracePolicy stackTracePolicy; // <4> + private final String kittenUrl; // <5> + ... +} +---- +<1> the random UUID. +This is posted to the Slack also, so if the user quotes this number then the support team can find additional details (such as the stack trace) +<2> the main error message to display to the user. +This will default to: + ++ +_"Our apologies, an error has occurred. +The development team has been notified (via the Slack messaging system)._ + ++ +but can be configured to something else if required (see below). + +<3> optionally, additional details (shown in a smaller font). +This defaults to: + ++ +_"Quote the reference below to point us to more +detailed information about the problem. +\ +In the meantime, and by way of an apology, +here's a picture of a kitten for you to look at._ + ++ +but can be configured to something else if required (see below). + +<4> whether the end user should be able to view the stack trace. +This implementation ALWAYS HIDES the stack trace. +<5> the URL of an image to display, if any. +This will default to: + ++ +link:http://www.randomkittengenerator.com/cats/rotator.php[] + ++ +but can be configured to something else if required (see below). + + + + +== How to configure/use + +=== Classpath + +Update your classpath by adding this dependency in your `dom` project's `pom.xml`: + + +[source,xml] +---- + + org.incode.module.errorrptslack + incode-module-errorrptslack-impl + 1.16.1 + +---- + + +Check for later releases by searching link:http://search.maven.org/#search|ga|1|incode-module-errorrptslack-impl[Maven Central Repo]. + +For instructions on how to use the latest `-SNAPSHOT`, see the xref:../../../pages/contributors-guide/contributors-guide.adoc#[contributors guide]. + + + +=== Configuration Properties + +The following configuration properties are required (either in `isis.properties` or through the `AppManifest`): + +[source,properties] +---- +isis.service.slack.authToken=XXXXXX // <1> +isis.service.errorReporting.slack.channel=ProdSupport +---- +<1> there is no "errorReporting" part to this config property; it is to configure the underlying xref:../../lib/slack/lib-slack.adoc#[Slack Module]. + +Optionally the message text and details can be changed: + +[source,properties] +---- +isis.service.errorReporting.slack.userMessage=... +isis.service.errorReporting.slack.details=... +isis.service.errorReporting.slack.kittenUrl=... +---- + +The timeout for waiting for Slack to acknowledge the message can also be tweaked: + +[source,properties] +---- +isis.service.errorReporting.slack.timeoutMs=500 +---- + +=== Bootstrapping + +In the `AppManifest`, update its `getDependencies()` method, eg: + +[source,java] +---- +@Override +public Set getDependencies() { + return Sets.newHashSet( + ... + new org.incode.module.errorrptjira.ErrorReportingSlackModule(), + ... + ); +} +---- + + + + +== Known issues + +None known at this time. + + + + +== Dependencies + +Maven can report modules dependencies using: + +[source,bash] +---- +mvn dependency:list -o -pl modules/spi/errorrptslack/impl -D excludeTransitive=true +---- + +which, excluding Apache Isis itself, depends only on the xref:../../lib/slack/lib-slack.adoc[Slack module]. + diff --git a/adocs/documentation/src/main/asciidoc/modules/spi/spi.adoc b/adocs/documentation/src/main/asciidoc/modules/spi/spi.adoc index b5824a943..ce4694b4c 100644 --- a/adocs/documentation/src/main/asciidoc/modules/spi/spi.adoc +++ b/adocs/documentation/src/main/asciidoc/modules/spi/spi.adoc @@ -30,6 +30,18 @@ This enables profiling and (in conjunction with the xref:audit/spi-audit.adoc#[A | link:http://isis.apache.org/guides/rgsvc/rgsvc.html#_rgsvc_application-layer-spi_CommandService[CommandService] | (none) +|xref:errorrptjira/spi-errorrptjira.adoc#[ErrorReportingJira] +| Whenever the error page is displayed to the user, automatically log the details in JIRA and provide the ticket details to the end-user. +| link:http://isis.apache.org/guides/rgsvc/rgsvc.html#_rgsvc_presentation-layer-spi_ErrorReportingService[ErrorReportingService] +| link:http://github.com/FasterXML/jackson-databind[Jackson] + +|xref:errorrptslack/spi-errorrptslack.adoc#[ErrorReportingSlack] +| Whenever the error page is displayed to the user, automatically post the details to a Slack channel and display an random image. + +The default implementation shows a random kitten (!), but this can be customised. +| link:http://isis.apache.org/guides/rgsvc/rgsvc.html#_rgsvc_presentation-layer-spi_ErrorReportingService[ErrorReportingService] +| xref:../../lib/slack/lib-slack.adoc#[Slack module] + |xref:publishmq/spi-publishmq.adoc#[PublishMQ] | Submits an XML representation of member interactions (action invocations and property edits) to an _Apache ActiveMQ_ queue. @@ -53,6 +65,11 @@ Permissions themselves can either _allow_ or _veto_ the ability to _view_ or _ch | link:http://isis.apache.org/guides/rgsvc/rgsvc.html#_rgsvc_presentation-layer-spi_SessionLoggingService[SessionLoggingService] | (none) +|xref:userimpersonate/spi-userimpersonate.adoc#[UserImpersonate] +| Allow the logged-in user to be switched dynamically, ie to impersonate some other user. +Intended for prototyping and demos only. +| link:http://isis.apache.org/guides/rgsvc/rgsvc.html#_rgsvc_core-domain-api_UserService[UserService] +| xref:../../lib/servletapi/lib-servletapi.adoc#[ServletAPI module]; xref:../../spi/security/spi-security.adoc#[Security SPI module] |=== diff --git a/adocs/documentation/src/main/asciidoc/modules/spi/userimpersonate/spi-userimpersonate.adoc b/adocs/documentation/src/main/asciidoc/modules/spi/userimpersonate/spi-userimpersonate.adoc new file mode 100644 index 000000000..fe7d5a70e --- /dev/null +++ b/adocs/documentation/src/main/asciidoc/modules/spi/userimpersonate/spi-userimpersonate.adoc @@ -0,0 +1,177 @@ +[[spi-userimpersonate]] += UserService API/SPI with Impersonation +:_basedir: ../../../ +:_imagesdir: images/ +:generate_pdf: +:toc: + +This module (`incode-module-userimpersonate-dom`) overrides the default implementation of Apache Isis' link:http://isis.apache.org/guides/rgsvc/rgsvc.html#_rgsvc_core-domain-api_UserService[`UserService`] API. +Intended for prototyping and demos only, it allows the logged-in user to be switched dynamically, ie to impersonate some other user. + + +== API + +The `UserService` API is defined as: + +[source,java] +---- +public interface UserService { + UserMemento getUser(); +} +---- + +where `UserMemento` contains both the current user name and their set of roles. + +The Apache Isis framework provide a default implementation of this service. +What this module does is to provide a different implementation of the service with a higher priority which is therefore used instead. + +This implementation - `UserServiceWithImpersonation` - extends the API as follows: + +[source,java] +---- +public class UserServiceWithImpersonation implements UserService { + + public UserMemento getUser() { ... } // <1> + + public void setUser(String userName) { ... } // <2> + public void setUser(String userName, String... roles) { ... } + public void setUser(String userName, List roles) { ... } + + public void reset() { ... } // <3> + + public boolean isImpersonating() { ... } // <4> + + public boolean isAvailable() { ... } // <5> +} +---- +<1> the API of `UserService`, this returns the current user. +If a user is being impersonated (per `setUser(...)`) then that will be returned. ++ +Otherwise, though, the service delegates down to the default implementation of `UserService` (in other words, the user that actually logged on). +<2> Impersonate a different user, optionally specifying a different set of roles. +If roles are not specified then the roles of the original user are preserved. +<3> Removes the impersonation, returning back to the original user. +<4> Check to see if a user is being impersonated (that is, that `setUser(...)` was called and `reset()` has not been called subsequently). +<5> Checks that the service is available. +If it is not, then `setUser(...)` has no effect. + +The service is only available when running within a webapp. +This is because it relies upon the `HttpSession` (as obtained from xref:../../lib/servletapi/lib-servletapi.adoc#[Servlet API module]) to store the impersonating user identity. + +[NOTE] +==== +Note that impersonations do _not_ nest. + +That is, the user logs in as _user1_, then impersonates to _user2_, then impersonates again to _user3_, then resetting will go back to the original _user1_. +==== + + +== Menus and Contributions + +The `ImpersonationMenu` domain service provides a couple of actions which are surfaced in the UI on the tertiary menu bar: + +[source,java] +---- +public class ImpersonateMenu { + + public void impersonate( + ApplicationUser applicationUser, + @Nullable + List applicationRoleList) { ... } + + public void stopImpersonating() { ... } +} +---- + +This uses the xref:../../spi/security/spi-security.adoc#[Security module] to constrain the list of valid users/roles. + +There are also two mixins: + +* the `Object_impersonateUser` mixin allows impersonation to be invoked from any domain object. + +* the `Object_stopImpersonating` mixin similarly resets impersonation. + +The actions of the menu and the mixins are restricted to prototyping only. +They also emit domain events so can be vetoed if required. + +Behind the scenes these classes delegate to the module's `ImpersonationService`, mostly an implementation detail: + +[source,java] +---- +public class ImpersonationService { + + public void impersonate( + ApplicationUser applicationUser, + List applicationRoleList) { ... } + public boolean hideImpersonate() { ... } + + public void stopImpersonating() { ... } + public boolean hideStopImpersonating() { ... } +} +---- + + + + +== How to configure/use + +=== Classpath + +Update your classpath by adding this dependency in your `dom` project's `pom.xml`: + + +[source,xml] +---- + + org.incode.module.userimpersonate + incode-module-userimpersonate-dom + 1.16.1 + +---- + + +Check for later releases by searching link:http://search.maven.org/#search|ga|1|incode-module-userimpersonate-dom[Maven Central Repo]. + +For instructions on how to use the latest `-SNAPSHOT`, see the xref:../../../pages/contributors-guide/contributors-guide.adoc#[contributors guide]. + + + +=== Bootstrapping + +In the `AppManifest`, update its `getDependencies()` method, eg: + +[source,java] +---- +@Override +public Set getDependencies() { + return Sets.newHashSet( + ... + new org.incode.module.userimpersonate.UserImpersonateModule(), + ... + ); +} +---- + + + + +== Known issues + +None known at this time. + + + + +== Dependencies + +Maven can report modules dependencies using: + +[source,bash] +---- +mvn dependency:list -o -pl modules/spi/userimpersonate/impl -D excludeTransitive=true +---- + +which, excluding Apache Isis itself, depends only on the xref:../../lib/servletapi/lib-servletapi.adoc#[ServletAPI library module] and the xref:../../spi/security/spi-security.adoc#[Security SPI module] + + + diff --git a/modules/lib/servletapi/impl/src/main/java/org/isisaddons/module/servletapi/ServletApiModule.java b/modules/lib/servletapi/impl/src/main/java/org/isisaddons/module/servletapi/ServletApiModule.java index a7f629604..f7a1e757f 100644 --- a/modules/lib/servletapi/impl/src/main/java/org/isisaddons/module/servletapi/ServletApiModule.java +++ b/modules/lib/servletapi/impl/src/main/java/org/isisaddons/module/servletapi/ServletApiModule.java @@ -1,5 +1,9 @@ package org.isisaddons.module.servletapi; -public final class ServletApiModule { - private ServletApiModule(){} +import javax.xml.bind.annotation.XmlRootElement; + +import org.apache.isis.applib.ModuleAbstract; + +@XmlRootElement(name = "module") +public class ServletApiModule extends ModuleAbstract { } diff --git a/modules/lib/servletapi/impl/src/main/java/org/isisaddons/module/servletapi/dom/HttpSessionProvider.java b/modules/lib/servletapi/impl/src/main/java/org/isisaddons/module/servletapi/dom/HttpSessionProvider.java index 6967682a7..d6c368e59 100644 --- a/modules/lib/servletapi/impl/src/main/java/org/isisaddons/module/servletapi/dom/HttpSessionProvider.java +++ b/modules/lib/servletapi/impl/src/main/java/org/isisaddons/module/servletapi/dom/HttpSessionProvider.java @@ -24,13 +24,13 @@ public Optional getHttpSession() { @Programmatic public Optional getAttribute( final String httpSessionKey, - final Class userMementoClass) { + final Class clazz) { try { return getHttpSession() .filter(Objects::nonNull) .map(httpSession -> httpSession.getAttribute(httpSessionKey)) - .filter(userMementoClass::isInstance) - .map(userMementoClass::cast); + .filter(clazz::isInstance) + .map(clazz::cast); } catch (Exception e) { // bit hacky; to clean this up will require changes to servletapi module. return Optional.empty(); diff --git a/modules/lib/slack/impl/src/main/java/org/incode/module/slack/impl/SlackService.java b/modules/lib/slack/impl/src/main/java/org/incode/module/slack/impl/SlackService.java index 726996db5..f9f6003eb 100644 --- a/modules/lib/slack/impl/src/main/java/org/incode/module/slack/impl/SlackService.java +++ b/modules/lib/slack/impl/src/main/java/org/incode/module/slack/impl/SlackService.java @@ -21,7 +21,6 @@ import org.apache.isis.applib.annotation.NatureOfService; import org.apache.isis.applib.annotation.Programmatic; import org.apache.isis.core.commons.config.IsisConfiguration; -import org.apache.isis.core.commons.config.IsisConfigurationDefault; import lombok.Setter; @@ -56,7 +55,7 @@ public SlackService() { /** * For testing purposes only. */ - public SlackService(final IsisConfigurationDefault configuration) { + public SlackService(final IsisConfiguration configuration) { this.configuration = configuration; } diff --git a/modules/lib/zip/impl/src/main/java/org/incode/module/zip/impl/ZipService.java b/modules/lib/zip/impl/src/main/java/org/incode/module/zip/impl/ZipService.java index c2b60e21e..270fbde9c 100644 --- a/modules/lib/zip/impl/src/main/java/org/incode/module/zip/impl/ZipService.java +++ b/modules/lib/zip/impl/src/main/java/org/incode/module/zip/impl/ZipService.java @@ -32,7 +32,7 @@ public static class FileAndName { * */ @Programmatic - public byte[] zip(final List fileAndNameList) throws IOException { + public byte[] zip(final List fileAndNameList) { final byte[] bytes; try { @@ -56,7 +56,7 @@ public byte[] zip(final List fileAndNameList) throws IOException { * As per {@link #zip(List)}, but using each file's name as the zip entry (rather than providing it). */ @Programmatic - public byte[] zipFiles(final List fileList) throws IOException { + public byte[] zipFiles(final List fileList) { return zip(fileList.stream() .map(file -> new FileAndName(file.getName(), file)) .collect(Collectors.toList()) diff --git a/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/ErrorReportingJiraModule.java b/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/ErrorReportingJiraModule.java similarity index 83% rename from modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/ErrorReportingJiraModule.java rename to modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/ErrorReportingJiraModule.java index 76da8cd37..2986c32b7 100644 --- a/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/ErrorReportingJiraModule.java +++ b/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/ErrorReportingJiraModule.java @@ -1,4 +1,4 @@ -package org.incode.module.jira; +package org.incode.module.errorrptjira; import javax.xml.bind.annotation.XmlRootElement; diff --git a/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/impl/ErrorReportingServiceForJira.java b/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/impl/ErrorReportingServiceForJira.java similarity index 99% rename from modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/impl/ErrorReportingServiceForJira.java rename to modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/impl/ErrorReportingServiceForJira.java index a38aa727b..b0c14eab8 100644 --- a/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/impl/ErrorReportingServiceForJira.java +++ b/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/impl/ErrorReportingServiceForJira.java @@ -1,4 +1,4 @@ -package org.incode.module.jira.impl; +package org.incode.module.errorrptjira.impl; import java.util.List; import java.util.Map; diff --git a/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/impl/HttpPoster.java b/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/impl/HttpPoster.java similarity index 98% rename from modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/impl/HttpPoster.java rename to modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/impl/HttpPoster.java index afcc33cf8..416b59d85 100644 --- a/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/impl/HttpPoster.java +++ b/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/impl/HttpPoster.java @@ -1,4 +1,4 @@ -package org.incode.module.jira.impl; +package org.incode.module.errorrptjira.impl; import java.util.Optional; diff --git a/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/impl/JiraMarshaller.java b/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/impl/JiraMarshaller.java similarity index 95% rename from modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/impl/JiraMarshaller.java rename to modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/impl/JiraMarshaller.java index b1849c4da..e5a3f28f2 100644 --- a/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/impl/JiraMarshaller.java +++ b/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/impl/JiraMarshaller.java @@ -1,4 +1,4 @@ -package org.incode.module.jira.impl; +package org.incode.module.errorrptjira.impl; import java.util.Map; diff --git a/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/impl/JsonMarshaller.java b/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/impl/JsonMarshaller.java similarity index 95% rename from modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/impl/JsonMarshaller.java rename to modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/impl/JsonMarshaller.java index 3455921eb..f1c7235c1 100644 --- a/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/jira/impl/JsonMarshaller.java +++ b/modules/spi/errorrptjira/impl/src/main/java/org/incode/module/errorrptjira/impl/JsonMarshaller.java @@ -1,4 +1,4 @@ -package org.incode.module.jira.impl; +package org.incode.module.errorrptjira.impl; import java.io.IOException; import java.util.Map; diff --git a/modules/spi/errorrptjira/impl/src/test/java/org/incode/module/jira/impl/ErrorReportingServiceForJira_Test.java b/modules/spi/errorrptjira/impl/src/test/java/org/incode/module/errorrptjira/impl/ErrorReportingServiceForJira_Test.java similarity index 96% rename from modules/spi/errorrptjira/impl/src/test/java/org/incode/module/jira/impl/ErrorReportingServiceForJira_Test.java rename to modules/spi/errorrptjira/impl/src/test/java/org/incode/module/errorrptjira/impl/ErrorReportingServiceForJira_Test.java index 7c67251b9..f23a8dbb0 100644 --- a/modules/spi/errorrptjira/impl/src/test/java/org/incode/module/jira/impl/ErrorReportingServiceForJira_Test.java +++ b/modules/spi/errorrptjira/impl/src/test/java/org/incode/module/errorrptjira/impl/ErrorReportingServiceForJira_Test.java @@ -1,4 +1,4 @@ -package org.estatio.webapp.services.jira; +package org.incode.module.errorrptjira.impl; import java.util.Collections; import java.util.List; @@ -18,8 +18,6 @@ import org.apache.isis.viewer.wicket.ui.errors.ExceptionModel; import org.apache.isis.viewer.wicket.ui.errors.StackTraceDetail; -import org.incode.module.jira.impl.ErrorReportingServiceForJira; - import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.nullValue; diff --git a/modules/spi/errorrptslack/impl/src/main/java/org/incode/module/errorrptslack/ErrorReportingSlackModule.java b/modules/spi/errorrptslack/impl/src/main/java/org/incode/module/errorrptslack/ErrorReportingSlackModule.java new file mode 100644 index 000000000..2ed22b1e7 --- /dev/null +++ b/modules/spi/errorrptslack/impl/src/main/java/org/incode/module/errorrptslack/ErrorReportingSlackModule.java @@ -0,0 +1,24 @@ +package org.incode.module.errorrptslack; + +import java.util.Set; + +import javax.xml.bind.annotation.XmlRootElement; + +import com.google.common.collect.Sets; + +import org.apache.isis.applib.Module; +import org.apache.isis.applib.ModuleAbstract; + +import org.incode.module.slack.SlackModule; + +@XmlRootElement(name = "module") +public class ErrorReportingSlackModule extends ModuleAbstract { + + @Override + public Set getDependencies() { + return Sets.newHashSet( + new SlackModule() + ); + } + +} diff --git a/modules/spi/errorrptslack/impl/src/main/java/org/incode/module/slack/impl/ErrorReportingServiceForSlack.java b/modules/spi/errorrptslack/impl/src/main/java/org/incode/module/errorrptslack/impl/ErrorReportingServiceForSlack.java similarity index 98% rename from modules/spi/errorrptslack/impl/src/main/java/org/incode/module/slack/impl/ErrorReportingServiceForSlack.java rename to modules/spi/errorrptslack/impl/src/main/java/org/incode/module/errorrptslack/impl/ErrorReportingServiceForSlack.java index 7e3ee3b44..5dc0c34c0 100644 --- a/modules/spi/errorrptslack/impl/src/main/java/org/incode/module/slack/impl/ErrorReportingServiceForSlack.java +++ b/modules/spi/errorrptslack/impl/src/main/java/org/incode/module/errorrptslack/impl/ErrorReportingServiceForSlack.java @@ -1,4 +1,4 @@ -package org.incode.module.slack.impl; +package org.incode.module.errorrptslack.impl; import java.util.List; import java.util.Objects; @@ -30,6 +30,8 @@ import org.apache.isis.applib.services.user.UserService; import org.apache.isis.core.commons.config.IsisConfiguration; +import org.incode.module.slack.impl.SlackService; + import lombok.Setter; @DomainService(nature = NatureOfService.DOMAIN, menuOrder = "100") @@ -40,7 +42,7 @@ public class ErrorReportingServiceForSlack implements ErrorReportingService { private static final String CONFIG_KEY_PREFIX = "isis.service.errorReporting.slack."; private static final String USER_MESSAGE_DEFAULT = "Our apologies, an error has occurred. The development team has been notified (via the Slack messaging system)."; private static final String DETAILS_DEFAULT = - "The reference identifier below gives us more " + "Quote the reference below to point us to more " + "detailed information about the problem.\n" + "\n" + "In the meantime, and by way of an apology, \n" diff --git a/modules/spi/errorrptslack/impl/src/main/java/org/incode/module/slack/ErrorReportingSlackModule.java b/modules/spi/errorrptslack/impl/src/main/java/org/incode/module/slack/ErrorReportingSlackModule.java deleted file mode 100644 index 5b478e5c3..000000000 --- a/modules/spi/errorrptslack/impl/src/main/java/org/incode/module/slack/ErrorReportingSlackModule.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.incode.module.slack; - -import javax.xml.bind.annotation.XmlRootElement; - -import org.apache.isis.applib.ModuleAbstract; - -@XmlRootElement(name = "module") -public class ErrorReportingSlackModule extends ModuleAbstract { - -} diff --git a/modules/spi/errorrptslack/impl/src/test/java/org/incode/module/slack/impl/ErrorReportingServiceForSlack_Test.java b/modules/spi/errorrptslack/impl/src/test/java/org/incode/module/errorrptslack/impl/ErrorReportingServiceForSlack_Test.java similarity index 95% rename from modules/spi/errorrptslack/impl/src/test/java/org/incode/module/slack/impl/ErrorReportingServiceForSlack_Test.java rename to modules/spi/errorrptslack/impl/src/test/java/org/incode/module/errorrptslack/impl/ErrorReportingServiceForSlack_Test.java index d120a4ec3..b9ef33a14 100644 --- a/modules/spi/errorrptslack/impl/src/test/java/org/incode/module/slack/impl/ErrorReportingServiceForSlack_Test.java +++ b/modules/spi/errorrptslack/impl/src/test/java/org/incode/module/errorrptslack/impl/ErrorReportingServiceForSlack_Test.java @@ -1,4 +1,4 @@ -package org.incode.module.slack.impl; +package org.incode.module.errorrptslack.impl; import java.util.Collections; import java.util.List; @@ -7,6 +7,7 @@ import org.jmock.Expectations; import org.jmock.auto.Mock; import org.junit.Assert; +import org.junit.Assume; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -17,10 +18,11 @@ import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2; import org.apache.isis.viewer.wicket.ui.errors.ExceptionModel; +import org.incode.module.slack.impl.SlackService; + import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assume.assumeTrue; /** * run using: @@ -60,7 +62,7 @@ private void allowingGetStringReturnSystemProperty(final String property) { errorReportingService.init(); final boolean initialized = errorReportingService.isInitialized(); - assumeTrue(initialized); + Assume.assumeTrue(initialized); } public static class reportError extends ErrorReportingServiceForSlack_Test { diff --git a/modules/spi/security/impl/src/main/java/org/isisaddons/module/security/SecurityModule.java b/modules/spi/security/impl/src/main/java/org/isisaddons/module/security/SecurityModule.java index 5f367f39c..ee283415a 100644 --- a/modules/spi/security/impl/src/main/java/org/isisaddons/module/security/SecurityModule.java +++ b/modules/spi/security/impl/src/main/java/org/isisaddons/module/security/SecurityModule.java @@ -1,8 +1,11 @@ package org.isisaddons.module.security; -public final class SecurityModule { +import javax.xml.bind.annotation.XmlRootElement; - private SecurityModule(){} +import org.apache.isis.applib.ModuleAbstract; + +@XmlRootElement(name = "module") +public class SecurityModule extends ModuleAbstract { public abstract static class ActionDomainEvent extends org.apache.isis.applib.services.eventbus.ActionDomainEvent { } diff --git a/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/UserImpersonateModule.java b/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/UserImpersonateModule.java index 3c8295c62..635995344 100644 --- a/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/UserImpersonateModule.java +++ b/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/UserImpersonateModule.java @@ -1,12 +1,26 @@ package org.incode.module.userimpersonate; +import java.util.Set; + import javax.xml.bind.annotation.XmlRootElement; +import com.google.common.collect.Sets; + +import org.apache.isis.applib.Module; import org.apache.isis.applib.ModuleAbstract; +import org.isisaddons.module.security.SecurityModule; +import org.isisaddons.module.servletapi.ServletApiModule; + @XmlRootElement(name = "module") public class UserImpersonateModule extends ModuleAbstract { + @Override public Set getDependencies() { + return Sets.newHashSet( + new SecurityModule(), + new ServletApiModule() + ); + } //region > ui event classes public abstract static class TitleUiEvent diff --git a/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/app/ImpersonateMenu.java b/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/app/ImpersonateMenu.java index bdbeac454..cf52baa91 100644 --- a/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/app/ImpersonateMenu.java +++ b/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/app/ImpersonateMenu.java @@ -20,7 +20,6 @@ import org.isisaddons.module.security.dom.user.ApplicationUser; import org.incode.module.userimpersonate.UserImpersonateModule; -import org.incode.module.userimpersonate.contributions.Object_impersonateUser; @DomainService( nature = NatureOfService.VIEW_MENU_ONLY, @@ -33,7 +32,7 @@ public class ImpersonateMenu { public static class ImpersonateDomainEvent - extends UserImpersonateModule.ActionDomainEvent {} + extends UserImpersonateModule.ActionDomainEvent {} @Action( domainEvent = ImpersonateDomainEvent.class, @@ -61,7 +60,7 @@ public boolean hideImpersonate() { public static class StopImpersonatingDomainEvent - extends UserImpersonateModule.ActionDomainEvent {} + extends UserImpersonateModule.ActionDomainEvent {} @Action( domainEvent = StopImpersonatingDomainEvent.class, diff --git a/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/contributions/Object_stopImpersonating.java b/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/contributions/Object_stopImpersonating.java index 63efa88ea..cbe1c9438 100644 --- a/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/contributions/Object_stopImpersonating.java +++ b/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/contributions/Object_stopImpersonating.java @@ -21,7 +21,7 @@ public Object_stopImpersonating(final Object object) { } public static class ActionDomainEvent - extends UserImpersonateModule.ActionDomainEvent {} + extends UserImpersonateModule.ActionDomainEvent {} @Action( domainEvent = ActionDomainEvent.class, diff --git a/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/impl/UserServiceWithImpersonation.java b/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/impl/UserServiceWithImpersonation.java index f0abfc3d2..b4aca7858 100644 --- a/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/impl/UserServiceWithImpersonation.java +++ b/modules/spi/userimpersonate/impl/src/main/java/org/incode/module/userimpersonate/impl/UserServiceWithImpersonation.java @@ -57,23 +57,29 @@ public boolean isImpersonating() { @Programmatic public boolean isAvailable() { - return httpSessionProvider.getHttpSession().isPresent(); + return httpSessionProvider != null && httpSessionProvider.getHttpSession().isPresent(); } - private UserService delegateUserService; private UserService delegateUserService() { if (delegateUserService == null) { + // there will always be at least one other user service, namely UserServiceDefault provided by the framework itself delegateUserService = userServiceList.stream().filter(x -> x != UserServiceWithImpersonation.this).findFirst().get(); } return delegateUserService; } private Optional getImpersonatedUserIfAny() { - return httpSessionProvider.getAttribute(HTTP_SESSION_KEY, UserMemento.class); + if(!isAvailable()) { + return Optional.empty(); + } + return httpSessionProvider.getAttribute(HTTP_SESSION_KEY, UserMemento.class); } private void setImpersonatedUser(UserMemento overrideUser) { + if(!isAvailable()) { + return; + } httpSessionProvider.setAttribute(HTTP_SESSION_KEY, overrideUser); }