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 2021/06/24 12:48:39 UTC

[isis] branch master updated: ISIS-2761: introduces a ObjectIconService to be shared among all viewers

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


The following commit(s) were added to refs/heads/master by this push:
     new cd59ac3  ISIS-2761: introduces a ObjectIconService to be shared among all viewers
cd59ac3 is described below

commit cd59ac36ef38f1aeaa72c778f07265e957fbffeb
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Jun 24 14:48:26 2021 +0200

    ISIS-2761: introduces a ObjectIconService to be shared among all viewers
---
 .../isis/applib/value/NamedWithMimeType.java       |  16 +-
 .../isis/commons/internal/resources/_DataSink.java |  20 +-
 .../commons/internal/resources/_DataSource.java    | 139 ++++++++
 .../services/userprof/UserProfileUiModel.java      |   2 +
 .../common/model/IsisModuleViewerCommon.java       |   2 +
 .../common/model/decorator/icon/ObjectIcon.java    |  53 +++
 .../model/decorator/icon/ObjectIconService.java    |  51 +++
 .../decorator/icon/ObjectIconServiceDefault.java   | 177 ++++++++++
 .../model/decorator/icon/ObjectIconFallback.png}   | Bin
 .../viewer/restfulobjects/rendering/Responses.java |   4 +-
 .../resources/DomainObjectResourceServerside.java  |  25 +-
 .../viewer/resources/_DomainObjectIcons.java       |  74 ----
 .../services/ImageResourceCacheClassPath.java      | 285 ++++-----------
 .../viewer/services/ImageResourceCacheKeyTest.java | 386 ++++++++++-----------
 14 files changed, 715 insertions(+), 519 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/value/NamedWithMimeType.java b/api/applib/src/main/java/org/apache/isis/applib/value/NamedWithMimeType.java
