ISIS-993: working towards getting dynamic reloading working smoothly - not there yet.
* moved responsibility for reading the XML to ObjectLayoutMetadataFacet (not certain if that was a good idea). * Update to MedataMenu to switch on/off dynamic layouts. Don't invalidate entire spec, instead just reload the metadata. * EntityModel cloning now shares the assocated ScalarModel map (a shallow clone), needed for edit form * ObjectReflectorDefault only eagerly loads specs for contributed services and mixins, in an attempt to reduce startup time * EntityTabGroupsPanelFactory now created ether the EntityTabGroupsPanel or the original EntityCombinedPanel, depending on whether there is layout.xml metadata * added some further convenience methods to ObjectLayoutMetadata. What I would like to do is to eagerly load up the layout.xml up front rather than lazily. However, attempting to do that caused a stackoverflow, and not sure why. As things stand I also have an issue with edit failing for the todoapp if no layout data at all, not sure why. Project: http://git-wip-us.apache.org/repos/asf/isis/repo Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/2e8c0943 Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/2e8c0943 Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/2e8c0943 Branch: refs/heads/ISIS-993 Commit: 2e8c094367dcddea351d592ec9f457f802f8b219 Parents: 82d6d64 Author: Dan Haywood <d...@haywood-associates.co.uk> Authored: Tue Jan 12 18:23:47 2016 +0000 Committer: Dan Haywood <d...@haywood-associates.co.uk> Committed: Mon Jan 25 15:06:07 2016 +0000 ---------------------------------------------------------------------- .../layout/v1_0/ObjectLayoutMetadata.java | 53 ++- .../isis/applib/layout/v1_0/PropertyGroup.java | 9 +- .../layout/ObjectLayoutMetadataService.java | 17 +- .../layout/Object_downloadLayoutXml.java | 13 +- .../facetdecorator/FacetDecoratorSet.java | 11 +- .../ObjectLayoutMetadataFacet.java | 11 +- .../ObjectLayoutMetadataFacetDefault.java | 423 ++++++++++++++++++- .../ObjectLayoutMetadataFacetFactory.java | 12 +- .../ObjectLayoutMetadataServiceDefault.java | 378 +---------------- .../services/metamodel/MetadataMenu.java | 45 +- .../specloader/ObjectReflectorDefault.java | 10 +- .../specimpl/FacetedMethodsBuilder.java | 6 +- .../specimpl/ObjectActionContributee.java | 3 + .../dflt/ObjectSpecificationDefault.java | 2 + .../v1_0/ObjectLayoutMetadataTest.java | 5 +- .../viewer/wicket/model/models/EntityModel.java | 36 +- .../combined/EntityCombinedPanelFactory.java | 9 +- .../entity/properties/EntityColumnMembers.java | 5 +- .../entity/properties/EntityPropertiesForm.java | 4 +- .../EntityTabGroupsPanel$EntityTabPanel.html | 5 +- .../entity/tabgroups/EntityTabGroupsPanel.java | 15 +- .../tabgroups/EntityTabGroupsPanelFactory.java | 14 +- .../wicket/ui/pages/entity/EntityPage.java | 22 +- 23 files changed, 626 insertions(+), 482 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ObjectLayoutMetadata.java ---------------------------------------------------------------------- diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ObjectLayoutMetadata.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ObjectLayoutMetadata.java index 2f056a8..4af327c 100644 --- a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ObjectLayoutMetadata.java +++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/ObjectLayoutMetadata.java @@ -33,7 +33,6 @@ import com.google.common.collect.Maps; import org.apache.isis.applib.annotation.Programmatic; import org.apache.isis.applib.services.dto.Dto; -import org.apache.isis.applib.services.layout.ObjectLayoutMetadataService; @XmlRootElement( name = "objectLayout" @@ -182,62 +181,74 @@ public class ObjectLayoutMetadata implements Dto, ActionHolder, Serializable { @Programmatic @XmlTransient public LinkedHashMap<String, PropertyLayoutMetadata> getAllPropertiesById() { - final LinkedHashMap<String, PropertyLayoutMetadata> propertyIds = Maps.newLinkedHashMap(); + final LinkedHashMap<String, PropertyLayoutMetadata> propertiesById = Maps.newLinkedHashMap(); visit(new ObjectLayoutMetadata.VisitorAdapter() { public void visit(final PropertyLayoutMetadata propertyLayoutMetadata) { - propertyIds.put(propertyLayoutMetadata.getId(), propertyLayoutMetadata); + propertiesById.put(propertyLayoutMetadata.getId(), propertyLayoutMetadata); } }); - return propertyIds; + return propertiesById; } @Programmatic @XmlTransient public LinkedHashMap<String, CollectionLayoutMetadata> getAllCollectionsById() { - final LinkedHashMap<String, CollectionLayoutMetadata> collectionIds = Maps.newLinkedHashMap(); - final LinkedHashMap<String, ActionLayoutMetadata> actionIds = Maps.newLinkedHashMap(); + final LinkedHashMap<String, CollectionLayoutMetadata> collectionsById = Maps.newLinkedHashMap(); visit(new ObjectLayoutMetadata.VisitorAdapter() { @Override public void visit(final CollectionLayoutMetadata collectionLayoutMetadata) { - collectionIds.put(collectionLayoutMetadata.getId(), collectionLayoutMetadata); + collectionsById.put(collectionLayoutMetadata.getId(), collectionLayoutMetadata); } }); - return collectionIds; + return collectionsById; } @Programmatic @XmlTransient public LinkedHashMap<String, ActionLayoutMetadata> getAllActionsById() { - final LinkedHashMap<String, ActionLayoutMetadata> actionIds = Maps.newLinkedHashMap(); + final LinkedHashMap<String, ActionLayoutMetadata> actionsById = Maps.newLinkedHashMap(); visit(new ObjectLayoutMetadata.VisitorAdapter() { @Override public void visit(final ActionLayoutMetadata actionLayoutMetadata) { - actionIds.put(actionLayoutMetadata.getId(), actionLayoutMetadata); + actionsById.put(actionLayoutMetadata.getId(), actionLayoutMetadata); } }); - return actionIds; + return actionsById; } + @Programmatic + @XmlTransient + public LinkedHashMap<String, Tab> getAllTabsByName() { + final LinkedHashMap<String, Tab> tabsByName = Maps.newLinkedHashMap(); + + visit(new ObjectLayoutMetadata.VisitorAdapter() { + @Override + public void visit(final Tab tab) { + tabsByName.put(tab.getName(), tab); + } + }); + return tabsByName; + } - private boolean normalized; - /** - * Whether {@link ObjectLayoutMetadataService#normalize(ObjectLayoutMetadata, Class)} - * has been called on this instance. - */ @Programmatic @XmlTransient - public boolean isNormalized() { - return normalized; - } + public LinkedHashMap<String, PropertyGroup> getAllPropertyGroupsByName() { + final LinkedHashMap<String, PropertyGroup> propertyGroupsByName = Maps.newLinkedHashMap(); - public void setNormalized(final boolean normalized) { - this.normalized = normalized; + visit(new ObjectLayoutMetadata.VisitorAdapter() { + @Override + public void visit(final PropertyGroup propertyGroup) { + propertyGroupsByName.put(propertyGroup.getName(), propertyGroup); + } + }); + return propertyGroupsByName; } + } http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyGroup.java ---------------------------------------------------------------------- diff --git a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyGroup.java b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyGroup.java index fd7f3c7..2fb52e3 100644 --- a/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyGroup.java +++ b/core/applib/src/main/java/org/apache/isis/applib/layout/v1_0/PropertyGroup.java @@ -19,7 +19,6 @@ package org.apache.isis.applib.layout.v1_0; import java.io.Serializable; -import java.util.ArrayList; import java.util.List; import javax.annotation.Nullable; @@ -30,6 +29,7 @@ import javax.xml.bind.annotation.XmlTransient; import javax.xml.bind.annotation.XmlType; import com.google.common.base.Function; +import com.google.common.collect.Lists; import org.apache.isis.applib.annotation.MemberOrder; @@ -67,7 +67,7 @@ public class PropertyGroup implements ColumnContent, ActionHolder, Serializable - private List<ActionLayoutMetadata> actions; + private List<ActionLayoutMetadata> actions = Lists.newArrayList(); @XmlElementWrapper(required = false) @XmlElement(name = "action", required = false) @@ -81,10 +81,7 @@ public class PropertyGroup implements ColumnContent, ActionHolder, Serializable - // must be at least one property in the property group - private List<PropertyLayoutMetadata> properties = new ArrayList<PropertyLayoutMetadata>() {{ - add(new PropertyLayoutMetadata()); - }}; + private List<PropertyLayoutMetadata> properties = Lists.newArrayList(); @XmlElement(name = "property", required = true) public List<PropertyLayoutMetadata> getProperties() { http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/applib/src/main/java/org/apache/isis/applib/services/layout/ObjectLayoutMetadataService.java ---------------------------------------------------------------------- diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/layout/ObjectLayoutMetadataService.java b/core/applib/src/main/java/org/apache/isis/applib/services/layout/ObjectLayoutMetadataService.java index f0da669..e29ff47 100644 --- a/core/applib/src/main/java/org/apache/isis/applib/services/layout/ObjectLayoutMetadataService.java +++ b/core/applib/src/main/java/org/apache/isis/applib/services/layout/ObjectLayoutMetadataService.java @@ -28,22 +28,21 @@ public interface ObjectLayoutMetadataService { ObjectLayoutMetadata fromXml(Class<?> domainClass); /** - * @param objectLayoutMetadata - the layout to be validated. - * @param domainClass - as per domain class. - */ - @Programmatic - ObjectLayoutMetadata normalize(final ObjectLayoutMetadata objectLayoutMetadata, final Class<?> domainClass); - - /** - * Obtains the layout metadata for the specified domain object. It will have been {@link #normalize(ObjectLayoutMetadata, Class) normalized} already. + * Obtains the layout metadata, if any, for the (domain class of the) specified domain object. */ @Programmatic ObjectLayoutMetadata toMetadata(Object domainObject); /** - * Obtains the layout metadata for the specified domain class. It will have been {@link #normalize(ObjectLayoutMetadata, Class) normalized} already. + * Obtains the layout metadata, if any, for the specified domain class. */ @Programmatic ObjectLayoutMetadata toMetadata(Class<?> domainClass); + @Programmatic + void toggleDynamicReloading(); + + @Programmatic + boolean isDynamicReloading(); + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_downloadLayoutXml.java ---------------------------------------------------------------------- diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_downloadLayoutXml.java b/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_downloadLayoutXml.java index aca104c..726becf 100644 --- a/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_downloadLayoutXml.java +++ b/core/applib/src/main/java/org/apache/isis/applib/services/layout/Object_downloadLayoutXml.java @@ -17,6 +17,9 @@ package org.apache.isis.applib.services.layout; import javax.inject.Inject; +import javax.xml.bind.Marshaller; + +import com.google.common.collect.ImmutableMap; import org.apache.isis.applib.annotation.Action; import org.apache.isis.applib.annotation.ActionLayout; @@ -32,6 +35,9 @@ import org.apache.isis.applib.value.Clob; @Mixin public class Object_downloadLayoutXml { + public static final String TNS = "http://isis.apache.org/schema/applib/layout"; + public static final String SCHEMA_LOCATION = "http://isis.apache.org/schema/applib/layout/layout-1.0.xsd"; + private final Object object; public Object_downloadLayoutXml(final Object object) { @@ -53,7 +59,12 @@ public class Object_downloadLayoutXml { @ParameterLayout(named = "File name") final String fileName) { final ObjectLayoutMetadata metadata = getObjectLayoutMetadata(); - final String xml = jaxbService.toXml(metadata); + final String xml = jaxbService.toXml(metadata, + ImmutableMap.<String,Object>of( + Marshaller.JAXB_SCHEMA_LOCATION, + TNS + " " + SCHEMA_LOCATION + )); + return new Clob(Util.withSuffix(fileName, "xml"), "text/xml", xml); } http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetdecorator/FacetDecoratorSet.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetdecorator/FacetDecoratorSet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetdecorator/FacetDecoratorSet.java index c540e30..38eb045 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetdecorator/FacetDecoratorSet.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetdecorator/FacetDecoratorSet.java @@ -21,7 +21,6 @@ package org.apache.isis.core.metamodel.facetdecorator; import java.text.MessageFormat; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; @@ -81,10 +80,6 @@ public class FacetDecoratorSet implements ApplicationScopedComponent { } } - public Set<FacetDecorator> getFacetDecorators() { - return Collections.unmodifiableSet(facetDecoratorSet); - } - public boolean isEmpty() { return facetDecoratorByFacetType.isEmpty(); } @@ -114,10 +109,12 @@ public class FacetDecoratorSet implements ApplicationScopedComponent { if (isEmpty()) { return; } - final Class<? extends Facet>[] facetTypes = holder.getFacetTypes(); + final Set<Class<? extends Facet>> facetTypes = facetDecoratorByFacetType.keySet(); for (final Class<? extends Facet> facetType : facetTypes) { final Facet facet = holder.getFacet(facetType); - decorateFacet(facet, holder); + if(facet != null) { + decorateFacet(facet, holder); + } } } http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacet.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacet.java index 4d8db93..2a63428 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacet.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacet.java @@ -19,8 +19,8 @@ package org.apache.isis.core.metamodel.facets.object.layoutmetadata; -import org.apache.isis.core.metamodel.facetapi.Facet; import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata; +import org.apache.isis.core.metamodel.facetapi.Facet; /** * Corresponds to providing a <code>.layout.xml</code> file for the domain object's class. @@ -28,8 +28,13 @@ import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata; public interface ObjectLayoutMetadataFacet extends Facet { /** - * Will have been {@link org.apache.isis.applib.services.layout.ObjectLayoutMetadataService#normalize(ObjectLayoutMetadata, Class) normalized}. + * Will have been normalized by framework earlier. */ ObjectLayoutMetadata getMetadata(); -} + /** + * (Re)load, in support of dynamic layout reloading. + */ + void reloadMetadata(); + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetDefault.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetDefault.java index 95e3712..9538e72 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetDefault.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetDefault.java @@ -18,19 +18,72 @@ */ package org.apache.isis.core.metamodel.facets.object.layoutmetadata; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.isis.applib.layout.v1_0.ActionHolder; +import org.apache.isis.applib.layout.v1_0.ActionLayoutMetadata; +import org.apache.isis.applib.layout.v1_0.CollectionLayoutMetadata; +import org.apache.isis.applib.layout.v1_0.Column; +import org.apache.isis.applib.layout.v1_0.ColumnHolder; import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata; +import org.apache.isis.applib.layout.v1_0.PropertyGroup; +import org.apache.isis.applib.layout.v1_0.PropertyLayoutMetadata; +import org.apache.isis.applib.layout.v1_0.Tab; +import org.apache.isis.applib.layout.v1_0.TabGroup; +import org.apache.isis.applib.services.i18n.TranslationService; import org.apache.isis.applib.services.layout.ObjectLayoutMetadataService; import org.apache.isis.core.metamodel.facetapi.Facet; import org.apache.isis.core.metamodel.facetapi.FacetAbstract; import org.apache.isis.core.metamodel.facetapi.FacetHolder; +import org.apache.isis.core.metamodel.facetapi.FacetUtil; +import org.apache.isis.core.metamodel.facets.actions.layout.ActionPositionFacetForActionXml; +import org.apache.isis.core.metamodel.facets.actions.layout.BookmarkPolicyFacetForActionXml; +import org.apache.isis.core.metamodel.facets.actions.layout.CssClassFaFacetForActionXml; +import org.apache.isis.core.metamodel.facets.actions.layout.CssClassFacetForActionXml; +import org.apache.isis.core.metamodel.facets.actions.layout.DescribedAsFacetForActionXml; +import org.apache.isis.core.metamodel.facets.actions.layout.HiddenFacetForActionLayoutXml; +import org.apache.isis.core.metamodel.facets.actions.layout.NamedFacetForActionXml; +import org.apache.isis.core.metamodel.facets.collections.layout.CssClassFacetForCollectionXml; +import org.apache.isis.core.metamodel.facets.collections.layout.DefaultViewFacetForCollectionXml; +import org.apache.isis.core.metamodel.facets.collections.layout.DescribedAsFacetForCollectionXml; +import org.apache.isis.core.metamodel.facets.collections.layout.HiddenFacetForCollectionXml; +import org.apache.isis.core.metamodel.facets.collections.layout.NamedFacetForCollectionXml; +import org.apache.isis.core.metamodel.facets.collections.layout.PagedFacetForCollectionXml; +import org.apache.isis.core.metamodel.facets.collections.layout.SortedByFacetForCollectionXml; +import org.apache.isis.core.metamodel.facets.members.order.annotprop.MemberOrderFacetXml; +import org.apache.isis.core.metamodel.facets.object.membergroups.MemberGroupLayoutFacet; +import org.apache.isis.core.metamodel.facets.properties.propertylayout.CssClassFacetForPropertyXml; +import org.apache.isis.core.metamodel.facets.properties.propertylayout.DescribedAsFacetForPropertyXml; +import org.apache.isis.core.metamodel.facets.properties.propertylayout.HiddenFacetForPropertyXml; +import org.apache.isis.core.metamodel.facets.properties.propertylayout.LabelAtFacetForPropertyXml; +import org.apache.isis.core.metamodel.facets.properties.propertylayout.MultiLineFacetForPropertyXml; +import org.apache.isis.core.metamodel.facets.properties.propertylayout.NamedFacetForPropertyXml; +import org.apache.isis.core.metamodel.facets.properties.propertylayout.RenderedAdjustedFacetForPropertyXml; +import org.apache.isis.core.metamodel.facets.properties.propertylayout.TypicalLengthFacetForPropertyXml; import org.apache.isis.core.metamodel.spec.ObjectSpecification; +import org.apache.isis.core.metamodel.spec.feature.Contributed; +import org.apache.isis.core.metamodel.spec.feature.ObjectAction; +import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation; +import org.apache.isis.core.metamodel.spec.feature.ObjectMember; +import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation; +import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation; public class ObjectLayoutMetadataFacetDefault extends FacetAbstract implements ObjectLayoutMetadataFacet { - private final ObjectLayoutMetadata metadata; - private final ObjectLayoutMetadataService objectLayoutMetadataService; + private static final Logger LOG = LoggerFactory.getLogger(ObjectLayoutMetadataFacetDefault.class); + public static Class<? extends Facet> type() { return ObjectLayoutMetadataFacet.class; @@ -39,27 +92,375 @@ public class ObjectLayoutMetadataFacetDefault public static ObjectLayoutMetadataFacet create( final FacetHolder facetHolder, - final ObjectLayoutMetadata objectLayoutMetadata, + final TranslationService translationService, final ObjectLayoutMetadataService objectLayoutMetadataService) { - if(objectLayoutMetadata == null) { - return null; - } - return new ObjectLayoutMetadataFacetDefault(facetHolder, objectLayoutMetadata, objectLayoutMetadataService); + return new ObjectLayoutMetadataFacetDefault(facetHolder, translationService, objectLayoutMetadataService); } + private final TranslationService translationService; + private final ObjectLayoutMetadataService objectLayoutMetadataService; + + private boolean blacklisted; + private ObjectLayoutMetadata metadata; + private ObjectLayoutMetadataFacetDefault( final FacetHolder facetHolder, - final ObjectLayoutMetadata metadata, + final TranslationService translationService, final ObjectLayoutMetadataService objectLayoutMetadataService) { super(ObjectLayoutMetadataFacetDefault.type(), facetHolder, Derivation.NOT_DERIVED); - this.metadata = metadata; this.objectLayoutMetadataService = objectLayoutMetadataService; + this.translationService = translationService; } + @Override + public boolean isNoop() { + getMetadata(); + return blacklisted; + } + @Override public ObjectLayoutMetadata getMetadata() { - final ObjectSpecification objectSpecification = (ObjectSpecification) getFacetHolder(); - return objectLayoutMetadataService.normalize(metadata, objectSpecification.getCorrespondingClass()); + if(blacklisted) { + return null; + } + reloadMetadata(); + return this.metadata; + } + + @Override + public void reloadMetadata() { + if (metadata != null && !objectLayoutMetadataService.isDynamicReloading()) { + return; + } + final Class<?> domainClass = getSpecification().getCorrespondingClass(); + final ObjectLayoutMetadata metadata = objectLayoutMetadataService.fromXml(domainClass); + this.metadata = normalize(metadata); + blacklisted = this.metadata == null; + } + + private ObjectLayoutMetadata normalize(final ObjectLayoutMetadata metadata) { + if(metadata == null) { + return null; + } + if(LOG.isInfoEnabled()) { + LOG.info("Normalizing layout metadata for " + getSpecification().getCorrespondingClass().getName()); + } + doNormalize(metadata, getSpecification()); + return metadata; + } + + private void doNormalize(final ObjectLayoutMetadata metadata, final ObjectSpecification objectSpec) { + + final Map<String, OneToOneAssociation> oneToOneAssociationById = + ObjectMember.Util.mapById(getOneToOneAssociations(objectSpec)); + final Map<String, OneToManyAssociation> oneToManyAssociationById = + ObjectMember.Util.mapById(getOneToManyAssociations(objectSpec)); + final Map<String, ObjectAction> objectActionById = + ObjectMember.Util.mapById(objectSpec.getObjectActions(Contributed.INCLUDED)); + + derive(metadata, oneToOneAssociationById, oneToManyAssociationById, objectActionById); + overwrite(metadata, oneToOneAssociationById, oneToManyAssociationById, objectActionById); + } + + /** + * Ensures that all object members (properties, collections and actions) are in the metadata. + * + * <p> + * If they are missing then they will be added to default tabs (created on the fly if need be). + * </p> + */ + private static void derive( + final ObjectLayoutMetadata metadata, + final Map<String, OneToOneAssociation> oneToOneAssociationById, + final Map<String, OneToManyAssociation> oneToManyAssociationById, + final Map<String, ObjectAction> objectActionById) { + + final LinkedHashMap<String, PropertyLayoutMetadata> propertyIds = metadata.getAllPropertiesById(); + final LinkedHashMap<String, CollectionLayoutMetadata> collectionIds = metadata.getAllCollectionsById(); + final LinkedHashMap<String, ActionLayoutMetadata> actionIds = metadata.getAllActionsById(); + + final AtomicReference<PropertyGroup> defaultPropertyGroupRef = new AtomicReference<>(); + final AtomicReference<Column> firstColumnRef = new AtomicReference<>(); + final AtomicReference<TabGroup> lastTabGroupRef = new AtomicReference<>(); + + // capture the first column, and also + // capture the first property group (if any) with the default name ('General') + metadata.visit(new ObjectLayoutMetadata.VisitorAdapter() { + @Override + public void visit(final Column column) { + firstColumnRef.compareAndSet(null, column); + } + @Override + public void visit(final PropertyGroup propertyGroup) { + if(MemberGroupLayoutFacet.DEFAULT_GROUP.equals(propertyGroup.getName())) { + defaultPropertyGroupRef.compareAndSet(null, propertyGroup); + } + } + @Override + public void visit(final TabGroup tabGroup) { + lastTabGroupRef.set(tabGroup); + } + }); + + // any missing properties will be added to the (first) 'General' property group found + // if there is no default ('General') property group + // then one will be added to the first Column of the first Tab. + final Tuple<List<String>> propertyIdTuple = surplusAndMissing(propertyIds.keySet(), oneToOneAssociationById.keySet()); + final List<String> surplusPropertyIds = propertyIdTuple.first; + final List<String> missingPropertyIds = propertyIdTuple.second; + + for (String surplusPropertyId : surplusPropertyIds) { + propertyIds.get(surplusPropertyId).setMetadataError("No such property"); + } + + if(!missingPropertyIds.isEmpty()) { + // ensure that there is a property group to use + boolean wasSet = defaultPropertyGroupRef.compareAndSet(null, new PropertyGroup(MemberGroupLayoutFacet.DEFAULT_GROUP)); + final PropertyGroup defaultPropertyGroup = defaultPropertyGroupRef.get(); + if(wasSet) { + firstColumnRef.get().getPropertyGroups().add(defaultPropertyGroup); + } + for (final String propertyId : missingPropertyIds) { + defaultPropertyGroup.getProperties().add(new PropertyLayoutMetadata(propertyId)); + } + } + + + // any missing collections will be added as tabs to the last TabGroup. + // If there is only a single tab group then a new TabGroup will be added first + final Tuple<List<String>> collectionIdTuple = surplusAndMissing(collectionIds.keySet(), oneToManyAssociationById.keySet()); + final List<String> surplusCollectionIds = collectionIdTuple.first; + final List<String> missingCollectionIds = collectionIdTuple.second; + + for (String surplusCollectionId : surplusCollectionIds) { + collectionIds.get(surplusCollectionId).setMetadataError("No such collection"); + } + + if(!missingCollectionIds.isEmpty()) { + while(metadata.getTabGroups().size() < 2) { + final TabGroup tabGroup = new TabGroup(); + metadata.getTabGroups().add(tabGroup); + lastTabGroupRef.set(tabGroup); + } + final TabGroup lastTabGroup = lastTabGroupRef.get(); + for (final String collectionId : missingCollectionIds) { + final Tab tab = new Tab(); + lastTabGroup.getTabs().add(tab); + Column left = new Column(12); + tab.setLeft(left); + final CollectionLayoutMetadata layoutMetadata = new CollectionLayoutMetadata(collectionId); + layoutMetadata.setDefaultView("table"); + left.getCollections().add(layoutMetadata); + } + } + + // any missing actions will be added as domain object actions (in the header) + final Tuple<List<String>> actionIdTuple = surplusAndMissing(actionIds.keySet(), objectActionById.keySet()); + final List<String> surplusActionIds = actionIdTuple.first; + final List<String> missingActionIds = actionIdTuple.second; + + for (String surplusActionId : surplusActionIds) { + actionIds.get(surplusActionId).setMetadataError("No such action"); + } + + if(!missingActionIds.isEmpty()) { + for (String actionId : missingActionIds) { + List<ActionLayoutMetadata> actions = metadata.getActions(); + if(actions == null) { + actions = Lists.newArrayList(); + metadata.setActions(actions); + } + actions.add(new ActionLayoutMetadata(actionId)); + } + } + } + + static class Tuple<T> { + final T first; + final T second; + private Tuple(final T first, final T second) { + this.first = first; + this.second = second; + } + public static <T> Tuple<T> of(final T first, final T second) { + return new Tuple<>(first, second); + } + } + /** + * Returns a 2-element tuple of [first-second, second-first] + */ + static <T> Tuple<List<T>> surplusAndMissing(final Collection<T> first, final Collection<T> second){ + final List<T> firstNotSecond = Lists.newArrayList(first); + firstNotSecond.removeAll(second); + final List<T> secondNotFirst = Lists.newArrayList(second); + secondNotFirst.removeAll(first); + return Tuple.of(firstNotSecond, secondNotFirst); + } + + private void overwrite( + final ObjectLayoutMetadata metadata, + final Map<String, OneToOneAssociation> oneToOneAssociationById, + final Map<String, OneToManyAssociation> oneToManyAssociationById, + final Map<String, ObjectAction> objectActionById) { + + final Map<String, int[]> propertySequenceByGroup = Maps.newHashMap(); + + metadata.visit(new ObjectLayoutMetadata.VisitorAdapter() { + private int collectionSequence = 1; + private int actionDomainObjectSequence = 1; + private int actionPropertyGroupSequence = 1; + private int actionPropertySequence = 1; + private int actionCollectionSequence = 1; + + @Override + public void visit(final ActionLayoutMetadata actionLayoutMetadata) { + final ActionHolder actionHolder = actionLayoutMetadata.getOwner(); + final ObjectAction objectAction = objectActionById.get(actionLayoutMetadata.getId()); + if(objectAction == null) { + return; + } + + final String memberOrderName; + final int memberOrderSequence; + if(actionHolder instanceof PropertyGroup) { + final PropertyGroup propertyGroup = (PropertyGroup) actionHolder; + final List<PropertyLayoutMetadata> properties = propertyGroup.getProperties(); + final PropertyLayoutMetadata propertyLayoutMetadata = properties.get(0); // any will do + memberOrderName = propertyLayoutMetadata.getId(); + memberOrderSequence = actionPropertyGroupSequence++; + } else if(actionHolder instanceof PropertyLayoutMetadata) { + final PropertyLayoutMetadata propertyLayoutMetadata = (PropertyLayoutMetadata) actionHolder; + memberOrderName = propertyLayoutMetadata.getId(); + memberOrderSequence = actionPropertySequence++; + } else if(actionHolder instanceof CollectionLayoutMetadata) { + final CollectionLayoutMetadata collectionLayoutMetadata = (CollectionLayoutMetadata) actionHolder; + memberOrderName = collectionLayoutMetadata.getId(); + memberOrderSequence = actionCollectionSequence++; + } else { + // DomainObject + memberOrderName = null; + memberOrderSequence = actionDomainObjectSequence++; + } + FacetUtil.addFacet( + new MemberOrderFacetXml(memberOrderName, ""+memberOrderSequence, translationService, objectAction)); + + + if(actionHolder instanceof PropertyGroup) { + if(actionLayoutMetadata.getPosition() == null || + actionLayoutMetadata.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.BELOW || + actionLayoutMetadata.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.RIGHT) { + actionLayoutMetadata.setPosition(org.apache.isis.applib.annotation.ActionLayout.Position.PANEL); + } + } else if(actionHolder instanceof PropertyLayoutMetadata) { + if(actionLayoutMetadata.getPosition() == null || + actionLayoutMetadata.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.PANEL_DROPDOWN || + actionLayoutMetadata.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.PANEL) { + actionLayoutMetadata.setPosition(org.apache.isis.applib.annotation.ActionLayout.Position.BELOW); + } + } else { + // doesn't do anything for DomainObject or Collection + actionLayoutMetadata.setPosition(null); + } + + FacetUtil.addFacet(ActionPositionFacetForActionXml.create(actionLayoutMetadata, objectAction)); + FacetUtil.addFacet(BookmarkPolicyFacetForActionXml.create(actionLayoutMetadata, objectAction)); + FacetUtil.addFacet(CssClassFacetForActionXml.create(actionLayoutMetadata, objectAction)); + FacetUtil.addFacet(CssClassFaFacetForActionXml.create(actionLayoutMetadata, objectAction)); + FacetUtil.addFacet(DescribedAsFacetForActionXml.create(actionLayoutMetadata, objectAction)); + FacetUtil.addFacet(HiddenFacetForActionLayoutXml.create(actionLayoutMetadata, objectAction)); + FacetUtil.addFacet(NamedFacetForActionXml.create(actionLayoutMetadata, objectAction)); + } + + @Override + public void visit(final PropertyLayoutMetadata propertyLayoutMetadata) { + final OneToOneAssociation oneToOneAssociation = oneToOneAssociationById.get(propertyLayoutMetadata.getId()); + if(oneToOneAssociation == null) { + return; + } + + FacetUtil.addFacet(CssClassFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); + FacetUtil.addFacet(DescribedAsFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); + FacetUtil.addFacet(HiddenFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); + FacetUtil.addFacet(LabelAtFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); + FacetUtil.addFacet(MultiLineFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); + FacetUtil.addFacet(NamedFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); + FacetUtil.addFacet( + RenderedAdjustedFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); + FacetUtil.addFacet(TypicalLengthFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); + + // @MemberOrder#name based on owning property group, @MemberOrder#sequence monotonically increasing + final PropertyGroup propertyGroup = propertyLayoutMetadata.getOwner(); + final String groupName = propertyGroup.getName(); + final String sequence = nextInSequenceFor(groupName, propertySequenceByGroup); + FacetUtil.addFacet( + new MemberOrderFacetXml(groupName, sequence, translationService, oneToOneAssociation)); + } + + @Override + public void visit(final CollectionLayoutMetadata collectionLayoutMetadata) { + final OneToManyAssociation oneToManyAssociation = oneToManyAssociationById.get(collectionLayoutMetadata.getId()); + if(oneToManyAssociation == null) { + return; + } + + FacetUtil.addFacet(CssClassFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation)); + FacetUtil.addFacet( + DefaultViewFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation)); + FacetUtil.addFacet( + DescribedAsFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation)); + FacetUtil.addFacet(HiddenFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation)); + FacetUtil.addFacet(NamedFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation)); + FacetUtil.addFacet(PagedFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation)); + FacetUtil.addFacet(SortedByFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation)); + + // @MemberOrder#name based on the collection's id (so that each has a single "member group") + final String groupName = collectionLayoutMetadata.getId(); + final String sequence = "" + collectionSequence++; + FacetUtil.addFacet( + new MemberOrderFacetXml(groupName, sequence, translationService, oneToManyAssociation)); + + // if there is only a single column and no other contents, then copy the collection Id onto the tab' + final Column column = collectionLayoutMetadata.getOwner(); + final ColumnHolder holder = column.getOwner(); + if(holder instanceof Tab) { + final Tab tab = (Tab) holder; + if(tab.getContents().size() == 1) { + final String collectionName = oneToManyAssociation.getName(); + tab.setName(collectionName); + } + } + } + }); } + private String nextInSequenceFor( + final String key, final Map<String, int[]> seqByKey) { + synchronized (seqByKey) { + int[] holder = seqByKey.get(key); + if(holder == null) { + holder = new int[]{0}; + seqByKey.put(key, holder); + } + holder[0]++; + return ""+holder[0]; + } + } + + private static List<OneToOneAssociation> getOneToOneAssociations(final ObjectSpecification objectSpec) { + List associations = objectSpec + .getAssociations(Contributed.INCLUDED, ObjectAssociation.Filters.PROPERTIES); + return associations; + } + private static List<OneToManyAssociation> getOneToManyAssociations(final ObjectSpecification objectSpec) { + List associations = objectSpec + .getAssociations(Contributed.INCLUDED, ObjectAssociation.Filters.COLLECTIONS); + return associations; + } + + private ObjectSpecification getSpecification() { + return (ObjectSpecification)getFacetHolder(); + } + + + } http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetFactory.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetFactory.java index 0f1b4e8..479849c 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetFactory.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layoutmetadata/ObjectLayoutMetadataFacetFactory.java @@ -19,7 +19,7 @@ package org.apache.isis.core.metamodel.facets.object.layoutmetadata; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata; +import org.apache.isis.applib.services.i18n.TranslationService; import org.apache.isis.applib.services.layout.ObjectLayoutMetadataService; import org.apache.isis.core.metamodel.facetapi.FacetHolder; import org.apache.isis.core.metamodel.facetapi.FacetUtil; @@ -38,17 +38,13 @@ public class ObjectLayoutMetadataFacetFactory extends FacetFactoryAbstract imple @Override public void process(final ProcessClassContext processClassContext) { - final Class<?> cls = processClassContext.getCls(); final FacetHolder facetHolder = processClassContext.getFacetHolder(); + final TranslationService translationService = servicesInjector.lookupService(TranslationService.class); final ObjectLayoutMetadataService objectLayoutMetadataService = servicesInjector.lookupService(ObjectLayoutMetadataService.class); FacetUtil.addFacet( - ObjectLayoutMetadataFacetDefault.create(facetHolder, readMetadata(cls), objectLayoutMetadataService)); - } - - private ObjectLayoutMetadata readMetadata(final Class<?> domainClass) { - final ObjectLayoutMetadataService objectLayoutMetadataService = servicesInjector.lookupService(ObjectLayoutMetadataService.class); - return objectLayoutMetadataService.fromXml(domainClass); + ObjectLayoutMetadataFacetDefault.create(facetHolder, + translationService, objectLayoutMetadataService)); } private ServicesInjector servicesInjector; http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/ObjectLayoutMetadataServiceDefault.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/ObjectLayoutMetadataServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/ObjectLayoutMetadataServiceDefault.java index 3080769..6431486 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/ObjectLayoutMetadataServiceDefault.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/layout/ObjectLayoutMetadataServiceDefault.java @@ -19,16 +19,10 @@ package org.apache.isis.core.metamodel.services.layout; import java.io.IOException; import java.net.URL; import java.nio.charset.Charset; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; import javax.inject.Inject; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.io.Resources; @@ -38,60 +32,17 @@ import org.slf4j.LoggerFactory; import org.apache.isis.applib.annotation.DomainService; import org.apache.isis.applib.annotation.NatureOfService; import org.apache.isis.applib.annotation.Programmatic; -import org.apache.isis.applib.layout.v1_0.ActionHolder; -import org.apache.isis.applib.layout.v1_0.ActionLayoutMetadata; -import org.apache.isis.applib.layout.v1_0.CollectionLayoutMetadata; -import org.apache.isis.applib.layout.v1_0.Column; -import org.apache.isis.applib.layout.v1_0.ColumnHolder; import org.apache.isis.applib.layout.v1_0.ObjectLayoutMetadata; -import org.apache.isis.applib.layout.v1_0.PropertyGroup; -import org.apache.isis.applib.layout.v1_0.PropertyLayoutMetadata; -import org.apache.isis.applib.layout.v1_0.Tab; -import org.apache.isis.applib.layout.v1_0.TabGroup; -import org.apache.isis.applib.services.i18n.TranslationService; import org.apache.isis.applib.services.jaxb.JaxbService; import org.apache.isis.applib.services.layout.ObjectLayoutMetadataService; -import org.apache.isis.core.metamodel.deployment.DeploymentCategory; -import org.apache.isis.core.metamodel.deployment.DeploymentCategoryAware; -import org.apache.isis.core.metamodel.facetapi.FacetUtil; -import org.apache.isis.core.metamodel.facets.actions.layout.ActionPositionFacetForActionXml; -import org.apache.isis.core.metamodel.facets.actions.layout.BookmarkPolicyFacetForActionXml; -import org.apache.isis.core.metamodel.facets.actions.layout.CssClassFaFacetForActionXml; -import org.apache.isis.core.metamodel.facets.actions.layout.CssClassFacetForActionXml; -import org.apache.isis.core.metamodel.facets.actions.layout.DescribedAsFacetForActionXml; -import org.apache.isis.core.metamodel.facets.actions.layout.HiddenFacetForActionLayoutXml; -import org.apache.isis.core.metamodel.facets.actions.layout.NamedFacetForActionXml; -import org.apache.isis.core.metamodel.facets.collections.layout.CssClassFacetForCollectionXml; -import org.apache.isis.core.metamodel.facets.collections.layout.DefaultViewFacetForCollectionXml; -import org.apache.isis.core.metamodel.facets.collections.layout.DescribedAsFacetForCollectionXml; -import org.apache.isis.core.metamodel.facets.collections.layout.HiddenFacetForCollectionXml; -import org.apache.isis.core.metamodel.facets.collections.layout.NamedFacetForCollectionXml; -import org.apache.isis.core.metamodel.facets.collections.layout.PagedFacetForCollectionXml; -import org.apache.isis.core.metamodel.facets.collections.layout.SortedByFacetForCollectionXml; -import org.apache.isis.core.metamodel.facets.members.order.annotprop.MemberOrderFacetXml; import org.apache.isis.core.metamodel.facets.object.layoutmetadata.ObjectLayoutMetadataFacet; -import org.apache.isis.core.metamodel.facets.object.membergroups.MemberGroupLayoutFacet; -import org.apache.isis.core.metamodel.facets.properties.propertylayout.CssClassFacetForPropertyXml; -import org.apache.isis.core.metamodel.facets.properties.propertylayout.DescribedAsFacetForPropertyXml; -import org.apache.isis.core.metamodel.facets.properties.propertylayout.HiddenFacetForPropertyXml; -import org.apache.isis.core.metamodel.facets.properties.propertylayout.LabelAtFacetForPropertyXml; -import org.apache.isis.core.metamodel.facets.properties.propertylayout.MultiLineFacetForPropertyXml; -import org.apache.isis.core.metamodel.facets.properties.propertylayout.NamedFacetForPropertyXml; -import org.apache.isis.core.metamodel.facets.properties.propertylayout.RenderedAdjustedFacetForPropertyXml; -import org.apache.isis.core.metamodel.facets.properties.propertylayout.TypicalLengthFacetForPropertyXml; import org.apache.isis.core.metamodel.spec.ObjectSpecification; import org.apache.isis.core.metamodel.spec.SpecificationLoader; import org.apache.isis.core.metamodel.spec.SpecificationLoaderAware; -import org.apache.isis.core.metamodel.spec.feature.Contributed; -import org.apache.isis.core.metamodel.spec.feature.ObjectAction; -import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation; -import org.apache.isis.core.metamodel.spec.feature.ObjectMember; -import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation; -import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation; @DomainService(nature = NatureOfService.DOMAIN) public class ObjectLayoutMetadataServiceDefault - implements ObjectLayoutMetadataService, DeploymentCategoryAware , SpecificationLoaderAware { + implements ObjectLayoutMetadataService, SpecificationLoaderAware { private static final Logger LOG = LoggerFactory.getLogger(ObjectLayoutMetadataServiceDefault.class); @@ -139,316 +90,6 @@ public class ObjectLayoutMetadataServiceDefault } - @Override - public ObjectLayoutMetadata normalize(final ObjectLayoutMetadata objectLayoutMetadata, final Class<?> domainClass) { - // caching (of whether validated) is enabled only in production. - return objectLayoutMetadata.isNormalized() && deploymentCategory.isProduction() - ? objectLayoutMetadata - : deriveAndOverwrite(objectLayoutMetadata, domainClass); - } - - private ObjectLayoutMetadata deriveAndOverwrite(final ObjectLayoutMetadata objectLayoutMetadata, final Class<?> domainClass) { - synchronized (objectLayoutMetadata) { - final ObjectSpecification objectSpec = specificationLookup.loadSpecification(domainClass); - doDeriveAndOverwrite(objectLayoutMetadata, objectSpec); - objectLayoutMetadata.setNormalized(true); - } - return objectLayoutMetadata; - } - - private void doDeriveAndOverwrite(final ObjectLayoutMetadata metadata, final ObjectSpecification objectSpec) { - - final Map<String, OneToOneAssociation> oneToOneAssociationById = - ObjectMember.Util.mapById(getOneToOneAssociations(objectSpec)); - final Map<String, OneToManyAssociation> oneToManyAssociationById = - ObjectMember.Util.mapById(getOneToManyAssociations(objectSpec)); - final Map<String, ObjectAction> objectActionById = - ObjectMember.Util.mapById(objectSpec.getObjectActions(Contributed.INCLUDED)); - - derive(metadata, oneToOneAssociationById, oneToManyAssociationById, objectActionById); - overwrite(metadata, oneToOneAssociationById, oneToManyAssociationById, objectActionById); - } - - /** - * Ensures that all object members (properties, collections and actions) are in the metadata. - * - * <p> - * If they are missing then they will be added to default tabs (created on the fly if need be). - * </p> - */ - private static void derive( - final ObjectLayoutMetadata metadata, - final Map<String, OneToOneAssociation> oneToOneAssociationById, - final Map<String, OneToManyAssociation> oneToManyAssociationById, - final Map<String, ObjectAction> objectActionById) { - - final LinkedHashMap<String, PropertyLayoutMetadata> propertyIds = metadata.getAllPropertiesById(); - final LinkedHashMap<String, CollectionLayoutMetadata> collectionIds = metadata.getAllCollectionsById(); - final LinkedHashMap<String, ActionLayoutMetadata> actionIds = metadata.getAllActionsById(); - - final AtomicReference<PropertyGroup> defaultPropertyGroupRef = new AtomicReference<>(); - final AtomicReference<Column> firstColumnRef = new AtomicReference<>(); - final AtomicReference<TabGroup> lastTabGroupRef = new AtomicReference<>(); - - // capture the first column, and also - // capture the first property group (if any) with the default name ('General') - metadata.visit(new ObjectLayoutMetadata.VisitorAdapter() { - @Override - public void visit(final Column column) { - firstColumnRef.compareAndSet(null, column); - } - @Override - public void visit(final PropertyGroup propertyGroup) { - if(MemberGroupLayoutFacet.DEFAULT_GROUP.equals(propertyGroup.getName())) { - defaultPropertyGroupRef.compareAndSet(null, propertyGroup); - } - } - @Override - public void visit(final TabGroup tabGroup) { - lastTabGroupRef.set(tabGroup); - } - }); - - // any missing properties will be added to the (first) 'General' property group found - // if there is no default ('General') property group - // then one will be added to the first Column of the first Tab. - final List<String>[] propertyIdTuple = surplusAndMissing(propertyIds.keySet(), oneToOneAssociationById.keySet()); - final List<String> surplusPropertyIds = propertyIdTuple[0]; - final List<String> missingPropertyIds = propertyIdTuple[1]; - - for (String surplusPropertyId : surplusPropertyIds) { - propertyIds.get(surplusPropertyId).setMetadataError("No such property"); - } - - if(!missingPropertyIds.isEmpty()) { - // ensure that there is a property group to use - boolean wasSet = defaultPropertyGroupRef.compareAndSet(null, new PropertyGroup(MemberGroupLayoutFacet.DEFAULT_GROUP)); - final PropertyGroup defaultPropertyGroup = defaultPropertyGroupRef.get(); - if(wasSet) { - firstColumnRef.get().getPropertyGroups().add(defaultPropertyGroup); - } - for (final String propertyId : missingPropertyIds) { - defaultPropertyGroup.getProperties().add(new PropertyLayoutMetadata(propertyId)); - } - } - - - // any missing collections will be added as tabs to the last TabGroup. - // If there is only a single tab group then a new TabGroup will be added first - final List<String>[] collectionIdTuple = surplusAndMissing(collectionIds.keySet(), oneToManyAssociationById.keySet()); - final List<String> surplusCollectionIds = collectionIdTuple[0]; - final List<String> missingCollectionIds = collectionIdTuple[1]; - - for (String surplusCollectionId : surplusCollectionIds) { - collectionIds.get(surplusCollectionId).setMetadataError("No such collection"); - } - - if(!missingCollectionIds.isEmpty()) { - while(metadata.getTabGroups().size() < 2) { - final TabGroup tabGroup = new TabGroup(); - metadata.getTabGroups().add(tabGroup); - lastTabGroupRef.set(tabGroup); - } - final TabGroup lastTabGroup = lastTabGroupRef.get(); - for (final String collectionId : missingCollectionIds) { - final Tab tab = new Tab(); - lastTabGroup.getTabs().add(tab); - Column left = new Column(12); - tab.setLeft(left); - final CollectionLayoutMetadata layoutMetadata = new CollectionLayoutMetadata(collectionId); - layoutMetadata.setDefaultView("table"); - left.getCollections().add(layoutMetadata); - } - } - - // any missing actions will be added as domain object actions (in the header) - final List<String>[] actionIdTuple = surplusAndMissing(actionIds.keySet(), objectActionById.keySet()); - final List<String> surplusActionIds = actionIdTuple[0]; - final List<String> missingActionIds = actionIdTuple[1]; - - for (String surplusActionId : surplusActionIds) { - actionIds.get(surplusActionId).setMetadataError("No such action"); - } - - if(!missingActionIds.isEmpty()) { - for (String actionId : missingActionIds) { - List<ActionLayoutMetadata> actions = metadata.getActions(); - if(actions == null) { - actions = Lists.newArrayList(); - metadata.setActions(actions); - } - actions.add(new ActionLayoutMetadata(actionId)); - } - } - } - - /** - * Returns a 2-element array (a tuple) of [first-second, second-first] - */ - static <T> List<T>[] surplusAndMissing(final java.util.Collection<T> first, final java.util.Collection<T> second){ - final List<T> firstNotSecond = Lists.newArrayList(first); - firstNotSecond.removeAll(second); - final List<T> secondNotFirst = Lists.newArrayList(second); - secondNotFirst.removeAll(first); - return new List[]{ firstNotSecond, secondNotFirst }; - } - - private void overwrite( - final ObjectLayoutMetadata metadata, - final Map<String, OneToOneAssociation> oneToOneAssociationById, - final Map<String, OneToManyAssociation> oneToManyAssociationById, - final Map<String, ObjectAction> objectActionById) { - - metadata.visit(new ObjectLayoutMetadata.VisitorAdapter() { - private final Map<String, int[]> propertySequenceByGroup = Maps.newHashMap(); - private int collectionSequence = 1; - private int actionDomainObjectSequence = 1; - private int actionPropertyGroupSequence = 1; - private int actionPropertySequence = 1; - private int actionCollectionSequence = 1; - - @Override - public void visit(final ActionLayoutMetadata actionLayoutMetadata) { - final ActionHolder actionHolder = actionLayoutMetadata.getOwner(); - final ObjectAction objectAction = objectActionById.get(actionLayoutMetadata.getId()); - if(objectAction == null) { - return; - } - - final String memberOrderName; - final int memberOrderSequence; - if(actionHolder instanceof PropertyGroup) { - final PropertyGroup propertyGroup = (PropertyGroup) actionHolder; - final List<PropertyLayoutMetadata> properties = propertyGroup.getProperties(); - final PropertyLayoutMetadata propertyLayoutMetadata = properties.get(0); // any will do - memberOrderName = propertyLayoutMetadata.getId(); - memberOrderSequence = actionPropertyGroupSequence++; - } else if(actionHolder instanceof PropertyLayoutMetadata) { - final PropertyLayoutMetadata propertyLayoutMetadata = (PropertyLayoutMetadata) actionHolder; - memberOrderName = propertyLayoutMetadata.getId(); - memberOrderSequence = actionPropertySequence++; - } else if(actionHolder instanceof CollectionLayoutMetadata) { - final CollectionLayoutMetadata collectionLayoutMetadata = (CollectionLayoutMetadata) actionHolder; - memberOrderName = collectionLayoutMetadata.getId(); - memberOrderSequence = actionCollectionSequence++; - } else { - // DomainObject - memberOrderName = null; - memberOrderSequence = actionDomainObjectSequence++; - } - FacetUtil.addFacet( - new MemberOrderFacetXml(memberOrderName, ""+memberOrderSequence, translationService, objectAction)); - - - if(actionHolder instanceof PropertyGroup) { - if(actionLayoutMetadata.getPosition() == null || - actionLayoutMetadata.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.BELOW || - actionLayoutMetadata.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.RIGHT) { - actionLayoutMetadata.setPosition(org.apache.isis.applib.annotation.ActionLayout.Position.PANEL); - } - } else if(actionHolder instanceof PropertyLayoutMetadata) { - if(actionLayoutMetadata.getPosition() == null || - actionLayoutMetadata.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.PANEL_DROPDOWN || - actionLayoutMetadata.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.PANEL) { - actionLayoutMetadata.setPosition(org.apache.isis.applib.annotation.ActionLayout.Position.BELOW); - } - } else { - // doesn't do anything for DomainObject or Collection - actionLayoutMetadata.setPosition(null); - } - - FacetUtil.addFacet(ActionPositionFacetForActionXml.create(actionLayoutMetadata, objectAction)); - FacetUtil.addFacet(BookmarkPolicyFacetForActionXml.create(actionLayoutMetadata, objectAction)); - FacetUtil.addFacet(CssClassFacetForActionXml.create(actionLayoutMetadata, objectAction)); - FacetUtil.addFacet(CssClassFaFacetForActionXml.create(actionLayoutMetadata, objectAction)); - FacetUtil.addFacet(DescribedAsFacetForActionXml.create(actionLayoutMetadata, objectAction)); - FacetUtil.addFacet(HiddenFacetForActionLayoutXml.create(actionLayoutMetadata, objectAction)); - FacetUtil.addFacet(NamedFacetForActionXml.create(actionLayoutMetadata, objectAction)); - } - - @Override - public void visit(final PropertyLayoutMetadata propertyLayoutMetadata) { - final OneToOneAssociation oneToOneAssociation = oneToOneAssociationById.get(propertyLayoutMetadata.getId()); - if(oneToOneAssociation == null) { - return; - } - - FacetUtil.addFacet(CssClassFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); - FacetUtil.addFacet(DescribedAsFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); - FacetUtil.addFacet(HiddenFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); - FacetUtil.addFacet(LabelAtFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); - FacetUtil.addFacet(MultiLineFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); - FacetUtil.addFacet(NamedFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); - FacetUtil.addFacet(RenderedAdjustedFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); - FacetUtil.addFacet(TypicalLengthFacetForPropertyXml.create(propertyLayoutMetadata, oneToOneAssociation)); - - // @MemberOrder#name based on owning property group, @MemberOrder#sequence monotonically increasing - final PropertyGroup propertyGroup = propertyLayoutMetadata.getOwner(); - final String groupName = propertyGroup.getName(); - final String sequence = nextInSequenceFor(groupName, propertySequenceByGroup); - FacetUtil.addFacet( - new MemberOrderFacetXml(groupName, sequence, translationService, oneToOneAssociation)); - } - - @Override - public void visit(final CollectionLayoutMetadata collectionLayoutMetadata) { - final OneToManyAssociation oneToManyAssociation = oneToManyAssociationById.get(collectionLayoutMetadata.getId()); - if(oneToManyAssociation == null) { - return; - } - - FacetUtil.addFacet(CssClassFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation)); - FacetUtil.addFacet(DefaultViewFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation)); - FacetUtil.addFacet(DescribedAsFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation)); - FacetUtil.addFacet(HiddenFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation)); - FacetUtil.addFacet(NamedFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation)); - FacetUtil.addFacet(PagedFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation)); - FacetUtil.addFacet(SortedByFacetForCollectionXml.create(collectionLayoutMetadata, oneToManyAssociation)); - - // @MemberOrder#name based on the collection's id (so that each has a single "member group") - final String groupName = collectionLayoutMetadata.getId(); - final String sequence = "" + collectionSequence++; - FacetUtil.addFacet( - new MemberOrderFacetXml(groupName, sequence, translationService, oneToManyAssociation)); - - // if there is only a single column and no other contents, then copy the collection Id onto the tab' - final Column column = collectionLayoutMetadata.getOwner(); - final ColumnHolder holder = column.getOwner(); - if(holder instanceof Tab) { - final Tab tab = (Tab) holder; - if(tab.getContents().size() == 1) { - final String collectionName = oneToManyAssociation.getName(); - tab.setName(collectionName); - } - } - } - - private String nextInSequenceFor( - final String key, final Map<String, int[]> seqByKey) { - synchronized (seqByKey) { - int[] holder = seqByKey.get(key); - if(holder == null) { - holder = new int[]{0}; - seqByKey.put(key, holder); - } - holder[0]++; - return ""+holder[0]; - } - } - }); - } - - private static List<OneToOneAssociation> getOneToOneAssociations(final ObjectSpecification objectSpec) { - List associations = objectSpec - .getAssociations(Contributed.INCLUDED, ObjectAssociation.Filters.PROPERTIES); - return associations; - } - private static List<OneToManyAssociation> getOneToManyAssociations(final ObjectSpecification objectSpec) { - List associations = objectSpec - .getAssociations(Contributed.INCLUDED, ObjectAssociation.Filters.COLLECTIONS); - return associations; - } - @Override public ObjectLayoutMetadata toMetadata(final Object domainObject) { @@ -462,16 +103,22 @@ public class ObjectLayoutMetadataServiceDefault return facet != null? facet.getMetadata(): null; } + //////////////////////////////////////////////////////// + private boolean dynamicReloading; - //region > injected dependencies - private DeploymentCategory deploymentCategory; + @Override + public void toggleDynamicReloading() { + this.dynamicReloading = !this.dynamicReloading; + } @Override - public void setDeploymentCategory(final DeploymentCategory deploymentCategory) { - this.deploymentCategory = deploymentCategory; + public boolean isDynamicReloading() { + return this.dynamicReloading; } + //region > injected dependencies + private SpecificationLoader specificationLookup; @Override @@ -479,12 +126,9 @@ public class ObjectLayoutMetadataServiceDefault this.specificationLookup = specificationLookup; } - @Inject JaxbService jaxbService; - @Inject - TranslationService translationService; //endregion http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetadataMenu.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetadataMenu.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetadataMenu.java index fadfae2..900ecc3 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetadataMenu.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetadataMenu.java @@ -132,6 +132,50 @@ public class MetadataMenu implements SpecificationLoaderSpiAware { // ////////////////////////////////////// + public static class SwitchOnDynamicReloadingOfLayoutsDomainEvent extends ActionDomainEvent { + } + + @Action( + domainEvent = SwitchOnDynamicReloadingOfLayoutsDomainEvent.class, + semantics = SemanticsOf.SAFE, + restrictTo = RestrictTo.PROTOTYPING + ) + @ActionLayout( + cssClassFa = "fa-check" + ) + @MemberOrder(sequence="500.400.2") + public void switchOnDynamicReloadingOfLayouts() { + objectLayoutMetadataService.toggleDynamicReloading(); + } + public boolean hideSwitchOnDynamicReloadingOfLayouts() { + return objectLayoutMetadataService.isDynamicReloading(); + } + + // ////////////////////////////////////// + + public static class SwitchOffDynamicReloadingOfLayoutsDomainEvent extends ActionDomainEvent { + } + + @Action( + domainEvent = SwitchOffDynamicReloadingOfLayoutsDomainEvent.class, + semantics = SemanticsOf.SAFE, + restrictTo = RestrictTo.PROTOTYPING + ) + @ActionLayout( + cssClassFa = "fa-times" + ) + @MemberOrder(sequence="500.400.3") + public void switchOffDynamicReloadingOfLayouts() { + objectLayoutMetadataService.toggleDynamicReloading(); + } + public boolean hideSwitchOffDynamicReloadingOfLayouts() { + return !objectLayoutMetadataService.isDynamicReloading(); + } + + + + // ////////////////////////////////////// + @Inject ObjectLayoutMetadataService objectLayoutMetadataService; @@ -146,5 +190,4 @@ public class MetadataMenu implements SpecificationLoaderSpiAware { this.specificationLoader = specificationLoader; } - } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java index e4abde8..5f4c0d1 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/ObjectReflectorDefault.java @@ -33,6 +33,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.isis.applib.AppManifest; +import org.apache.isis.applib.annotation.DomainService; +import org.apache.isis.applib.annotation.NatureOfService; import org.apache.isis.core.commons.components.ApplicationScopedComponent; import org.apache.isis.core.commons.config.IsisConfiguration; import org.apache.isis.core.commons.debug.DebugBuilder; @@ -256,7 +258,12 @@ public final class ObjectReflectorDefault private void loadSpecificationsForServices() { for (final Class<?> serviceClass : getServiceClasses()) { - internalLoadSpecification(serviceClass); + final DomainService domainService = serviceClass.getAnnotation(DomainService.class); + if(domainService != null) { + if(domainService.nature() == NatureOfService.VIEW || domainService.nature() == NatureOfService.VIEW_CONTRIBUTIONS_ONLY) { + internalLoadSpecification(serviceClass); + } + } } } @@ -515,6 +522,7 @@ public final class ObjectReflectorDefault facetDecoratorSet.decorate(specSpi); specSpi.updateFromFacetValues(); specSpi.setIntrospectionState(IntrospectionState.INTROSPECTED); + } @Override http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java index 9628a34..a6e71df 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java @@ -49,6 +49,7 @@ import org.apache.isis.core.metamodel.facets.FacetedMethod; import org.apache.isis.core.metamodel.facets.FacetedMethodParameter; import org.apache.isis.core.metamodel.facets.actcoll.typeof.TypeOfFacet; import org.apache.isis.core.metamodel.facets.object.facets.FacetsFacet; +import org.apache.isis.core.metamodel.facets.object.layoutmetadata.ObjectLayoutMetadataFacet; import org.apache.isis.core.metamodel.layoutmetadata.LayoutMetadataReader; import org.apache.isis.core.metamodel.layoutmetadata.LayoutMetadataReader.ReaderException; import org.apache.isis.core.metamodel.layoutmetadata.LayoutMetadataReader2; @@ -189,13 +190,14 @@ public class FacetedMethodsBuilder { public Properties introspectClass() { - if (LOG.isDebugEnabled()) { - LOG.debug("introspecting " + getClassName() + ": class-level details"); + if (LOG.isInfoEnabled()) { + LOG.info("introspecting " + getClassName() + ": class-level details"); } // process facets at object level // this will also remove some methods, such as the superclass methods. + final ObjectLayoutMetadataFacet facet = spec.getFacet(ObjectLayoutMetadataFacet.class); final Properties metadataProperties = readMetadataProperties(introspectedClass); getFacetProcessor().process(introspectedClass, metadataProperties, methodRemover, spec); http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java index 5aa6444..070a88d 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java @@ -22,6 +22,9 @@ import java.util.List; import com.google.common.collect.Lists; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.apache.isis.applib.Identifier; import org.apache.isis.applib.annotation.Bulk; import org.apache.isis.applib.annotation.InvokedOn; http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java index 071f760..afd556e 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java @@ -176,6 +176,8 @@ public class ObjectSpecificationDefault extends ObjectSpecificationAbstract impl sortCacheAndUpdateActions(actions); } + + if(isNotIntrospected()) { facetedMethodsBuilder.introspectClassPostProcessing(metadataProperties); } http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/metamodel/src/test/java/org/apache/isis/core/metamodel/layoutxml/v1_0/ObjectLayoutMetadataTest.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/layoutxml/v1_0/ObjectLayoutMetadataTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/layoutxml/v1_0/ObjectLayoutMetadataTest.java index 73df1fb..c5e8c1b 100644 --- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/layoutxml/v1_0/ObjectLayoutMetadataTest.java +++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/layoutxml/v1_0/ObjectLayoutMetadataTest.java @@ -77,8 +77,9 @@ public class ObjectLayoutMetadataTest { left.getCollections().add(similarToColl); similarToColl.setId("similarTo"); - PropertyLayoutMetadata namePropertyLayoutMetadata = leftPropGroup.getProperties().get(0); - namePropertyLayoutMetadata.setId("name"); + left.getPropertyGroups().add(new PropertyGroup("General")); + PropertyLayoutMetadata namePropertyLayoutMetadata = new PropertyLayoutMetadata("name"); + left.getPropertyGroups().get(0).getProperties().add(namePropertyLayoutMetadata); ActionLayoutMetadata updateNameActionLayoutMetadata = new ActionLayoutMetadata(); updateNameActionLayoutMetadata.setId("updateName"); http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java ---------------------------------------------------------------------- diff --git a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java index bebb67c..559e110 100644 --- a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java +++ b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java @@ -126,11 +126,14 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> { VIEW, EDIT; } + private final Map<PropertyMemento, ScalarModel> propertyScalarModels; private ObjectAdapterMemento adapterMemento; + private ObjectAdapterMemento contextAdapterIfAny; + private Mode mode = Mode.VIEW; private RenderingHint renderingHint = RenderingHint.REGULAR; - private final Map<PropertyMemento, ScalarModel> propertyScalarModels = Maps.newHashMap(); private Hint hint; + private final PendingModel pendingModel; /** * Toggled by 'entityDetailsButton'. @@ -149,7 +152,7 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> { // ////////////////////////////////////////////////////////// public EntityModel() { - pendingModel = new PendingModel(this); + this((ObjectAdapterMemento)null); } public EntityModel(final PageParameters pageParameters) { @@ -162,8 +165,13 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> { } public EntityModel(final ObjectAdapterMemento adapterMemento) { + this(adapterMemento, Maps.<PropertyMemento, ScalarModel>newHashMap()); + } + + public EntityModel(final ObjectAdapterMemento adapterMemento, final Map<PropertyMemento, ScalarModel> propertyScalarModels) { this.adapterMemento = adapterMemento; this.pendingModel = new PendingModel(this); + this.propertyScalarModels = propertyScalarModels; } public static String oidStr(final PageParameters pageParameters) { @@ -608,8 +616,6 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> { } } - private final PendingModel pendingModel; - private ObjectAdapterMemento contextAdapterIfAny; public ObjectAdapter getPendingElseCurrentAdapter() { return pendingModel.getPendingElseCurrentAdapter(); @@ -642,19 +648,27 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> { return tabMetadata; } - public EntityModel withTabMetadata(final Tab tabMetadata) { - this.tabMetadata = tabMetadata; - return this; + /** + * Returns a new copy that SHARES the property scalar models (for edit form). + */ + public EntityModel cloneWithTabMetadata(final Tab tabMetadata) { + final EntityModel entityModel = new EntityModel(this.adapterMemento, this.propertyScalarModels); + entityModel.tabMetadata = tabMetadata; + return entityModel; } private Column columnMetadata; private Column.Hint columnHint; - public EntityModel withColumnMetadata(final Column columnMetadata, final Column.Hint columnHint) { - this.columnMetadata = columnMetadata; - this.columnHint = columnHint; - return this; + /** + * Returns a new copy that SHARES the property scalar models (for edit form). + */ + public EntityModel cloneWithColumnMetadata(final Column columnMetadata, final Column.Hint columnHint) { + final EntityModel entityModel = new EntityModel(this.adapterMemento, this.propertyScalarModels); + entityModel.columnMetadata = columnMetadata; + entityModel.columnHint = columnHint; + return entityModel; } public Column getColumnMetadata() { http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java ---------------------------------------------------------------------- diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java index 32c0900..004ba23 100644 --- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java +++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/combined/EntityCombinedPanelFactory.java @@ -22,8 +22,6 @@ package org.apache.isis.viewer.wicket.ui.components.entity.combined; import org.apache.wicket.Component; import org.apache.wicket.model.IModel; -import org.apache.isis.core.metamodel.facets.object.layoutmetadata.ObjectLayoutMetadataFacet; -import org.apache.isis.core.metamodel.spec.ObjectSpecification; import org.apache.isis.viewer.wicket.model.models.EntityModel; import org.apache.isis.viewer.wicket.ui.ComponentFactory; import org.apache.isis.viewer.wicket.ui.ComponentType; @@ -44,14 +42,11 @@ public class EntityCombinedPanelFactory extends EntityComponentFactoryAbstract { @Override protected ApplicationAdvice doAppliesTo(final EntityModel entityModel) { - final ObjectSpecification specification = entityModel.getTypeOfSpecification(); - // opposite to the EntityTabbedPanelFactory - return appliesIf(!specification.containsDoOpFacet(ObjectLayoutMetadataFacet.class)); + return appliesIf(false); // TODO: remove } @Override public Component createComponent(final String id, final IModel<?> model) { - final EntityModel entityModel = (EntityModel) model; - return new EntityCombinedPanel(id, entityModel); + throw new IllegalStateException("shouldn't be called"); // TODO: remove } } http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityColumnMembers.java ---------------------------------------------------------------------- diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityColumnMembers.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityColumnMembers.java index 3e0cd3f..a294969 100644 --- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityColumnMembers.java +++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityColumnMembers.java @@ -73,14 +73,13 @@ public class EntityColumnMembers extends PanelAbstract<EntityModel> { final Component owningPanel) { super(id, entityModel); - this.owningPanel = owningPanel; // for repainting + this.owningPanel = owningPanel; // for repainting, perhaps buildGui(); } private void buildGui() { - final EntityModel entityModel = (EntityModel) getModel(); - addPropertiesAndCollections(this, entityModel); + addPropertiesAndCollections(this, getModel()); } private void addPropertiesAndCollections( http://git-wip-us.apache.org/repos/asf/isis/blob/2e8c0943/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java ---------------------------------------------------------------------- diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java index 24837b6..31c54a1 100644 --- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java +++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/properties/EntityPropertiesForm.java @@ -238,9 +238,7 @@ public class EntityPropertiesForm extends FormAbstract<ObjectAdapter> implements final Hint hint) { final Column columnMetaDataIfAny = hint.from(tabMetaDataIfAny); - final EntityModel entityModelWithHints = - new EntityModel(entityModel.getPageParameters()) - .withColumnMetadata(columnMetaDataIfAny, hint); + final EntityModel entityModelWithHints = entityModel.cloneWithColumnMetadata(columnMetaDataIfAny, hint); final EntityColumnMembers columnMembers = new EntityColumnMembers("entityMembers", entityModelWithHints, markupContainer);