This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch 3937-grid.api.overhaul
in repository https://gitbox.apache.org/repos/asf/causeway.git
The following commit(s) were added to refs/heads/3937-grid.api.overhaul by this
push:
new 9746304b624 CAUSEWAY-3937: loading and caching are orthogonal concerns
9746304b624 is described below
commit 9746304b62486f19fb779f2fe94c0f0e3242c8d6
Author: Andi Huber <[email protected]>
AuthorDate: Tue Oct 28 15:28:09 2025 +0100
CAUSEWAY-3937: loading and caching are orthogonal concerns
---
api/applib/src/main/java/module-info.java | 3 +-
.../applib/layout/resource}/LayoutResource.java | 21 +-
.../layout/resource}/LayoutResourceLoader.java | 10 +-
.../causeway/applib/services/grid/GridService.java | 75 +++-----
.../applib/services/grid/package-info.java | 26 ---
.../metamodel/CausewayModuleCoreMetamodel.java | 4 +-
.../metamodel/facets/object/grid/BSGridFacet.java | 9 +-
.../core/metamodel/services/grid/GridCache.java | 211 +++++++++------------
.../core/metamodel/services/grid/GridLoader.java | 102 ++--------
.../services/grid/GridLoadingContext.java | 8 +-
.../services/grid/GridObjectMemberResolver.java | 14 +-
.../services/grid/GridServiceDefault.java | 88 ++++-----
.../{GridLoader.java => LayoutResourceLookup.java} | 59 ++++--
.../grid/spi/LayoutResourceLoaderDefault.java | 2 +
.../services/layout/LayoutServiceDefault.java | 7 +-
.../metamodel/MetaModelServiceDefault.java | 3 +-
.../services/grid/GridCache_resourceNameTest.java | 48 +----
.../metamodel/services/grid/GridLoadingTest.java | 27 +--
.../services/grid/GridXmlRoundtripTest.java | 9 +-
.../spiimpl/LayoutResourceLoaderFromGithub.java | 4 +-
.../viewer/controller/ResourceController.java | 3 +-
21 files changed, 281 insertions(+), 452 deletions(-)
diff --git a/api/applib/src/main/java/module-info.java
b/api/applib/src/main/java/module-info.java
index 2cff49c4aa3..9ce9612ccbe 100644
--- a/api/applib/src/main/java/module-info.java
+++ b/api/applib/src/main/java/module-info.java
@@ -35,12 +35,13 @@
exports org.apache.causeway.applib.graph;
exports org.apache.causeway.applib.id;
exports org.apache.causeway.applib.jaxb;
+ exports org.apache.causeway.applib.layout;
exports org.apache.causeway.applib.layout.component;
exports org.apache.causeway.applib.layout.grid.bootstrap;
exports org.apache.causeway.applib.layout.links;
exports org.apache.causeway.applib.layout.menubars.bootstrap;
exports org.apache.causeway.applib.layout.menubars;
- exports org.apache.causeway.applib.layout;
+ exports org.apache.causeway.applib.layout.resource;
exports org.apache.causeway.applib.locale;
exports org.apache.causeway.applib.mixins.dto;
exports org.apache.causeway.applib.mixins.layout;
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/spi/LayoutResource.java
b/api/applib/src/main/java/org/apache/causeway/applib/layout/resource/LayoutResource.java
similarity index 67%
rename from
core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/spi/LayoutResource.java
rename to
api/applib/src/main/java/org/apache/causeway/applib/layout/resource/LayoutResource.java
index 82c8aff25b7..1db90c16247 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/spi/LayoutResource.java
+++
b/api/applib/src/main/java/org/apache/causeway/applib/layout/resource/LayoutResource.java
@@ -16,15 +16,26 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.causeway.core.metamodel.services.grid.spi;
+package org.apache.causeway.applib.layout.resource;
-import org.jspecify.annotations.NonNull;
+import java.util.Objects;
import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
+/**
+ * Layout data record with name, format and contents (XML, JSON, etc.) based
on format.
+ *
+ * @since 4.0 {@index}
+ */
public record LayoutResource(
- @NonNull String resourceName,
- @NonNull CommonMimeType format,
- @NonNull String content) {
+ String resourceName,
+ CommonMimeType format,
+ String content) {
+
+ public LayoutResource {
+ Objects.requireNonNull(resourceName);
+ Objects.requireNonNull(format);
+ Objects.requireNonNull(content);
+ }
}
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/spi/LayoutResourceLoader.java
b/api/applib/src/main/java/org/apache/causeway/applib/layout/resource/LayoutResourceLoader.java
similarity index 86%
rename from
core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/spi/LayoutResourceLoader.java
rename to
api/applib/src/main/java/org/apache/causeway/applib/layout/resource/LayoutResourceLoader.java
index 7e280f337ba..b2274903130 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/spi/LayoutResourceLoader.java
+++
b/api/applib/src/main/java/org/apache/causeway/applib/layout/resource/LayoutResourceLoader.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.causeway.core.metamodel.services.grid.spi;
+package org.apache.causeway.applib.layout.resource;
import java.util.Optional;
@@ -27,7 +27,7 @@
/**
* SPI for grid loading.
*
- * @since 2.0 {@index}
+ * @since 4.0 {@index}
*/
public interface LayoutResourceLoader {
@@ -35,7 +35,7 @@ public interface LayoutResourceLoader {
* Try to locate and load a {@link LayoutResource} by type and name.
*/
Try<LayoutResource> tryLoadLayoutResource(
- final @NonNull Class<?> type,
+ final @NonNull Class<?> domainObject,
final @NonNull String candidateResourceName);
/**
@@ -46,9 +46,9 @@ Try<LayoutResource> tryLoadLayoutResource(
* <p>Silently ignores exceptions underneath, if any.
*/
default Optional<LayoutResource> lookupLayoutResource(
- final @NonNull Class<?> type,
+ final @NonNull Class<?> domainObject,
final @NonNull String candidateResourceName) {
- return tryLoadLayoutResource(type, candidateResourceName)
+ return tryLoadLayoutResource(domainObject, candidateResourceName)
.getValue();
}
diff --git
a/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridService.java
b/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridService.java
index c83e0dc3fd3..b05a53c479e 100644
---
a/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridService.java
+++
b/api/applib/src/main/java/org/apache/causeway/applib/services/grid/GridService.java
@@ -18,23 +18,35 @@
*/
package org.apache.causeway.applib.services.grid;
+import java.util.EnumSet;
+import java.util.Optional;
+
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
import org.apache.causeway.applib.annotation.ActionLayout;
import org.apache.causeway.applib.annotation.CollectionLayout;
import org.apache.causeway.applib.annotation.DomainObjectLayout;
import org.apache.causeway.applib.annotation.PropertyLayout;
import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
import org.apache.causeway.applib.services.layout.LayoutExportStyle;
+import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
import org.apache.causeway.commons.internal.exceptions._Exceptions;
/**
* Loads the layout (grid) for any domain class.
- *
- * <p> Acts on top of {@link GridMarshaller} and any {@link
GridSystemService}(s) registered with Spring.
+ * Also supports various formats {@link LayoutExportStyle} for export.
*
* @since 1.x revised for 4.0 {@index}
*/
public interface GridService {
+ public record LayoutKey(
+ @NonNull Class<?> domainClass,
+ /** layout suffix */
+ @Nullable String layoutIfAny) {
+ }
+
/**
* Whether dynamic reloading of layouts is enabled.
*
@@ -47,26 +59,10 @@ public interface GridService {
*
* <p> Acts as a no-op if not {@link #supportsReloading()}.
*/
- void remove(Class<?> domainClass);
-
- /**
- * Whether any persisted layout metadata (eg a <code>.layout.xml</code>
file) exists for this domain class.
- */
- boolean existsFor(Class<?> domainClass);
-
- /**
- * Returns a new instance of a {@link BSGrid} for the specified domain
class,
- * for example as loaded from a <code>layout.xml</code> file.
- *
- * <p>If non exists, returns <code>null</code>. (The caller can then
- * use {@link GridService#defaultGridFor(Class)} to obtain a
- * default grid if necessary).
- *
- */
- BSGrid load(final Class<?> domainClass);
+ void invalidate(Class<?> domainClass);
/**
- * Returns an alternative layout for the domain class.
+ * Returns a normalized grid for the domain class.
*
* <p>The alternative layout name can for example be returned by the
* domain object's <code>layout()</code> method, whereby - based on the
@@ -74,22 +70,8 @@ public interface GridService {
*
* <p>The default implementation uses the layout name to search for a
differently
* named layout file, <code>[domainClass].layout.[layout].xml</code>.
- */
- BSGrid load(Class<?> domainClass, String layout);
-
- /**
- * Returns a default grid; eg where none can be loaded using {@link
#load(Class)}.
*
- * <p>Used when no existing grid layout exists for a domain class.
- *
- * <p>The default implementation searches through all available
- * {@link GridSystemService}s and asks each in turn for a
- * {@link GridSystemService#defaultGrid(Class) default grid}.
- */
- BSGrid defaultGridFor(Class<?> domainClass);
-
- /**
- * Returns a normalized grid for the domain class obtained previously
using {@link #load(Class)}.
+ * <p>When no specific grid layout is found returns a generic fallback.
*
* <p>If a 'normalized' grid is persisted as the <code>layout.xml</code>,
then the expectation is that
* any ordering metadata from layout annotations can be removed from the
domain class
@@ -100,7 +82,7 @@ public interface GridService {
* layout XML (in other words moving towards a {@link #complete(BSGrid)
complete} grid. Metadata within the
* <code>layout.xml</code> file takes precedence over any annotations.
*/
- BSGrid normalize(BSGrid grid);
+ BSGrid loadAndNormalize(LayoutKey layoutKey);
/**
* Modifies the provided {@link BSGrid} with additional metadata, broadly
speaking corresponding to the
@@ -119,30 +101,23 @@ public interface GridService {
* most of the layout annotations ({@link DomainObjectLayout}, {@link
ActionLayout}, {@link PropertyLayout},
* {@link CollectionLayout} will still be retained in the domain class
code.
*
- * @param grid
*/
BSGrid minimal(BSGrid grid);
// -- LAYOUT EXPORT
- GridMarshaller marshaller();
+ EnumSet<CommonMimeType> supportedFormats();
+ Optional<GridMarshaller> marshaller(CommonMimeType format);
default BSGrid toGridForExport(
final Class<?> domainClass,
final LayoutExportStyle style) {
- // don't use the grid from the facet, because it will be modified
subsequently.
- BSGrid grid = load(domainClass);
- if(grid == null) {
- grid = defaultGridFor(domainClass);
- }
- grid = normalize(grid); // required so the grid's tns and
schema-locations get populated
- if (style == LayoutExportStyle.COMPLETE) {
- return complete(grid);
- }
- if (style == LayoutExportStyle.MINIMAL) {
- return minimal(grid);
- }
+ var grid = loadAndNormalize(new LayoutKey(domainClass, null));
+
+ if (style == LayoutExportStyle.COMPLETE) return complete(grid);
+ if (style == LayoutExportStyle.MINIMAL) return minimal(grid);
+
throw _Exceptions.unmatchedCase(style);
}
diff --git
a/api/applib/src/main/java/org/apache/causeway/applib/services/grid/package-info.java
b/api/applib/src/main/java/org/apache/causeway/applib/services/grid/package-info.java
deleted file mode 100644
index bccd22a454f..00000000000
---
a/api/applib/src/main/java/org/apache/causeway/applib/services/grid/package-info.java
+++ /dev/null
@@ -1,26 +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.
- */
-
-/**
- * The {@link org.apache.causeway.applib.services.grid.GridService}
encapsulates a single layout grid system which
- * can be used to customize the layout of domain objects.
- *
- *
- */
-package org.apache.causeway.applib.services.grid;
\ No newline at end of file
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/CausewayModuleCoreMetamodel.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/CausewayModuleCoreMetamodel.java
index 7de1f847710..a853ba43960 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/CausewayModuleCoreMetamodel.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/CausewayModuleCoreMetamodel.java
@@ -32,6 +32,7 @@
import org.apache.causeway.applib.CausewayModuleApplib;
import org.apache.causeway.applib.graph.tree.TreeAdapter;
+import org.apache.causeway.applib.layout.resource.LayoutResourceLoader;
import org.apache.causeway.applib.services.appfeat.ApplicationFeatureSort;
import org.apache.causeway.applib.services.grid.GridMarshaller;
import org.apache.causeway.applib.services.message.MessageService;
@@ -57,9 +58,8 @@
import
org.apache.causeway.core.metamodel.services.exceprecog.ExceptionRecognizerForRecoverableException;
import org.apache.causeway.core.metamodel.services.grid.GridLoadingContext;
import org.apache.causeway.core.metamodel.services.grid.GridMarshallerXml;
-import org.apache.causeway.core.metamodel.services.grid.GridServiceDefault;
import
org.apache.causeway.core.metamodel.services.grid.GridObjectMemberResolver.FallbackLayoutDataSource;
-import
org.apache.causeway.core.metamodel.services.grid.spi.LayoutResourceLoader;
+import org.apache.causeway.core.metamodel.services.grid.GridServiceDefault;
import
org.apache.causeway.core.metamodel.services.grid.spi.LayoutResourceLoaderDefault;
import
org.apache.causeway.core.metamodel.services.idstringifier.IdStringifierLookupService;
import
org.apache.causeway.core.metamodel.services.inject.ServiceInjectorDefault;
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/BSGridFacet.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/BSGridFacet.java
index e4abfe06f87..61ad5f698fa 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/BSGridFacet.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/BSGridFacet.java
@@ -19,7 +19,6 @@
package org.apache.causeway.core.metamodel.facets.object.grid;
import java.util.Map;
-import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
@@ -28,6 +27,7 @@
import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
import org.apache.causeway.applib.services.grid.GridService;
+import org.apache.causeway.applib.services.grid.GridService.LayoutKey;
import org.apache.causeway.commons.internal.base._Lazy;
import org.apache.causeway.commons.internal.base._Strings;
import org.apache.causeway.commons.internal.exceptions._Exceptions;
@@ -114,12 +114,7 @@ private boolean hasLayoutPrefixFacet() {
private BSGrid load(final @NonNull String layoutPrefix) {
var domainClass = objSpec().getCorrespondingClass();
- var grid = Optional.ofNullable(
- // loads from object's XML if available
- gridService.load(domainClass,
_Strings.emptyToNull(layoutPrefix)))
- // loads from default-XML if available
- .orElseGet(()->gridService.defaultGridFor(domainClass));
- var bsGrid = gridService.normalize(grid);
+ var bsGrid = gridService.loadAndNormalize(new LayoutKey(domainClass,
_Strings.emptyToNull(layoutPrefix)));
return bsGrid;
}
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridCache.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridCache.java
index e064c4e3dc0..2840fc3392b 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridCache.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridCache.java
@@ -18,50 +18,32 @@
*/
package org.apache.causeway.core.metamodel.services.grid;
-import java.util.EnumSet;
-import java.util.HashMap;
import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-import org.jspecify.annotations.NonNull;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
+import org.apache.causeway.applib.layout.resource.LayoutResource;
import org.apache.causeway.applib.mixins.metamodel.Object_rebuildMetamodel;
-import org.apache.causeway.applib.services.grid.GridMarshaller;
-import org.apache.causeway.applib.services.message.MessageService;
-import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
-import org.apache.causeway.core.metamodel.services.grid.GridLoader.LayoutKey;
+import org.apache.causeway.applib.services.grid.GridService.LayoutKey;
+
import lombok.extern.slf4j.Slf4j;
/**
- * Cache for {@link BSGrid} instances,
- * delegating grid loading to the {@link GridLoader}.
+ * Cache for {@link BSGrid} instances,.
*
* @since 4.0
*/
@Slf4j
record GridCache(
- GridLoader gridLoader,
- MessageService messageService,
- /**
- * Whether dynamic reloading of layouts is enabled.
- *
- * <p> The default implementation enables reloading for prototyping mode,
- * disables in production
- */
- boolean supportsReloading,
- Map<LayoutKey, BSGrid> gridCache,
+ Map<LayoutKey, BSGrid> gridsByKey,
// for better logging messages (used only in prototyping mode)
- Map<LayoutKey, String> badContentByKey) {
+ Map<LayoutKey, LayoutResource> badLayoutResourceByKey) {
public GridCache(
final GridLoadingContext gridLoadingContext) {
- this(new GridLoader(gridLoadingContext.layoutResourceLoaders()),
- gridLoadingContext.messageService(),
- gridLoadingContext.supportsReloading(),
- new HashMap<>(), new HashMap<>());
+ this(
+ new ConcurrentHashMap<>(), new ConcurrentHashMap<>());
}
/**
@@ -71,111 +53,94 @@ public GridCache(
* <p>This is called by the {@link Object_rebuildMetamodel} mixin action.
*/
public void remove(final Class<?> domainClass) {
- if(!supportsReloading()) return;
-
- final String layoutIfAny = null;
- var layoutKey = new LayoutKey(domainClass, layoutIfAny);
- badContentByKey.remove(layoutKey);
- gridCache.remove(layoutKey);
+
badLayoutResourceByKey.entrySet().removeIf(entry->entry.getKey().domainClass().equals(domainClass));
+
gridsByKey.entrySet().removeIf(entry->entry.getKey().domainClass().equals(domainClass));
}
- /**
- * Whether any persisted layout metadata (eg a <code>.layout.xml</code>
file) exists for this domain class.
- *
- * <p>If none exists, will return null.
- */
- public boolean existsFor(final Class<?> domainClass, final
EnumSet<CommonMimeType> supportedFormats) {
- return gridLoader.loadLayoutResource(new LayoutKey(domainClass, null),
supportedFormats).isPresent();
+ public BSGrid computeIfAbsent(final LayoutKey layoutKey, final
Function<LayoutKey, BSGrid> factory) {
+ return gridsByKey.computeIfAbsent(layoutKey, factory);
}
/**
- * Optionally returns a new instance of a {@link BSGrid},
- * based on whether the underlying resource could be found, loaded and
parsed.
- *
- * <p>The layout alternative will typically be specified through a
- * `layout()` method on the domain object, the value of which is used
- * for the suffix of the layout file (eg "Customer-layout.archived.xml"
- * to use a different layout for customers that have been archived).
- *
- * @throws UnsupportedOperationException - when format is not supported
+ * Stores a normalized, validated grid.
*/
- public Optional<BSGrid> load(
- final Class<?> domainClass,
- final String layoutIfAny,
- final @NonNull GridMarshaller marshaller) {
-
- var supportedFormats = marshaller.supportedFormats();
-
- var layoutKey = new LayoutKey(domainClass, layoutIfAny);
- var layoutResource = gridLoader.loadLayoutResource(layoutKey,
supportedFormats).orElse(null);
- if(layoutResource == null) {
- log.debug(
- "Failed to locate or load layout resource for class {}, "
- + "with layout-suffix (if any) {}, "
- + "using layout-resource-loaders {}.",
- domainClass.getName(), layoutIfAny,
- gridLoader().layoutResourceLoaders().stream()
- .map(Object::getClass)
- .map(Class::getName)
- .collect(Collectors.joining(", ")));
- return Optional.empty();
- }
-
- if(supportsReloading()) {
- final String badContent = badContentByKey.get(layoutKey);
- if(badContent != null) {
- if(Objects.equals(layoutResource.content(), badContent)) {
- // seen this before and already logged; just quit
- return Optional.empty();
- } else {
- // this different content might be good
- badContentByKey.remove(layoutKey);
- }
- }
- } else {
- // if cached, serve from cache - otherwise fall through
- final BSGrid grid = gridCache.get(layoutKey);
- if(grid != null) return Optional.of(grid);
- }
-
- try {
- final BSGrid grid = marshaller
- .unmarshal(domainClass, layoutResource.content(),
layoutResource.format())
- .getValue().orElseThrow();
- if(supportsReloading()) {
- gridCache.put(layoutKey, grid);
- }
- return Optional.of(grid);
- } catch(Exception ex) {
-
- if(supportsReloading()) {
- // save fact that this was bad content, so that we don't log
again if called next time
- badContentByKey.put(layoutKey, layoutResource.content());
- }
-
- // note that we don't blacklist if the file exists but couldn't be
parsed;
- // the developer might fix so we will want to retry.
- final String resourceName = layoutResource.resourceName();
- final String message = "Failed to parse " + resourceName + " file
(" + ex.getMessage() + ")";
- if(supportsReloading()) {
- messageService.warnUser(message);
- }
- log.warn(message);
-
- return Optional.empty();
- }
+ public void putValid(final LayoutKey layoutKey, final BSGrid bsGrid) {
+ gridsByKey.put(layoutKey, bsGrid);
}
/**
- * Optionally returns a new instance of a {@link BSGrid},
- * based on whether the underlying resource could be found, loaded and
parsed.
- *
- * @throws UnsupportedOperationException - when format is not supported
+ * Stores a bad {@link LayoutResource}.
*/
- public Optional<BSGrid> load(
- final Class<?> domainClass,
- final @NonNull GridMarshaller marshaller) {
- return load(domainClass, null, marshaller);
+ public void putInvalid(final LayoutKey layoutKey, final LayoutResource
layoutResource) {
+ badLayoutResourceByKey.put(layoutKey, layoutResource);
}
+
+// /**
+// * Optionally returns a new instance of a {@link BSGrid},
+// * based on whether the underlying resource could be found, loaded and
parsed.
+// *
+// * <p>The layout alternative will typically be specified through a
+// * `layout()` method on the domain object, the value of which is used
+// * for the suffix of the layout file (eg "Customer-layout.archived.xml"
+// * to use a different layout for customers that have been archived).
+// *
+// * @throws UnsupportedOperationException - when format is not supported
+// */
+// public Optional<BSGrid> load(
+// final LayoutKey layoutKey,
+// final @NonNull GridMarshaller marshaller) {
+//
+// var supportedFormats = marshaller.supportedFormats();
+//
+// var layoutResourceOpt = gridLoader.lookupLayoutResource(layoutKey,
supportedFormats);
+// if(layoutResourceOpt.isEmpty()) return Optional.empty();
+//
+// var layoutResource = layoutResourceOpt.get();
+//
+// if(supportsReloading()) {
+// final String badContent = badContentByKey.get(layoutKey);
+// if(badContent != null) {
+// if(Objects.equals(layoutResource.content(), badContent)) {
+// // seen this before and already logged; just quit
+// return Optional.empty();
+// } else {
+// // this different content might be good
+// badContentByKey.remove(layoutKey);
+// }
+// }
+// } else {
+// // if cached, serve from cache - otherwise fall through
+// final BSGrid grid = gridsByKey.get(layoutKey);
+// if(grid != null) return Optional.of(grid);
+// }
+//
+// try {
+// final BSGrid grid = marshaller
+// .unmarshal(domainClass, layoutResource.content(),
layoutResource.format())
+// .getValue().orElseThrow();
+// if(supportsReloading()) {
+// gridsByKey.put(layoutKey, grid);
+// }
+// return Optional.of(grid);
+// } catch(Exception ex) {
+//
+// if(supportsReloading()) {
+// // save fact that this was bad content, so that we don't log
again if called next time
+// badContentByKey.put(layoutKey, layoutResource.content());
+// }
+//
+// // note that we don't blacklist if the file exists but couldn't
be parsed;
+// // the developer might fix so we will want to retry.
+// final String resourceName = layoutResource.resourceName();
+// final String message = "Failed to parse " + resourceName + "
file (" + ex.getMessage() + ")";
+// if(supportsReloading()) {
+// messageService.warnUser(message);
+// }
+// log.warn(message);
+//
+// return Optional.empty();
+// }
+// }
+
}
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoader.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoader.java
index 094fe1122ad..5ba50aa9a24 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoader.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoader.java
@@ -18,90 +18,30 @@
*/
package org.apache.causeway.core.metamodel.services.grid;
-import java.util.EnumSet;
-import java.util.Optional;
-import java.util.stream.Stream;
+import org.apache.causeway.applib.layout.grid.bootstrap.BSGrid;
+import org.apache.causeway.applib.layout.resource.LayoutResource;
+import org.apache.causeway.applib.services.grid.GridService.LayoutKey;
+import org.apache.causeway.commons.functional.Try;
-import org.jspecify.annotations.NonNull;
-import org.jspecify.annotations.Nullable;
-
-import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
-import org.apache.causeway.commons.collections.Can;
-import org.apache.causeway.commons.internal.base._Strings;
-import org.apache.causeway.commons.internal.reflection._Reflect;
-import
org.apache.causeway.commons.internal.reflection._Reflect.InterfacePolicy;
-import org.apache.causeway.core.metamodel.services.grid.spi.LayoutResource;
-import
org.apache.causeway.core.metamodel.services.grid.spi.LayoutResourceLoader;
+import lombok.extern.slf4j.Slf4j;
+@Slf4j
record GridLoader(
- Can<LayoutResourceLoader> layoutResourceLoaders) {
-
- public record LayoutKey(
- @NonNull Class<?> domainClass,
- /** layout suffix */
- @Nullable String layoutIfAny) {
- }
-
- // -- HELPER
-
- Optional<LayoutResource> loadLayoutResource(
- final LayoutKey layoutKey,
- final EnumSet<CommonMimeType> supportedFormats) {
- return _Reflect.streamTypeHierarchy(layoutKey.domainClass(),
InterfacePolicy.EXCLUDE)
- .flatMap(type->loadContent(type, layoutKey.layoutIfAny(),
supportedFormats).stream())
- .findFirst();
+ GridLoadingContext gridLoadingContext) {
+
+ /**
+ * Optionally returns a new instance of a {@link BSGrid},
+ * based on whether the underlying resource could be found, loaded and
parsed.
+ *
+ * <p>The layout alternative will typically be specified through a
+ * `layout()` method on the domain object, the value of which is used
+ * for the suffix of the layout file (eg "Customer-layout.archived.xml"
+ * to use a different layout for customers that have been archived).
+ */
+ public Try<BSGrid> tryLoad(final LayoutKey layoutKey, final LayoutResource
layoutResource) {
+ return gridLoadingContext.gridMarshaller(layoutResource.format())
+ .orElseThrow()
+ .unmarshal(layoutKey.domainClass(), layoutResource.content(),
layoutResource.format());
}
- private Optional<LayoutResource> loadContent(
- final @NonNull Class<?> domainClass,
- final @Nullable String layoutIfAny,
- final EnumSet<CommonMimeType> supportedFormats) {
- return streamResourceNameCandidatesFor(domainClass, layoutIfAny,
supportedFormats)
-
.flatMap(candidateResourceName->lookupLayoutResourceUsingLoaders(domainClass,
candidateResourceName).stream())
- .findFirst();
- }
-
- private Stream<String> streamResourceNameCandidatesFor(
- final @NonNull Class<?> domainClass,
- final @Nullable String layoutIfAny,
- final @NonNull EnumSet<CommonMimeType> supportedFormats) {
- return supportedFormats.stream()
- .flatMap(format->streamResourceNameCandidatesFor(domainClass,
layoutIfAny, format));
- }
-
- private Stream<String> streamResourceNameCandidatesFor(
- final @NonNull Class<?> domainClass,
- final @Nullable String layoutIfAny,
- final @NonNull CommonMimeType format) {
- return format.proposedFileExtensions().stream()
-
.flatMap(fileExtension->streamResourceNameCandidatesFor(domainClass,
layoutIfAny, fileExtension));
- }
-
- private Stream<String> streamResourceNameCandidatesFor(
- final @NonNull Class<?> domainClass,
- final @Nullable String layoutIfAny,
- final @NonNull String fileExtension) {
-
- var typeSimpleName = domainClass.getSimpleName();
-
- return _Strings.isNotEmpty(layoutIfAny)
- ? Stream.of(
- String.format("%s-%s.layout.%s", typeSimpleName,
layoutIfAny, fileExtension),
- String.format("%s.layout.%s", typeSimpleName,
fileExtension),
- String.format("%s.layout.fallback.%s", typeSimpleName,
fileExtension))
- : Stream.of(
- String.format("%s.layout.%s", typeSimpleName,
fileExtension),
- String.format("%s.layout.fallback.%s",
typeSimpleName,fileExtension));
- }
-
- private Optional<LayoutResource> lookupLayoutResourceUsingLoaders(
- final @NonNull Class<?> type,
- final @NonNull String candidateResourceName) {
-
- return layoutResourceLoaders.stream()
- .flatMap(loader->loader.lookupLayoutResource(type,
candidateResourceName).stream())
- .findFirst();
- }
-
-
}
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoadingContext.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoadingContext.java
index 8a0d6dd7818..c70f5b69372 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoadingContext.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoadingContext.java
@@ -27,6 +27,7 @@
import jakarta.inject.Provider;
+import org.apache.causeway.applib.layout.resource.LayoutResourceLoader;
import org.apache.causeway.applib.services.grid.GridMarshaller;
import org.apache.causeway.applib.services.message.MessageService;
import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
@@ -35,7 +36,6 @@
import org.apache.causeway.core.config.environment.CausewaySystemEnvironment;
import org.apache.causeway.core.metamodel.CausewayModuleCoreMetamodel;
import
org.apache.causeway.core.metamodel.services.grid.GridObjectMemberResolver.FallbackLayoutDataSource;
-import
org.apache.causeway.core.metamodel.services.grid.spi.LayoutResourceLoader;
import org.apache.causeway.core.metamodel.specloader.SpecificationLoader;
/**
@@ -49,6 +49,12 @@ public record GridLoadingContext(
Map<CommonMimeType, GridMarshaller> marshallersByMime,
Can<LayoutResourceLoader> layoutResourceLoaders,
Can<FallbackLayoutDataSource> fallbackLayoutDataSources,
+ /**
+ * Whether dynamic reloading of layouts is enabled.
+ *
+ * <p> The default implementation enables reloading for prototyping mode,
+ * disables in production
+ */
boolean supportsReloading) {
/** Factory also to be used for JUnit tests. */
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridObjectMemberResolver.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridObjectMemberResolver.java
index 08c6621edb6..dfd97200b68 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridObjectMemberResolver.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridObjectMemberResolver.java
@@ -614,19 +614,21 @@ private void addActionTo(
actionLayoutData.owner(owner);
}
- public void normalize(final BSGrid grid, final Class<?> domainClass) {
+ public Optional<BSGrid> normalize(final BSGrid grid, final Class<?>
domainClass) {
final boolean valid = validateAndNormalize(grid, domainClass);
if (valid) {
overwriteFacets(grid, domainClass);
if(log.isDebugEnabled()) {
log.debug("Grid:\n\n{}\n\n", toXml(grid));
}
- } else {
- if(gridLoadingContext.causewaySystemEnvironment().isPrototyping())
{
- gridLoadingContext.messageService().warnUser("Grid metadata
errors for " + grid.domainClass().getName() + "; check the error log");
- }
- log.error("Grid metadata errors in {}:\n\n{}\n\n",
grid.domainClass().getName(), toXml(grid));
+ return Optional.of(grid);
+ }
+ if(gridLoadingContext.causewaySystemEnvironment().isPrototyping()) {
+ gridLoadingContext.messageService().warnUser("Grid metadata errors
for " + grid.domainClass().getName() + "; check the error log");
}
+ log.error("Grid metadata errors in {}:\n\n{}\n\n",
grid.domainClass().getName(), toXml(grid));
+ return Optional.empty();
+
}
/**
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridServiceDefault.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridServiceDefault.java
index 2838a7e510e..fd587507276 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridServiceDefault.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridServiceDefault.java
@@ -18,6 +18,9 @@
*/
package org.apache.causeway.core.metamodel.services.grid;
+import java.util.EnumSet;
+import java.util.Optional;
+
import jakarta.annotation.Priority;
import jakarta.inject.Inject;
import jakarta.inject.Named;
@@ -30,98 +33,79 @@
import org.apache.causeway.applib.services.grid.GridMarshaller;
import org.apache.causeway.applib.services.grid.GridService;
import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
-import org.apache.causeway.commons.internal.base._Casts;
+import org.apache.causeway.commons.functional.Try;
import org.apache.causeway.core.metamodel.CausewayModuleCoreMetamodel;
/**
* Default implementation of {@link GridService}.
- *
- * @since 1.x revised for 2.0 {@index}
*/
@Service
@Named(CausewayModuleCoreMetamodel.NAMESPACE + ".GridServiceDefault")
@Priority(PriorityPrecedence.MIDPOINT)
@Qualifier("Default")
public record GridServiceDefault(
- GridLoadingContext gridLoadingContext,
- GridObjectMemberResolver gridSystemService,
- GridCache gridCache) implements GridService {
+ GridLoadingContext context,
+ LayoutResourceLookup layoutLookup,
+ GridLoader loader,
+ GridObjectMemberResolver memberResolver,
+ GridCache cache) implements GridService {
@Inject
public GridServiceDefault(
final GridLoadingContext gridLoadingContext) {
- this(gridLoadingContext, new
GridObjectMemberResolver(gridLoadingContext), new
GridCache(gridLoadingContext));
- }
-
- @Override
- public boolean supportsReloading() {
- return gridCache.supportsReloading();
+ this(gridLoadingContext,
+ new
LayoutResourceLookup(gridLoadingContext.layoutResourceLoaders()),
+ new GridLoader(gridLoadingContext),
+ new GridObjectMemberResolver(gridLoadingContext),
+ new GridCache(gridLoadingContext));
}
@Override
- public void remove(final Class<?> domainClass) {
- gridCache.remove(domainClass);
+ public EnumSet<CommonMimeType> supportedFormats() {
+ return context.supportedFormats();
}
@Override
- public boolean existsFor(final Class<?> domainClass) {
- return gridCache.existsFor(domainClass,
gridLoadingContext.supportedFormats());
+ public Optional<GridMarshaller> marshaller(final CommonMimeType format) {
+ return context.gridMarshaller(format);
}
- @Deprecated //FIXME bad API
@Override
- public GridMarshaller marshaller() {
- return
gridLoadingContext().marshallersByMime().get(CommonMimeType.XML);
- }
-
- @Override
- public BSGrid load(final Class<?> domainClass) {
- return gridCache.load(domainClass, marshaller()).orElse(null);
+ public boolean supportsReloading() {
+ return context.supportsReloading();
}
@Override
- public BSGrid load(final Class<?> domainClass, final String layout) {
- return gridCache.load(domainClass, layout, marshaller()).orElse(null);
+ public void invalidate(final Class<?> domainClass) {
+ if(supportsReloading()) cache.remove(domainClass);
}
- // --
-
@Override
- public BSGrid defaultGridFor(final Class<?> domainClass) {
-
- var grid = gridSystemService.defaultGrid(domainClass);
- if(grid != null) return grid;
-
- throw new IllegalStateException(
- "No GridSystemService available to create grid for '" +
domainClass.getName() + "'");
+ public BSGrid loadAndNormalize(final LayoutKey layoutKey) {
+ return cache.computeIfAbsent(layoutKey, this::loadAndNormalizeNoCache);
}
@Override
- public BSGrid normalize(final BSGrid grid) {
- if(grid.isNormalized()) return grid;
-
- var domainClass = grid.domainClass();
- gridSystemService().normalize(_Casts.uncheckedCast(grid), domainClass);
-
+ public BSGrid complete(final BSGrid grid) {
+ memberResolver().complete(grid, grid.domainClass());
return grid;
}
@Override
- public BSGrid complete(final BSGrid grid) {
- var domainClass = grid.domainClass();
- var gridSystemService = gridSystemService();
- gridSystemService.complete(_Casts.uncheckedCast(grid), domainClass);
-
+ public BSGrid minimal(final BSGrid grid) {
+ memberResolver().minimal(grid, grid.domainClass());
return grid;
}
- @Override
- public BSGrid minimal(final BSGrid grid) {
- var domainClass = grid.domainClass();
- var gridSystemService = gridSystemService();
- gridSystemService.minimal(_Casts.uncheckedCast(grid), domainClass);
+ // -- HELPER
- return grid;
+ private BSGrid loadAndNormalizeNoCache(final LayoutKey layoutKey) {
+ return Try.call(()->layoutLookup.lookupLayoutResource(layoutKey,
context.supportedFormats()).orElse(null))
+
.flatMapSuccessWhenPresent(layoutResource->loader.tryLoad(layoutKey,
layoutResource))
+
.mapSuccess(gridOpt->gridOpt.orElseGet(()->memberResolver.defaultGrid(layoutKey.domainClass())))
+ // at this point we have a grid
+ .mapSuccessWhenPresent(grid->memberResolver.normalize(grid,
layoutKey.domainClass()).orElse(null))
+ .valueAsNonNullElseFail();
}
}
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoader.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/LayoutResourceLookup.java
similarity index 67%
copy from
core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoader.java
copy to
core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/LayoutResourceLookup.java
index 094fe1122ad..09f40a0f332 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/GridLoader.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/LayoutResourceLookup.java
@@ -20,38 +20,57 @@
import java.util.EnumSet;
import java.util.Optional;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
+import org.apache.causeway.applib.layout.resource.LayoutResource;
+import org.apache.causeway.applib.layout.resource.LayoutResourceLoader;
+import org.apache.causeway.applib.services.grid.GridService.LayoutKey;
import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
import org.apache.causeway.commons.collections.Can;
import org.apache.causeway.commons.internal.base._Strings;
import org.apache.causeway.commons.internal.reflection._Reflect;
import
org.apache.causeway.commons.internal.reflection._Reflect.InterfacePolicy;
-import org.apache.causeway.core.metamodel.services.grid.spi.LayoutResource;
-import
org.apache.causeway.core.metamodel.services.grid.spi.LayoutResourceLoader;
-record GridLoader(
- Can<LayoutResourceLoader> layoutResourceLoaders) {
-
- public record LayoutKey(
- @NonNull Class<?> domainClass,
- /** layout suffix */
- @Nullable String layoutIfAny) {
- }
+import lombok.extern.slf4j.Slf4j;
- // -- HELPER
+/**
+ * Finds {@link LayoutResource}(s) based on domainClass and layout-suffix,
+ * by probing possible name candidates against the class-path or other sources
(SPI).
+ *
+ * @since 4.0
+ */
+@Slf4j
+record LayoutResourceLookup(
+ Can<LayoutResourceLoader> layoutResourceLoaders) {
- Optional<LayoutResource> loadLayoutResource(
+ public Optional<LayoutResource> lookupLayoutResource(
final LayoutKey layoutKey,
final EnumSet<CommonMimeType> supportedFormats) {
- return _Reflect.streamTypeHierarchy(layoutKey.domainClass(),
InterfacePolicy.EXCLUDE)
+ var layoutResourceOpt =
_Reflect.streamTypeHierarchy(layoutKey.domainClass(), InterfacePolicy.EXCLUDE)
.flatMap(type->loadContent(type, layoutKey.layoutIfAny(),
supportedFormats).stream())
.findFirst();
+
+ if(layoutResourceOpt.isPresent()) return layoutResourceOpt;
+
+ log.debug(
+ "Failed to locate or load layout resource for class {}, "
+ + "with layout-suffix (if any) {}, "
+ + "using layout-resource-loaders {}.",
+ layoutKey.domainClass().getName(), layoutKey.layoutIfAny(),
+ layoutResourceLoaders().stream()
+ .map(Object::getClass)
+ .map(Class::getName)
+ .collect(Collectors.joining(", ")));
+
+ return Optional.empty();
}
+ // -- HELPER
+
private Optional<LayoutResource> loadContent(
final @NonNull Class<?> domainClass,
final @Nullable String layoutIfAny,
@@ -85,13 +104,13 @@ private Stream<String> streamResourceNameCandidatesFor(
var typeSimpleName = domainClass.getSimpleName();
return _Strings.isNotEmpty(layoutIfAny)
- ? Stream.of(
- String.format("%s-%s.layout.%s", typeSimpleName,
layoutIfAny, fileExtension),
- String.format("%s.layout.%s", typeSimpleName,
fileExtension),
- String.format("%s.layout.fallback.%s", typeSimpleName,
fileExtension))
- : Stream.of(
- String.format("%s.layout.%s", typeSimpleName,
fileExtension),
- String.format("%s.layout.fallback.%s",
typeSimpleName,fileExtension));
+ ? Stream.of(
+ String.format("%s-%s.layout.%s", typeSimpleName,
layoutIfAny, fileExtension),
+ String.format("%s.layout.%s", typeSimpleName,
fileExtension),
+ String.format("%s.layout.fallback.%s", typeSimpleName,
fileExtension))
+ : Stream.of(
+ String.format("%s.layout.%s", typeSimpleName,
fileExtension),
+ String.format("%s.layout.fallback.%s",
typeSimpleName,fileExtension));
}
private Optional<LayoutResource> lookupLayoutResourceUsingLoaders(
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/spi/LayoutResourceLoaderDefault.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/spi/LayoutResourceLoaderDefault.java
index ea5e29c4689..2dbaa89ae1d 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/spi/LayoutResourceLoaderDefault.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/grid/spi/LayoutResourceLoaderDefault.java
@@ -27,6 +27,8 @@
import org.springframework.stereotype.Service;
import org.apache.causeway.applib.annotation.PriorityPrecedence;
+import org.apache.causeway.applib.layout.resource.LayoutResource;
+import org.apache.causeway.applib.layout.resource.LayoutResourceLoader;
import org.apache.causeway.applib.value.NamedWithMimeType;
import org.apache.causeway.commons.functional.Try;
import org.apache.causeway.commons.io.DataSource;
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/layout/LayoutServiceDefault.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/layout/LayoutServiceDefault.java
index abafd08d4fa..5e8b0b01732 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/layout/LayoutServiceDefault.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/layout/LayoutServiceDefault.java
@@ -83,7 +83,7 @@ public String menuBarsLayout(
@Override
public EnumSet<CommonMimeType> supportedObjectLayoutFormats() {
- return gridService.marshaller().supportedFormats();
+ return gridService.supportedFormats();
}
@Override
@@ -131,8 +131,9 @@ private Try<String> tryGridToFormatted(
private String gridToFormatted(final @Nullable BSGrid grid, final
CommonMimeType format) {
if(grid==null) return null;
-
- return gridService.marshaller().marshal(_Casts.uncheckedCast(grid),
format);
+ return gridService.marshaller(format)
+ .map(marshaller->marshaller.marshal(grid, format))
+ .orElse(null);
}
private static String zipEntryNameFor(
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/metamodel/MetaModelServiceDefault.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/metamodel/MetaModelServiceDefault.java
index 12da736ef91..b2232bbd58f 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/metamodel/MetaModelServiceDefault.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/metamodel/MetaModelServiceDefault.java
@@ -115,8 +115,7 @@ public Optional<LogicalType> lookupLogicalTypeByClass(final
@Nullable Class<?> d
@Override
public void rebuild(final Class<?> domainType) {
-
- gridService.remove(domainType);
+ gridService.invalidate(domainType);
specificationLoader().reloadSpecification(domainType);
}
diff --git
a/core/mmtest/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridCache_resourceNameTest.java
b/core/mmtest/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridCache_resourceNameTest.java
index 02f3a885a2c..9424191bf45 100644
---
a/core/mmtest/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridCache_resourceNameTest.java
+++
b/core/mmtest/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridCache_resourceNameTest.java
@@ -19,82 +19,52 @@
package org.apache.causeway.core.metamodel.services.grid;
import java.util.EnumSet;
-import java.util.Map;
-import jakarta.inject.Provider;
-
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import org.apache.causeway.applib.services.grid.GridMarshaller;
-import org.apache.causeway.applib.services.message.MessageService;
+import org.apache.causeway.applib.layout.resource.LayoutResource;
+import org.apache.causeway.applib.services.grid.GridService.LayoutKey;
import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
import org.apache.causeway.commons.collections.Can;
-import org.apache.causeway.core.config.CausewayConfiguration;
-import org.apache.causeway.core.config.environment.CausewaySystemEnvironment;
-import org.apache.causeway.core.metamodel.services.grid.GridLoader.LayoutKey;
-import
org.apache.causeway.core.metamodel.services.grid.GridObjectMemberResolver.FallbackLayoutDataSource;
-import org.apache.causeway.core.metamodel.services.grid.spi.LayoutResource;
-import
org.apache.causeway.core.metamodel.services.grid.spi.LayoutResourceLoader;
import
org.apache.causeway.core.metamodel.services.grid.spi.LayoutResourceLoaderDefault;
-import org.apache.causeway.core.metamodel.specloader.SpecificationLoader;
class GridCache_resourceNameTest {
- private GridCache gridCache;
- private LayoutResourceLoader layoutResourceLoader;
-
- @BeforeEach
- void setUp() throws Exception {
- layoutResourceLoader = new LayoutResourceLoaderDefault();
-
- var ctx = new GridLoadingContext(
- (CausewaySystemEnvironment) null,
- (CausewayConfiguration) null,
- (MessageService) null,
- (Provider<SpecificationLoader>) null,
- (Map<CommonMimeType, GridMarshaller>) null,
- Can.of(layoutResourceLoader),
- Can.<FallbackLayoutDataSource>empty(),
- false); // reloading supported
-
- gridCache = new GridCache(ctx);
- }
-
@Test
void when_default_exists() {
assertEquals(
"Foo.layout.xml",
- resourceNameFor(new GridLoader.LayoutKey(Foo.class, null)));
+ resourceNameFor(new LayoutKey(Foo.class, null)));
}
@Test
void when_fallback_exists() {
assertEquals(
"Foo2.layout.fallback.xml",
- resourceNameFor(new GridLoader.LayoutKey(Foo2.class, null)));
+ resourceNameFor(new LayoutKey(Foo2.class, null)));
}
@Test
void when_default_and_fallback_both_exist() {
assertEquals(
"Foo3.layout.xml",
- resourceNameFor(new GridLoader.LayoutKey(Foo3.class, null)));
+ resourceNameFor(new LayoutKey(Foo3.class, null)));
}
@Test
void when_neither_exist() {
assertEquals(
(String)null,
- resourceNameFor(new GridLoader.LayoutKey(Foo4.class, null)));
+ resourceNameFor(new LayoutKey(Foo4.class, null)));
}
// -- HELPER
- private String resourceNameFor(final LayoutKey dcal) {
- return gridCache.gridLoader().loadLayoutResource(dcal,
EnumSet.of(CommonMimeType.XML))
+ private String resourceNameFor(final LayoutKey key) {
+ var resourceLookup = new LayoutResourceLookup(Can.of(new
LayoutResourceLoaderDefault()));
+ return resourceLookup.lookupLayoutResource(key,
EnumSet.of(CommonMimeType.XML))
.map(LayoutResource::resourceName)
.orElse(null);
}
diff --git
a/core/mmtest/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridLoadingTest.java
b/core/mmtest/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridLoadingTest.java
index aeda1067fa7..be4cb6adca1 100644
---
a/core/mmtest/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridLoadingTest.java
+++
b/core/mmtest/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridLoadingTest.java
@@ -18,8 +18,6 @@
*/
package org.apache.causeway.core.metamodel.services.grid;
-import java.util.EnumSet;
-
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -29,9 +27,6 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.apache.causeway.applib.services.grid.GridService;
-import org.apache.causeway.applib.services.layout.LayoutExportStyle;
-import org.apache.causeway.applib.services.layout.LayoutService;
-import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
import org.apache.causeway.core.config.environment.CausewaySystemEnvironment;
import org.apache.causeway.core.metamodel.MetaModelTestAbstract;
import org.apache.causeway.core.metamodel.facetapi.Facet.Precedence;
@@ -43,8 +38,7 @@
class GridLoadingTest
extends MetaModelTestAbstract {
- private GridCache gridCache;
- private LayoutService layoutService;
+ private GridServiceDefault gridService;
@Override
protected void onSetUp(final MetaModelContext_forTestingBuilder
mmcBuilder) {
@@ -58,20 +52,9 @@ protected void onSetUp(final
MetaModelContext_forTestingBuilder mmcBuilder) {
@Override
protected void afterSetUp() {
- layoutService =
getServiceRegistry().lookupServiceElseFail(LayoutService.class);
- gridCache = ((GridServiceDefault) getServiceRegistry()
- .lookupServiceElseFail(GridService.class))
- .gridCache();
- assertTrue(gridCache.supportsReloading());
- }
-
- // test blueprint, for future work
- void blueprint() {
- var domainClassAndLayout = new GridLoader.LayoutKey(Bar.class, null);
- gridCache.gridLoader().loadLayoutResource(domainClassAndLayout,
EnumSet.of(CommonMimeType.XML));
-
- var xml = layoutService.objectLayout(Bar.class,
LayoutExportStyle.MINIMAL, CommonMimeType.XML);
- System.out.println(xml);
+ this.gridService = ((GridServiceDefault) getServiceRegistry()
+ .lookupServiceElseFail(GridService.class));
+ assertTrue(gridService.supportsReloading());
}
@Test
@@ -97,6 +80,8 @@ void customNamed() {
// verify however, that the number of facets stays constant
// triggers grid to be re-loaded
+ gridService.invalidate(Bar.class);
+
var grid2 = gridFacet.getGrid(ManagedObject.adaptSingular(barSpec, new
Bar()));
assertNotSame(grid, grid2); // verify that we actually got a new grid,
indicative of a reload having taken place
diff --git
a/core/mmtest/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridXmlRoundtripTest.java
b/core/mmtest/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridXmlRoundtripTest.java
index c08a713790d..6663e554d8d 100644
---
a/core/mmtest/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridXmlRoundtripTest.java
+++
b/core/mmtest/src/test/java/org/apache/causeway/core/metamodel/services/grid/GridXmlRoundtripTest.java
@@ -36,7 +36,6 @@
import org.apache.causeway.applib.services.jaxb.CausewaySchemas;
import org.apache.causeway.applib.services.jaxb.JaxbService;
import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
-import org.apache.causeway.commons.internal.base._Casts;
import org.apache.causeway.commons.internal.testing._DocumentTester;
import org.apache.causeway.core.metamodel.MetaModelTestAbstract;
@@ -119,14 +118,16 @@ void happy_case() throws Exception {
tabRightCol.getCollections().add(similarToColl);
similarToColl.setId("similarTo");
- String xml =
gridServiceDefault.marshaller().marshal(_Casts.uncheckedCast(bsGrid),
CommonMimeType.XML);
+ var xmlMarshaller =
gridServiceDefault.marshaller(CommonMimeType.XML).orElseThrow();
+
+ String xml = xmlMarshaller.marshal(bsGrid, CommonMimeType.XML);
println(xml);
- BSGrid bsGridRoundtripped = (BSGrid)
gridServiceDefault.marshaller().unmarshal(Object.class, xml, CommonMimeType.XML)
+ BSGrid bsGridRoundtripped = xmlMarshaller.unmarshal(Object.class, xml,
CommonMimeType.XML)
.valueAsNonNullElseFail();
- String xmlRoundtripped =
gridServiceDefault.marshaller().marshal(_Casts.uncheckedCast(bsGridRoundtripped),
CommonMimeType.XML);
+ String xmlRoundtripped = xmlMarshaller.marshal(bsGridRoundtripped,
CommonMimeType.XML);
_DocumentTester.assertXmlEqualsIgnoreOrder(xml, xmlRoundtripped);
diff --git
a/extensions/core/layoutloaders/github/src/main/java/org/apache/causeway/extensions/layoutloaders/github/spiimpl/LayoutResourceLoaderFromGithub.java
b/extensions/core/layoutloaders/github/src/main/java/org/apache/causeway/extensions/layoutloaders/github/spiimpl/LayoutResourceLoaderFromGithub.java
index 82a8f075c46..10399968ff3 100644
---
a/extensions/core/layoutloaders/github/src/main/java/org/apache/causeway/extensions/layoutloaders/github/spiimpl/LayoutResourceLoaderFromGithub.java
+++
b/extensions/core/layoutloaders/github/src/main/java/org/apache/causeway/extensions/layoutloaders/github/spiimpl/LayoutResourceLoaderFromGithub.java
@@ -34,12 +34,12 @@
import org.springframework.web.client.RestTemplate;
import org.apache.causeway.applib.annotation.PriorityPrecedence;
+import org.apache.causeway.applib.layout.resource.LayoutResource;
+import org.apache.causeway.applib.layout.resource.LayoutResourceLoader;
import org.apache.causeway.applib.services.queryresultscache.QueryResultsCache;
import org.apache.causeway.applib.value.NamedWithMimeType;
import org.apache.causeway.commons.functional.Try;
import org.apache.causeway.core.config.CausewayConfiguration;
-import org.apache.causeway.core.metamodel.services.grid.spi.LayoutResource;
-import
org.apache.causeway.core.metamodel.services.grid.spi.LayoutResourceLoader;
import
org.apache.causeway.extensions.layoutloaders.github.CausewayModuleExtLayoutLoadersGithub;
import
org.apache.causeway.extensions.layoutloaders.github.menu.LayoutLoadersGitHubMenu;
diff --git
a/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/controller/ResourceController.java
b/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/controller/ResourceController.java
index b74d74b5cf7..5b098808e87 100644
---
a/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/controller/ResourceController.java
+++
b/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/controller/ResourceController.java
@@ -41,7 +41,6 @@
import org.apache.causeway.applib.value.Blob;
import org.apache.causeway.applib.value.Clob;
import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
-import org.apache.causeway.commons.internal.base._Casts;
import org.apache.causeway.core.config.CausewayConfiguration;
import org.apache.causeway.core.metamodel.facets.object.grid.GridFacet;
import org.apache.causeway.core.metamodel.object.ManagedObject;
@@ -190,7 +189,7 @@ public ResponseEntity<byte[]> icon(
private Optional<String> gridAsXml(final ManagedObject managedObject) {
return managedObject.objSpec().lookupFacet(GridFacet.class)
.map(facet->facet.getGrid(managedObject))
-
.map(grid->gridService().marshaller().marshal(_Casts.uncheckedCast(grid),
CommonMimeType.XML))
+
.flatMap(grid->gridService().marshaller(CommonMimeType.XML).map(mars->mars.marshal(grid,
CommonMimeType.XML)))
.map(x -> x.replaceAll("(\r\n)", "\n"));
}