index 263fa14..81ba3b9 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/value/NamedWithMimeType.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/value/NamedWithMimeType.java
@@ -150,18 +150,20 @@ public interface NamedWithMimeType extends Serializable {
 
         ;
 
-        private CommonMimeType(String primaryType, String ... additionalProposedFileExtension) {
+        private CommonMimeType(final String primaryType, final String ... additionalProposedFileExtension) {
             this.mimeType = newMimeType(primaryType);
             this.proposedFileExtensions = Can.ofSingleton(name().toLowerCase())
                     .addAll(Can.ofArray(additionalProposedFileExtension));
         }
 
-        @Getter
-        final MimeType mimeType;
-        @Getter
-        final Can<String> proposedFileExtensions;
+        @Getter final MimeType mimeType;
+        @Getter final Can<String> proposedFileExtensions;
 
-        static MimeType newMimeType(String primaryType, String subtype) {
+        public String getBaseType() {
+            return getMimeType().getBaseType();
+        }
+
+        static MimeType newMimeType(final String primaryType, final String subtype) {
             try {
                 return new MimeType(primaryType, subtype);
             } catch (MimeTypeParseException e) {
@@ -169,7 +171,7 @@ public interface NamedWithMimeType extends Serializable {
             }
         }
 
-        static MimeType newMimeType(String baseType) {
+        static MimeType newMimeType(final String baseType) {
             try {
                 return new MimeType(baseType);
             } catch (MimeTypeParseException e) {
diff --git a/viewers/wicket/ui/src/main/java/images/Images.java b/commons/src/main/java/org/apache/isis/commons/internal/resources/_DataSink.java
similarity index 66%
rename from viewers/wicket/ui/src/main/java/images/Images.java
rename to commons/src/main/java/org/apache/isis/commons/internal/resources/_DataSink.java
index f1e6fb0..d949541 100644
--- a/viewers/wicket/ui/src/main/java/images/Images.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/resources/_DataSink.java
@@ -16,18 +16,20 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
+package org.apache.isis.commons.internal.resources;
 
-package images;
-
-import org.apache.wicket.request.resource.PackageResource;
+import java.io.InputStream;
+import java.util.function.Consumer;
 
 /**
- * This is a bit of a hack, but the Isis convention is to plonk all the images
- * in an images package. This empty class allows Wicket to pick them up as
- * {@link PackageResource}s.
+ * <h1>- internal use only -</h1>
+ * Data Sink (as opposed to Data Source)
+ * <p>
+ * <b>WARNING</b>: Do <b>NOT</b> use any of the classes provided by this package! <br/>
+ * These may be changed or removed without notice!
+ * </p>
+ * @since 2.0
  */
-public final class Images {
+public interface _DataSink extends Consumer<InputStream>  {
 
-    private Images() {
-    }
 }
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/resources/_DataSource.java b/commons/src/main/java/org/apache/isis/commons/internal/resources/_DataSource.java
new file mode 100644
index 0000000..5c6102b
--- /dev/null
+++ b/commons/src/main/java/org/apache/isis/commons/internal/resources/_DataSource.java
@@ -0,0 +1,139 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.commons.internal.resources;
+
+import java.io.InputStream;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.isis.commons.internal._Constants;
+import org.apache.isis.commons.internal.base._Bytes;
+import org.apache.isis.commons.internal.context._Context;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+
+import lombok.NonNull;
+import lombok.SneakyThrows;
+import lombok.Value;
+import lombok.val;
+
+/**
+ * <h1>- internal use only -</h1>
+ * Data Source (as opposed to Data Sink)
+ * <p>
+ * <b>WARNING</b>: Do <b>NOT</b> use any of the classes provided by this package! <br/>
+ * These may be changed or removed without notice!
+ * </p>
+ * @since 2.0
+ */
+public interface _DataSource extends Supplier<InputStream>  {
+
+    // -- INTERFACE
+
+    /**
+     * Can be used as the key, when collecting {@link _DataSource}(s) into a {@link Map}.
+     */
+    Serializable identifier();
+
+    default byte[] asBytes() {
+        try(val is = get()){
+            return _Bytes.of(is);
+        } catch (Exception e) {
+            return _Constants.emptyBytes;
+        }
+    }
+
+    // -- UTILITIES
+
+    default boolean isPresent() {
+        try(val is = get()){
+            return is!=null;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    // -- FACTORIES
+
+    static _DataSource classPathResource(
+            final @NonNull Class<?> contextClass,
+            final @NonNull String resourceName) {
+
+        @Value
+        class Key implements Serializable {
+            private static final long serialVersionUID = 1L;
+
+            final @NonNull Class<?> contextClass;
+            final @NonNull String resourceName;
+        }
+
+        val key = new Key(contextClass, resourceName);
+
+        return new _DataSource() {
+
+            @Override
+            public Serializable identifier() {
+                return key;
+            }
+
+            @Override
+            public InputStream get() {
+                return _Resources.load(contextClass, resourceName);
+            }
+
+        };
+    }
+
+    static _DataSource classPathResource(
+            final @NonNull URL resourceUrl) {
+
+        return new _DataSource() {
+
+            @Override
+            public Serializable identifier() {
+                return resourceUrl;
+            }
+
+            @Override @SneakyThrows
+            public InputStream get() {
+                return resourceUrl.openStream();
+            }
+
+        };
+    }
+
+    static _DataSource classPathResource(
+            final @NonNull String absoluteResourceName) {
+        if(!absoluteResourceName.startsWith("/")) {
+            throw _Exceptions
+            .illegalArgument("invalid absoluteResourceName %s", absoluteResourceName);
+        }
+
+        val resourceUrl = _Context.getDefaultClassLoader().getResource(absoluteResourceName);
+        if(resourceUrl==null) {
+            throw _Exceptions
+            .noSuchElement("resource not found %s", absoluteResourceName);
+        }
+
+        return classPathResource(resourceUrl);
+
+    }
+
+}
diff --git a/viewers/common/src/main/java/org/apache/isis/viewer/common/applib/services/userprof/UserProfileUiModel.java b/viewers/common/src/main/java/org/apache/isis/viewer/common/applib/services/userprof/UserProfileUiModel.java
index 728ecf2..26a2cc4 100644
--- a/viewers/common/src/main/java/org/apache/isis/viewer/common/applib/services/userprof/UserProfileUiModel.java
+++ b/viewers/common/src/main/java/org/apache/isis/viewer/common/applib/services/userprof/UserProfileUiModel.java
@@ -40,6 +40,8 @@ import lombok.NoArgsConstructor;
 @NoArgsConstructor
 public class UserProfileUiModel implements Serializable {
 
+    private static final long serialVersionUID = 1L;
+
     /**
      * Returns an alternate name for the current user, typically for use on the
      * viewer's menu bar to identify the currently logged in user.
diff --git a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/IsisModuleViewerCommon.java b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/IsisModuleViewerCommon.java
index 507a7e1..a7ed0d6 100644
--- a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/IsisModuleViewerCommon.java
+++ b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/IsisModuleViewerCommon.java
@@ -25,6 +25,7 @@ import org.apache.isis.viewer.common.applib.mixins.Object_impersonate;
 import org.apache.isis.viewer.common.applib.mixins.Object_impersonateWithRoles;
 import org.apache.isis.viewer.common.applib.mixins.Object_stopImpersonating;
 import org.apache.isis.viewer.common.model.branding.BrandingUiModelProvider;
+import org.apache.isis.viewer.common.model.decorator.icon.ObjectIconServiceDefault;
 import org.apache.isis.viewer.common.model.header.HeaderUiModelProvider;
 import org.apache.isis.viewer.common.model.menu.MenuUiModelProvider;
 import org.apache.isis.viewer.common.model.userprofile.UserProfileUiModelProviderDefault;
@@ -37,6 +38,7 @@ import org.apache.isis.viewer.common.model.userprofile.UserProfileUiModelProvide
     UserProfileUiModelProviderDefault.class,
     MenuUiModelProvider.class,
     HeaderUiModelProvider.class,
+    ObjectIconServiceDefault.class,
 
     // @Mixin's
     Object_impersonate.class,
diff --git a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/decorator/icon/ObjectIcon.java b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/decorator/icon/ObjectIcon.java
new file mode 100644
index 0000000..9408030
--- /dev/null
+++ b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/decorator/icon/ObjectIcon.java
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.viewer.common.model.decorator.icon;
+
+import java.io.InputStream;
+import java.io.Serializable;
+import java.net.URL;
+
+import org.apache.isis.applib.value.NamedWithMimeType.CommonMimeType;
+import org.apache.isis.commons.internal._Constants;
+import org.apache.isis.commons.internal.base._Bytes;
+import org.apache.isis.commons.internal.base._Strings;
+
+import lombok.Getter;
+
+@lombok.Value
+public class ObjectIcon
+implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String shortName;
+    private URL url;
+    private CommonMimeType mimeType;
+
+    @Getter(lazy = true)
+    private String identifier = _Strings.base64UrlEncode(getUrl().getPath());
+
+    public byte[] asBytes() {
+        try(final InputStream is = url.openStream()){
+            return _Bytes.of(is);
+        } catch (Exception e) {
+            return _Constants.emptyBytes;
+        }
+    }
+
+}
diff --git a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/decorator/icon/ObjectIconService.java b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/decorator/icon/ObjectIconService.java
new file mode 100644
index 0000000..bd97e62
--- /dev/null
+++ b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/decorator/icon/ObjectIconService.java
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.viewer.common.model.decorator.icon;
+
+import javax.annotation.Nullable;
+
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+import lombok.NonNull;
+
+public interface ObjectIconService {
+
+    ObjectIcon getObjectIcon(
+            @NonNull ObjectSpecification specification,
+            @Nullable String iconNameIfAny);
+
+    ObjectIcon getObjectFallbackIcon();
+
+    // -- SHORTCUTS
+
+    default ObjectIcon getObjectIcon(final ObjectSpecification spec) {
+        return getObjectIcon(spec, null);
+    }
+
+    default ObjectIcon getObjectIcon(final ManagedObject adapter) {
+        return ManagedObjects.isSpecified(adapter)
+                ? getObjectIcon(
+                        adapter.getSpecification(),
+                        adapter.getSpecification().getIconName(adapter))
+                : getObjectFallbackIcon();
+    }
+
+}
diff --git a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/decorator/icon/ObjectIconServiceDefault.java b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/decorator/icon/ObjectIconServiceDefault.java
new file mode 100644
index 0000000..a8a7cc7
--- /dev/null
+++ b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/decorator/icon/ObjectIconServiceDefault.java
@@ -0,0 +1,177 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.viewer.common.model.decorator.icon;
+
+import java.net.URL;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.annotation.Nullable;
+import javax.annotation.Priority;
+import javax.inject.Named;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+import org.apache.isis.applib.annotation.PriorityPrecedence;
+import org.apache.isis.applib.value.NamedWithMimeType.CommonMimeType;
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.internal.base._Strings;
+import org.apache.isis.commons.internal.collections._Maps;
+import org.apache.isis.commons.internal.context._Context;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.commons.internal.resources._Resources;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+import lombok.NonNull;
+import lombok.val;
+
+@Service
+@Named("isis.viewer.common.ObjectIconServiceDefault")
+@Priority(PriorityPrecedence.LATE)
+@Qualifier("Default")
+//@RequiredArgsConstructor(onConstructor_ = {@Inject})
+public class ObjectIconServiceDefault
+implements ObjectIconService {
+
+    private static final String DEFAULT_IMAGE_RESOURCE_PATH = "/images";
+    private static final Can<CommonMimeType> IMAGE_TYPES =
+            Can.of(
+                CommonMimeType.PNG,
+                CommonMimeType.GIF,
+                CommonMimeType.JPEG,
+                CommonMimeType.SVG);
+
+    private final Map<String, ObjectIcon> iconByKey = _Maps.newConcurrentHashMap();
+
+    private final ObjectIcon fallbackIcon =
+            new ObjectIcon(
+                    "ObjectIconFallback",
+                    _Resources.getResourceUrl(
+                            ObjectIconServiceDefault.class,
+                            "ObjectIconFallback.png"),
+                    CommonMimeType.PNG);
+
+
+    @Override
+    public ObjectIcon getObjectIcon(
+            final @NonNull ObjectSpecification spec,
+            final @Nullable String iconNameModifier) {
+
+        val domainClass = spec.getCorrespondingClass();
+        val iconResourceKey = _Strings.isNotEmpty(iconNameModifier)
+                ? domainClass.getName() + "-" + iconNameModifier
+                : domainClass.getName();
+
+        // also memoize unsuccessful icon lookups, so we don't search repeatedly
+        return iconByKey.computeIfAbsent(iconResourceKey, key->
+            findIcon(spec, iconNameModifier));
+    }
+
+    @Override
+    public ObjectIcon getObjectFallbackIcon() {
+        return fallbackIcon;
+    }
+
+    // -- HELPER
+
+    private ObjectIcon findIcon(
+            final @NonNull ObjectSpecification spec,
+            final @Nullable String iconNameModifier) {
+
+        val domainClass = spec.getCorrespondingClass();
+        val iconResourceNameNoExt = _Strings.isNotEmpty(iconNameModifier)
+                ? domainClass.getSimpleName() + "-" + iconNameModifier
+                : domainClass.getSimpleName();
+
+        for(val imageType : IMAGE_TYPES) {
+
+            val objectIcon1 = imageType
+                .getProposedFileExtensions()
+                .stream()
+                .map(suffix->iconResourceNameNoExt + "." + suffix)
+                .map(iconResourceName->
+                        classPathResource(domainClass, iconResourceName)
+                        .map(url->new ObjectIcon(
+                                iconResourceNameNoExt,
+                                url,
+                                imageType)))
+                .filter(Optional::isPresent)
+                .map(Optional::get)
+                .findFirst();
+
+            if(objectIcon1.isPresent()) {
+                return objectIcon1.get(); // short-circuit if found
+            }
+
+            // also search the default image resource path
+
+            val objectIcon2 = imageType
+                    .getProposedFileExtensions()
+                    .stream()
+                    .map(suffix->DEFAULT_IMAGE_RESOURCE_PATH + "/" + iconResourceNameNoExt + "." + suffix)
+                    .map(iconResourcePath->
+                            classPathResource(iconResourcePath)
+                            .map(url->new ObjectIcon(
+                                    iconResourceNameNoExt,
+                                    url,
+                                    imageType)))
+                    .filter(Optional::isPresent)
+                    .map(Optional::get)
+                    .findFirst();
+
+            if(objectIcon2.isPresent()) {
+                return objectIcon2.get(); // short-circuit if found
+            }
+
+        }
+
+        return spec.superclass()!=null
+                // continue search in super spec
+                ? getObjectIcon(spec.superclass(), iconNameModifier) // memoizes as a side-effect
+                : _Strings.isNotEmpty(iconNameModifier)
+                        // also do a more generic search, skipping the modifier
+                        ? getObjectIcon(spec, null) // memoizes as a side-effect
+                        : getObjectFallbackIcon();
+    }
+
+    // -- HELPER
+
+    private static Optional<URL> classPathResource(
+            final @NonNull String absoluteResourceName) {
+        if(!absoluteResourceName.startsWith("/")) {
+            throw _Exceptions
+            .illegalArgument("invalid absolute resourceName %s", absoluteResourceName);
+        }
+        val resourceUrl = _Context.getDefaultClassLoader().getResource(absoluteResourceName);
+        return Optional.ofNullable(resourceUrl);
+    }
+
+    private static Optional<URL> classPathResource(
+            final @NonNull Class<?> contextClass,
+            final @NonNull String relativeResourceName) {
+        if(relativeResourceName.startsWith("/")) {
+            throw _Exceptions
+            .illegalArgument("invalid relative resourceName %s", relativeResourceName);
+        }
+        val resourceUrl = _Resources.getResourceUrl(contextClass, relativeResourceName);
+        return Optional.ofNullable(resourceUrl);
+    }
+
+}
diff --git a/viewers/wicket/ui/src/main/resources/images/Default.png b/viewers/common/src/main/resources/org/apache/isis/viewer/common/model/decorator/icon/ObjectIconFallback.png
similarity index 100%
rename from viewers/wicket/ui/src/main/resources/images/Default.png
rename to viewers/common/src/main/resources/org/apache/isis/viewer/common/model/decorator/icon/ObjectIconFallback.png
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/Responses.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/Responses.java
index 019aca8..ded48b9 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/Responses.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/Responses.java
@@ -86,7 +86,7 @@ public final class Responses {
         return response;
     }
 
-    private static Date now(ReprRenderer<?, ?> renderer) {
+    private static Date now(final ReprRenderer<?, ?> renderer) {
         if(renderer instanceof ReprRendererAbstract) {
             ((ReprRendererAbstract<?, ?>)renderer).getResourceContext().getMetaModelContext().getServiceRegistry()
             .lookupServiceElseFail(ClockService.class).getClock().javaUtilDate();
@@ -105,7 +105,7 @@ public final class Responses {
         return responseBuilder;
     }
 
-    public static JsonMapper.PrettyPrinting inferPrettyPrinting(ReprRenderer<?, ?> renderer) {
+    public static JsonMapper.PrettyPrinting inferPrettyPrinting(final ReprRenderer<?, ?> renderer) {
 
         if(renderer instanceof ReprRendererAbstract) {
             val systemEnvironment =  ((ReprRendererAbstract<?, ?>) renderer).getResourceContext()
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
index 26d8fc8..f4ca6f7 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
@@ -56,6 +56,8 @@ import org.apache.isis.core.metamodel.interactions.managed.MemberInteraction.Acc
 import org.apache.isis.core.metamodel.interactions.managed.PropertyInteraction;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ManagedObjects.EntityUtil;
+import org.apache.isis.viewer.common.model.decorator.icon.ObjectIcon;
+import org.apache.isis.viewer.common.model.decorator.icon.ObjectIconService;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
@@ -69,6 +71,7 @@ import org.apache.isis.viewer.restfulobjects.rendering.service.RepresentationSer
 import org.apache.isis.viewer.restfulobjects.rendering.util.Util;
 import org.apache.isis.viewer.restfulobjects.viewer.context.ResourceContext;
 
+import lombok.NonNull;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
@@ -76,12 +79,16 @@ import lombok.extern.log4j.Log4j2;
 @Path("/objects") @Log4j2
 public class DomainObjectResourceServerside extends ResourceAbstract implements DomainObjectResource {
 
+    private final ObjectIconService objectIconService;
+
     @Inject
     public DomainObjectResourceServerside(
             final MetaModelContext metaModelContext,
             final IsisConfiguration isisConfiguration,
+            final ObjectIconService objectIconService,
             final InteractionLayerTracker iInteractionLayerTracker) {
         super(metaModelContext, isisConfiguration, iInteractionLayerTracker);
+        this.objectIconService = objectIconService;
         log.debug("<init>");
     }
 
@@ -225,7 +232,11 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
     @Path("/{domainType}/{instanceId}/object-icon")
     @Consumes({ MediaType.WILDCARD })
     @Produces({
-        "image/png"
+        "image/png",
+        "image/gif",
+        "image/jpeg",
+        "image/jpg",
+        "image/svg+xml"
     })
     public Response image(
             @PathParam("domainType")
@@ -237,13 +248,19 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
 //                RepresentationType.OBJECT_ICON, Where.ANYWHERE, RepresentationService.Intent.NOT_APPLICABLE);
 
         val objectAdapter = getObjectAdapterElseThrowNotFound(domainType, instanceId);
+        val objectIcon = objectIconService.getObjectIcon(objectAdapter);
 
-        return _DomainObjectIcons.loadIcon(objectAdapter)
-            .map(Response::ok)
-            .orElseGet(Responses::ofNotFound)
+        return Response.ok(
+                objectIcon.asBytes(),
+                objectIcon.getMimeType().getBaseType())
             .build();
     }
 
+    public Response.ResponseBuilder objectIconResponse(
+            final @NonNull ObjectIcon objectIcon) {
+        return Response.ok();
+    }
+
     @Override
     @GET
     @Path("/{domainType}/{instanceId}/object-layout")
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/_DomainObjectIcons.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/_DomainObjectIcons.java
deleted file mode 100644
index 1efafef..0000000
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/_DomainObjectIcons.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.viewer.restfulobjects.viewer.resources;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Optional;
-
-import javax.annotation.Nullable;
-
-import org.apache.isis.commons.internal.base._Bytes;
-import org.apache.isis.commons.internal.base._Strings;
-import org.apache.isis.commons.internal.resources._Resources;
-import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.ManagedObjects;
-
-import lombok.val;
-import lombok.experimental.UtilityClass;
-
-@UtilityClass
-class _DomainObjectIcons {
-
-    public Optional<byte[]> loadIcon(
-            final @Nullable ManagedObject object) {
-
-        if(ManagedObjects.isNullOrUnspecifiedOrEmpty(object)) {
-            return Optional.empty();
-        }
-
-        val spec = object.getSpecification();
-
-        return Optional.ofNullable(
-                loadIcon(
-                        spec.getCorrespondingClass(),
-                        spec.getIconName(object)
-                        ));
-    }
-
-    //TODO[2761] that's a naive implementation; refactor the Wicket Viewer's icon resolving logic into a reusable utility or service
-    private byte[] loadIcon(
-            final Class<?> domainClass,
-            final String iconNameModifier) {
-
-        val iconResourceName = _Strings.isNotEmpty(iconNameModifier)
-                ? domainClass.getSimpleName() + "-" + iconNameModifier
-                : domainClass.getSimpleName();
-
-        try {
-            final InputStream resource = _Resources
-                    .load(domainClass, iconResourceName + ".png");
-            return _Bytes.of(resource);
-
-        } catch (IOException e) {
-            return null;
-        }
-    }
-
-}
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/ImageResourceCacheClassPath.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/ImageResourceCacheClassPath.java
index d93d20f..04108cf 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/ImageResourceCacheClassPath.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/ImageResourceCacheClassPath.java
@@ -18,37 +18,36 @@
  */
 package org.apache.isis.viewer.wicket.viewer.services;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Serializable;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
+import java.io.ByteArrayInputStream;
 
 import javax.annotation.Priority;
+import javax.inject.Inject;
 import javax.inject.Named;
 
-import org.apache.wicket.request.resource.PackageResourceReference;
+import org.apache.wicket.Application;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.resource.AbstractResource;
+import org.apache.wicket.request.resource.IResource;
+import org.apache.wicket.request.resource.PartWriterCallback;
 import org.apache.wicket.request.resource.ResourceReference;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.PriorityPrecedence;
-import org.apache.isis.commons.internal.collections._Lists;
-import org.apache.isis.commons.internal.collections._Maps;
-import org.apache.isis.core.metamodel.commons.ClassUtil;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.metamodel.spec.Specification;
+import org.apache.isis.viewer.common.model.decorator.icon.ObjectIcon;
+import org.apache.isis.viewer.common.model.decorator.icon.ObjectIconService;
 import org.apache.isis.viewer.wicket.model.models.ImageResourceCache;
 
-import images.Images;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import lombok.val;
+
 
 /**
- * Caches images loaded either from the same package as the specified object, or from the <tt>images</tt> package (using the {@link Images} otherwise.
- * class).
- *
+ * Caches images loaded either from the same package as the specified object,
+ * or from the <tt>images</tt> package otherwise.
  * <p>
  * Searches for a fixed set of suffixes: <code>png, gif, jpeg, jpg, svg</code>.
  */
@@ -56,244 +55,80 @@ import images.Images;
 @Named("isis.viewer.wicket.ImageResourceCacheClassPath")
 @Priority(PriorityPrecedence.MIDPOINT)
 @Qualifier("ClassPath")
-public class ImageResourceCacheClassPath implements ImageResourceCache {
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
+public class ImageResourceCacheClassPath
+implements ImageResourceCache {
 
     private static final long serialVersionUID = 1L;
 
-    private static final List<String> IMAGE_SUFFICES = Arrays.asList("png", "gif", "jpeg", "jpg", "svg");
-    private static final String FALLBACK_IMAGE = "Default.png";
-
-    private final Map<ImageResourceCacheKey, ResourceReference> resourceReferenceByKey = _Maps.newConcurrentHashMap();
-    private final PackageResourceReference fallbackResource;
-
-    public ImageResourceCacheClassPath() {
-        fallbackResource = new PackageResourceReference(Images.class, FALLBACK_IMAGE);
-        resourceReferenceByKey.put(new ImageResourceCacheKey(null, null), fallbackResource);
-    }
+    private final ObjectIconService objectIconService;
 
     @Override
     public ResourceReference resourceReferenceFor(final ManagedObject adapter) {
-        final Specification spec = adapter.getSpecification();
-        if(spec!=null && spec instanceof ObjectSpecification) {
-            final ObjectSpecification objSpec = (ObjectSpecification) spec;
-            return resourceReferenceFor(objSpec, objSpec.getIconName(adapter));
-        } else {
-            return fallbackResource;
-        }
-
+        val objectIcon = objectIconService.getObjectIcon(adapter);
+        return resourceReferenceForObjectIcon(objectIcon);
     }
 
     @Override
     public ResourceReference resourceReferenceForSpec(final ObjectSpecification spec) {
-        return resourceReferenceFor(spec, null);
+        val objectIcon = objectIconService.getObjectIcon(spec);
+        return resourceReferenceForObjectIcon(objectIcon);
     }
 
-    private ResourceReference resourceReferenceFor(
-            final ObjectSpecification specification,
-            final String iconNameIfAny) {
-
-        final Class<?> correspondingClassIfAny = specification != null? specification.getCorrespondingClass(): null;
-        final ImageResourceCacheKey key = new ImageResourceCacheKey(correspondingClassIfAny, iconNameIfAny);
+    // -- HELPER
 
-        ResourceReference resourceReference = resourceReferenceByKey.get(key);
-        if(resourceReference == null) {
-            resourceReference = findResourceReferenceFor(key);
-            resourceReferenceByKey.put(key, resourceReference);
-        }
-
-        return resourceReference;
+    private ResourceReference resourceReferenceForObjectIcon(final ObjectIcon objectIcon) {
+        return new ObjectIconResourceReference(objectIcon);
     }
 
-    protected ResourceReference findResourceReferenceFor(final ImageResourceCacheKey key) {
-        final List<ImageResourceCacheKey> keys = key.resourcePaths(IMAGE_SUFFICES);
-        for (ImageResourceCacheKey resourceKey : keys) {
-            Class<?> resourceClass = resourceKey.getResourceClass();
-            if(resourceClass == null) {
-                resourceClass = Images.class;
-            }
-            final String iconName = resourceKey.getResourceName();
+    private static class ObjectIconResourceReference
+    extends ResourceReference {
 
-            final InputStream resourceAsStream = resourceClass.getResourceAsStream(iconName);
-            if (resourceAsStream != null) {
-                closeSafely(resourceAsStream);
-                return new PackageResourceReference(resourceClass, iconName);
-            }
-        }
-        return fallbackResource;
-    }
-
-    private static void closeSafely(InputStream resourceAsStream) {
-        try {
-            resourceAsStream.close();
-        } catch (IOException e) {
-            // ignore
-        }
-    }
+        private static final long serialVersionUID = 1L;
 
-    static final class ImageResourceCacheKey implements Serializable {
+        private final @NonNull ObjectIconResource objectIconResource;
 
-        ImageResourceCacheKey(
-                final Class<?> resourceClass,
-                final String resourceName) {
-            this.resourceName = resourceName;
-            this.resourceClass = resourceClass;
-            this.toString = calcToString();
+        public ObjectIconResourceReference(final ObjectIcon objectIcon) {
+            super(new Key(Application.class.getName(), objectIcon.getIdentifier(), null, null, null));
+            this.objectIconResource = new ObjectIconResource(objectIcon);
         }
 
-        // -- getResourceClass, getResourceName
-
-        private final Class<?> resourceClass;
-        private final String resourceName;
-
-        public final Class<?> getResourceClass() {
-            return resourceClass;
-        }
-
-        public final String getResourceName() {
-            return resourceName;
-        }
-
-
-        // -- superKey
-
-        ImageResourceCacheKey superKey() {
-            if(resourceClass == null) {
-                return null;
-            }
-            final Class<?> superclass = resourceClass.getSuperclass();
-            if(superclass == Object.class) {
-                return null;
-            }
-            return new ImageResourceCacheKey(superclass, resourceName);
-        }
-
-
-
-        // -- resourcePaths
-
-        List<ImageResourceCacheKey> resourcePaths(final String... suffices) {
-            return resourcePaths(Arrays.asList(suffices));
-        }
-
-        List<ImageResourceCacheKey> resourcePaths(final List<String> suffices) {
-
-            ImageResourceCacheKey key;
-            final List<ImageResourceCacheKey> resourcePaths = _Lists.newArrayList();
-
-
-            boolean generated = false;
-
-            if(resourceName != null) {
-
-                final Class<?> resourceClass = ClassUtil.forNameElseNull(resourceName);
-
-                if(resourceClass != null) {
-                    for (String suffix : suffices) {
-                        resourcePaths.add(new ImageResourceCacheKey(resourceClass, resourceClass.getSimpleName() + "." + suffix));
-                    }
-                    generated = true;
-                }
-            }
-
-            if(!generated && resourceClass != null) {
-                // with the iconName
-                if(resourceName != null) {
-                    key = this;
-                    do {
-                        for (String suffix : suffices) {
-                            resourcePaths.add(new ImageResourceCacheKey(key.getResourceClass(), key.getResourceClass().getSimpleName() + "-" + resourceName + "." + suffix));
-                        }
-                        for (String suffix : suffices) {
-                            resourcePaths.add(new ImageResourceCacheKey(key.getResourceClass(), resourceName + "." + suffix));
-                        }
-                    } while ((key = key.superKey()) != null);
-                    key = this;
-                    do {
-                        for (String suffix : suffices) {
-                            resourcePaths.add(new ImageResourceCacheKey(null, key.getResourceClass().getSimpleName() + "-" + resourceName + "." + suffix));
-                        }
-                    } while ((key = key.superKey()) != null);
-                    for (String suffix : suffices) {
-                        resourcePaths.add(new ImageResourceCacheKey(null, resourceName + "." + suffix));
-                    }
-                }
-
-                // without the iconName
-                key = this;
-                do {
-                    for (String suffix : suffices) {
-                        resourcePaths.add(new ImageResourceCacheKey(key.getResourceClass(), key.getResourceClass().getSimpleName() + "." + suffix));
-                    }
-                } while ((key = key.superKey()) != null);
-                key = this;
-                do {
-                    for (String suffix : suffices) {
-                        resourcePaths.add(new ImageResourceCacheKey(null, key.getResourceClass().getSimpleName() + "." + suffix));
-                    }
-                } while ((key = key.superKey()) != null);
-
-                generated = true;
-            }
-
-            if(!generated && resourceName != null) {
-
-                for (String suffix : suffices) {
-                    resourcePaths.add(new ImageResourceCacheKey(null, resourceName + "." + suffix));
-                }
-
-            }
-
-            // fallback
-            for (String suffix : suffices) {
-                resourcePaths.add(new ImageResourceCacheKey(null, "Default" + "." + suffix));
-            }
-
-
-            return Collections.unmodifiableList(resourcePaths);
-        }
-
-
-
-        // -- equals, hashCode
-
         @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-            ImageResourceCacheKey key = (ImageResourceCacheKey) o;
-            if (toString != null ? !toString.equals(key.toString) : key.toString != null) return false;
-            return true;
-        }
-
-        @Override
-        public int hashCode() {
-            return toString != null ? toString.hashCode() : 0;
+        public IResource getResource() {
+            return objectIconResource;
         }
 
+    }
 
+    @RequiredArgsConstructor
+    private static class ObjectIconResource
+    extends AbstractResource {
 
-        // -- toString
+        private static final long serialVersionUID = 1L;
 
-        private final String toString;
+        private final @NonNull ObjectIcon objectIcon;
 
         @Override
-        public String toString() {
-            return toString;
-        }
-
-        private String calcToString() {
-            final StringBuilder buf = new StringBuilder();
-            if(resourceClass != null) {
-                buf.append(resourceClass.getName()).append("/").append(resourceClass.getSimpleName());
-            }
-            if(buf.length() > 0) {
-                buf.append("-");
-            }
-            if(resourceName != null) {
-                buf.append(resourceName);
-            }
-            return buf.toString();
+        protected ResourceResponse newResourceResponse(final Attributes attributes) {
+
+            val imageDataBytes = objectIcon.asBytes();
+            final long size = imageDataBytes.length;
+            ResourceResponse resourceResponse = new ResourceResponse();
+            resourceResponse.setContentType(objectIcon.getMimeType().getBaseType());
+            resourceResponse.setAcceptRange(ContentRangeType.BYTES);
+            resourceResponse.setContentLength(size);
+            resourceResponse.setFileName(objectIcon.getShortName());
+            RequestCycle cycle = RequestCycle.get();
+            Long startbyte = cycle.getMetaData(CONTENT_RANGE_STARTBYTE);
+            Long endbyte = cycle.getMetaData(CONTENT_RANGE_ENDBYTE);
+            resourceResponse.setWriteCallback(
+                new PartWriterCallback(
+                        new ByteArrayInputStream(imageDataBytes),
+                        size, startbyte, endbyte)
+                .setClose(true));
+            return resourceResponse;
         }
 
     }
+
 }
diff --git a/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/services/ImageResourceCacheKeyTest.java b/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/services/ImageResourceCacheKeyTest.java
index 92b0d970..8256271 100644
--- a/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/services/ImageResourceCacheKeyTest.java
+++ b/viewers/wicket/viewer/src/test/java/org/apache/isis/viewer/wicket/viewer/services/ImageResourceCacheKeyTest.java
@@ -18,205 +18,195 @@
  */
 package org.apache.isis.viewer.wicket.viewer.services;
 
-import java.util.Iterator;
-import java.util.List;
-
-import org.junit.Test;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.hamcrest.MatcherAssert.assertThat;
-
 public class ImageResourceCacheKeyTest {
 
-    ImageResourceCacheClassPath.ImageResourceCacheKey key;
-
-    public static class SomeSuperclass {
-    }
-
-    public static class SomeSubclass extends SomeSuperclass {
-    }
-
-    public static class SomeOtherContextClass extends SomeSuperclass {
-    }
-
-
-    public static class SuperKey extends ImageResourceCacheKeyTest {
-
-        @Test
-        public void whenSubclass() throws Exception {
-
-            key = new ImageResourceCacheClassPath.ImageResourceCacheKey(SomeSubclass.class, "foo");
-            final ImageResourceCacheClassPath.ImageResourceCacheKey superKey = key.superKey();
-
-            assertEquals(SomeSuperclass.class, superKey.getResourceClass());
-            assertEquals("foo", key.getResourceName());
-        }
-
-        @Test
-        public void whenSuperClass() throws Exception {
-
-            key = new ImageResourceCacheClassPath.ImageResourceCacheKey(SomeSuperclass.class, null);
-            final ImageResourceCacheClassPath.ImageResourceCacheKey superKey = key.superKey();
-
-            assertNull(superKey);
-        }
-
-    }
-
-    public static class ResourcePaths extends ImageResourceCacheKeyTest {
-
-        @Test
-        public void withIconName() throws Exception {
-            key = new ImageResourceCacheClassPath.ImageResourceCacheKey(SomeSubclass.class, "foo");
-
-            final List<ImageResourceCacheClassPath.ImageResourceCacheKey> keys = key.resourcePaths("png", "jpg", "jpeg");
-
-            final Iterator<ImageResourceCacheClassPath.ImageResourceCacheKey> iterator = keys.iterator();
-
-            assertNext(iterator, SomeSubclass.class, "SomeSubclass-foo.png");
-            assertNext(iterator, SomeSubclass.class, "SomeSubclass-foo.jpg");
-            assertNext(iterator, SomeSubclass.class, "SomeSubclass-foo.jpeg");
-
-            assertNext(iterator, SomeSubclass.class, "foo.png");
-            assertNext(iterator, SomeSubclass.class, "foo.jpg");
-            assertNext(iterator, SomeSubclass.class, "foo.jpeg");
-
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass-foo.png");
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass-foo.jpg");
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass-foo.jpeg");
-
-            assertNext(iterator, SomeSuperclass.class, "foo.png");
-            assertNext(iterator, SomeSuperclass.class, "foo.jpg");
-            assertNext(iterator, SomeSuperclass.class, "foo.jpeg");
-
-            assertNext(iterator, null, "SomeSubclass-foo.png");
-            assertNext(iterator, null, "SomeSubclass-foo.jpg");
-            assertNext(iterator, null, "SomeSubclass-foo.jpeg");
-
-            assertNext(iterator, null, "SomeSuperclass-foo.png");
-            assertNext(iterator, null, "SomeSuperclass-foo.jpg");
-            assertNext(iterator, null, "SomeSuperclass-foo.jpeg");
-
-            assertNext(iterator, null, "foo.png");
-            assertNext(iterator, null, "foo.jpg");
-            assertNext(iterator, null, "foo.jpeg");
-
-            assertNext(iterator, SomeSubclass.class, "SomeSubclass.png");
-            assertNext(iterator, SomeSubclass.class, "SomeSubclass.jpg");
-            assertNext(iterator, SomeSubclass.class, "SomeSubclass.jpeg");
-
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.png");
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpg");
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpeg");
-
-            assertNext(iterator, null, "SomeSubclass.png");
-            assertNext(iterator, null, "SomeSubclass.jpg");
-            assertNext(iterator, null, "SomeSubclass.jpeg");
-
-            assertNext(iterator, null, "SomeSuperclass.png");
-            assertNext(iterator, null, "SomeSuperclass.jpg");
-            assertNext(iterator, null, "SomeSuperclass.jpeg");
-
-            assertNext(iterator, null, "Default.png");
-            assertNext(iterator, null, "Default.jpg");
-            assertNext(iterator, null, "Default.jpeg");
-
-        }
-
-        @Test
-        public void withoutIconName() throws Exception {
-            key = new ImageResourceCacheClassPath.ImageResourceCacheKey(SomeSubclass.class, null);
-
-            final List<ImageResourceCacheClassPath.ImageResourceCacheKey> keys = key.resourcePaths("png", "jpg", "jpeg");
-
-            final Iterator<ImageResourceCacheClassPath.ImageResourceCacheKey> iterator = keys.iterator();
-
-            assertNext(iterator, SomeSubclass.class, "SomeSubclass.png");
-            assertNext(iterator, SomeSubclass.class, "SomeSubclass.jpg");
-            assertNext(iterator, SomeSubclass.class, "SomeSubclass.jpeg");
-
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.png");
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpg");
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpeg");
-
-            assertNext(iterator, null, "SomeSubclass.png");
-            assertNext(iterator, null, "SomeSubclass.jpg");
-            assertNext(iterator, null, "SomeSubclass.jpeg");
-
-            assertNext(iterator, null, "SomeSuperclass.png");
-            assertNext(iterator, null, "SomeSuperclass.jpg");
-            assertNext(iterator, null, "SomeSuperclass.jpeg");
-
-            assertNext(iterator, null, "Default.png");
-            assertNext(iterator, null, "Default.jpg");
-            assertNext(iterator, null, "Default.jpeg");
-
-        }
-
-        @Test
-        public void withoutClass() throws Exception {
-            key = new ImageResourceCacheClassPath.ImageResourceCacheKey(null, "foo");
-
-            final List<ImageResourceCacheClassPath.ImageResourceCacheKey> keys = key.resourcePaths("png", "jpg", "jpeg");
-
-            final Iterator<ImageResourceCacheClassPath.ImageResourceCacheKey> iterator = keys.iterator();
-
-            assertNext(iterator, null, "foo.png");
-            assertNext(iterator, null, "foo.jpg");
-            assertNext(iterator, null, "foo.jpeg");
-
-            assertNext(iterator, null, "Default.png");
-            assertNext(iterator, null, "Default.jpg");
-            assertNext(iterator, null, "Default.jpeg");
-        }
-
-        /**
-         * This what we see for repositories (using <code></code>@DomainService(repositoryFor=...))
-         */
-        @Test
-        public void withoutClassButIconNameSpecifyingADifferentContextClassAndClassName() throws Exception {
-            key = new ImageResourceCacheClassPath.ImageResourceCacheKey(SomeOtherContextClass.class, SomeSuperclass.class.getName());
-
-            final List<ImageResourceCacheClassPath.ImageResourceCacheKey> keys = key.resourcePaths("png", "jpg", "jpeg");
-
-            final Iterator<ImageResourceCacheClassPath.ImageResourceCacheKey> iterator = keys.iterator();
-
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.png");
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpg");
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpeg");
-
-            assertNext(iterator, null, "Default.png");
-            assertNext(iterator, null, "Default.jpg");
-            assertNext(iterator, null, "Default.jpeg");
-
-        }
-
-        @Test
-        public void withoutClassButIconNameSpecifyingAClassName() throws Exception {
-            key = new ImageResourceCacheClassPath.ImageResourceCacheKey(null, SomeSuperclass.class.getName());
-
-            final List<ImageResourceCacheClassPath.ImageResourceCacheKey> keys = key.resourcePaths("png", "jpg", "jpeg");
-
-            final Iterator<ImageResourceCacheClassPath.ImageResourceCacheKey> iterator = keys.iterator();
-
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.png");
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpg");
-            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpeg");
-
-            assertNext(iterator, null, "Default.png");
-            assertNext(iterator, null, "Default.jpg");
-            assertNext(iterator, null, "Default.jpeg");
-
-        }
-
-        private static void assertNext(Iterator<ImageResourceCacheClassPath.ImageResourceCacheKey> iterator, Class<?> resourceClass, String resourceName) {
-            assertThat(iterator.hasNext(), is(true));
-            final ImageResourceCacheClassPath.ImageResourceCacheKey next = iterator.next();
-            assertEquals(resourceClass, next.getResourceClass());
-            assertEquals(resourceName, next.getResourceName());
-        }
-    }
+//    ImageResourceCacheClassPath.ImageResourceCacheKey key;
+//
+//    public static class SomeSuperclass {
+//    }
+//
+//    public static class SomeSubclass extends SomeSuperclass {
+//    }
+//
+//    public static class SomeOtherContextClass extends SomeSuperclass {
+//    }
+//
+//
+//    public static class SuperKey extends ImageResourceCacheKeyTest {
+//
+//        @Test
+//        public void whenSubclass() throws Exception {
+//
+//            key = new ImageResourceCacheClassPath.ImageResourceCacheKey(SomeSubclass.class, "foo");
+//            final ImageResourceCacheClassPath.ImageResourceCacheKey superKey = key.superKey();
+//
+//            assertEquals(SomeSuperclass.class, superKey.getResourceClass());
+//            assertEquals("foo", key.getResourceName());
+//        }
+//
+//        @Test
+//        public void whenSuperClass() throws Exception {
+//
+//            key = new ImageResourceCacheClassPath.ImageResourceCacheKey(SomeSuperclass.class, null);
+//            final ImageResourceCacheClassPath.ImageResourceCacheKey superKey = key.superKey();
+//
+//            assertNull(superKey);
+//        }
+//
+//    }
+//
+//    public static class ResourcePaths extends ImageResourceCacheKeyTest {
+//
+//        @Test
+//        public void withIconName() throws Exception {
+//            key = new ImageResourceCacheClassPath.ImageResourceCacheKey(SomeSubclass.class, "foo");
+//
+//            final List<ImageResourceCacheClassPath.ImageResourceCacheKey> keys = key.resourcePaths("png", "jpg", "jpeg");
+//
+//            final Iterator<ImageResourceCacheClassPath.ImageResourceCacheKey> iterator = keys.iterator();
+//
+//            assertNext(iterator, SomeSubclass.class, "SomeSubclass-foo.png");
+//            assertNext(iterator, SomeSubclass.class, "SomeSubclass-foo.jpg");
+//            assertNext(iterator, SomeSubclass.class, "SomeSubclass-foo.jpeg");
+//
+//            assertNext(iterator, SomeSubclass.class, "foo.png");
+//            assertNext(iterator, SomeSubclass.class, "foo.jpg");
+//            assertNext(iterator, SomeSubclass.class, "foo.jpeg");
+//
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass-foo.png");
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass-foo.jpg");
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass-foo.jpeg");
+//
+//            assertNext(iterator, SomeSuperclass.class, "foo.png");
+//            assertNext(iterator, SomeSuperclass.class, "foo.jpg");
+//            assertNext(iterator, SomeSuperclass.class, "foo.jpeg");
+//
+//            assertNext(iterator, null, "SomeSubclass-foo.png");
+//            assertNext(iterator, null, "SomeSubclass-foo.jpg");
+//            assertNext(iterator, null, "SomeSubclass-foo.jpeg");
+//
+//            assertNext(iterator, null, "SomeSuperclass-foo.png");
+//            assertNext(iterator, null, "SomeSuperclass-foo.jpg");
+//            assertNext(iterator, null, "SomeSuperclass-foo.jpeg");
+//
+//            assertNext(iterator, null, "foo.png");
+//            assertNext(iterator, null, "foo.jpg");
+//            assertNext(iterator, null, "foo.jpeg");
+//
+//            assertNext(iterator, SomeSubclass.class, "SomeSubclass.png");
+//            assertNext(iterator, SomeSubclass.class, "SomeSubclass.jpg");
+//            assertNext(iterator, SomeSubclass.class, "SomeSubclass.jpeg");
+//
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.png");
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpg");
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpeg");
+//
+//            assertNext(iterator, null, "SomeSubclass.png");
+//            assertNext(iterator, null, "SomeSubclass.jpg");
+//            assertNext(iterator, null, "SomeSubclass.jpeg");
+//
+//            assertNext(iterator, null, "SomeSuperclass.png");
+//            assertNext(iterator, null, "SomeSuperclass.jpg");
+//            assertNext(iterator, null, "SomeSuperclass.jpeg");
+//
+//            assertNext(iterator, null, "Default.png");
+//            assertNext(iterator, null, "Default.jpg");
+//            assertNext(iterator, null, "Default.jpeg");
+//
+//        }
+//
+//        @Test
+//        public void withoutIconName() throws Exception {
+//            key = new ImageResourceCacheClassPath.ImageResourceCacheKey(SomeSubclass.class, null);
+//
+//            final List<ImageResourceCacheClassPath.ImageResourceCacheKey> keys = key.resourcePaths("png", "jpg", "jpeg");
+//
+//            final Iterator<ImageResourceCacheClassPath.ImageResourceCacheKey> iterator = keys.iterator();
+//
+//            assertNext(iterator, SomeSubclass.class, "SomeSubclass.png");
+//            assertNext(iterator, SomeSubclass.class, "SomeSubclass.jpg");
+//            assertNext(iterator, SomeSubclass.class, "SomeSubclass.jpeg");
+//
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.png");
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpg");
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpeg");
+//
+//            assertNext(iterator, null, "SomeSubclass.png");
+//            assertNext(iterator, null, "SomeSubclass.jpg");
+//            assertNext(iterator, null, "SomeSubclass.jpeg");
+//
+//            assertNext(iterator, null, "SomeSuperclass.png");
+//            assertNext(iterator, null, "SomeSuperclass.jpg");
+//            assertNext(iterator, null, "SomeSuperclass.jpeg");
+//
+//            assertNext(iterator, null, "Default.png");
+//            assertNext(iterator, null, "Default.jpg");
+//            assertNext(iterator, null, "Default.jpeg");
+//
+//        }
+//
+//        @Test
+//        public void withoutClass() throws Exception {
+//            key = new ImageResourceCacheClassPath.ImageResourceCacheKey(null, "foo");
+//
+//            final List<ImageResourceCacheClassPath.ImageResourceCacheKey> keys = key.resourcePaths("png", "jpg", "jpeg");
+//
+//            final Iterator<ImageResourceCacheClassPath.ImageResourceCacheKey> iterator = keys.iterator();
+//
+//            assertNext(iterator, null, "foo.png");
+//            assertNext(iterator, null, "foo.jpg");
+//            assertNext(iterator, null, "foo.jpeg");
+//
+//            assertNext(iterator, null, "Default.png");
+//            assertNext(iterator, null, "Default.jpg");
+//            assertNext(iterator, null, "Default.jpeg");
+//        }
+//
+//        /**
+//         * This what we see for repositories (using <code></code>@DomainService(repositoryFor=...))
+//         */
+//        @Test
+//        public void withoutClassButIconNameSpecifyingADifferentContextClassAndClassName() throws Exception {
+//            key = new ImageResourceCacheClassPath.ImageResourceCacheKey(SomeOtherContextClass.class, SomeSuperclass.class.getName());
+//
+//            final List<ImageResourceCacheClassPath.ImageResourceCacheKey> keys = key.resourcePaths("png", "jpg", "jpeg");
+//
+//            final Iterator<ImageResourceCacheClassPath.ImageResourceCacheKey> iterator = keys.iterator();
+//
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.png");
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpg");
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpeg");
+//
+//            assertNext(iterator, null, "Default.png");
+//            assertNext(iterator, null, "Default.jpg");
+//            assertNext(iterator, null, "Default.jpeg");
+//
+//        }
+//
+//        @Test
+//        public void withoutClassButIconNameSpecifyingAClassName() throws Exception {
+//            key = new ImageResourceCacheClassPath.ImageResourceCacheKey(null, SomeSuperclass.class.getName());
+//
+//            final List<ImageResourceCacheClassPath.ImageResourceCacheKey> keys = key.resourcePaths("png", "jpg", "jpeg");
+//
+//            final Iterator<ImageResourceCacheClassPath.ImageResourceCacheKey> iterator = keys.iterator();
+//
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.png");
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpg");
+//            assertNext(iterator, SomeSuperclass.class, "SomeSuperclass.jpeg");
+//
+//            assertNext(iterator, null, "Default.png");
+//            assertNext(iterator, null, "Default.jpg");
+//            assertNext(iterator, null, "Default.jpeg");
+//
+//        }
+//
+//        private static void assertNext(Iterator<ImageResourceCacheClassPath.ImageResourceCacheKey> iterator, Class<?> resourceClass, String resourceName) {
+//            assertThat(iterator.hasNext(), is(true));
+//            final ImageResourceCacheClassPath.ImageResourceCacheKey next = iterator.next();
+//            assertEquals(resourceClass, next.getResourceClass());
+//            assertEquals(resourceName, next.getResourceName());
+//        }
+//    }
 
 }
\ No newline at end of file