/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.isis.core.metamodel.services.grid; import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import com.google.common.base.Strings; import com.google.common.collect.Lists; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.isis.applib.DomainObjectContainer; import org.apache.isis.applib.annotation.ActionLayout; import org.apache.isis.applib.annotation.BookmarkPolicy; import org.apache.isis.applib.annotation.LabelPosition; import org.apache.isis.applib.annotation.Programmatic; import org.apache.isis.applib.annotation.Where; import org.apache.isis.applib.layout.component.ActionLayoutData; import org.apache.isis.applib.layout.component.ActionLayoutDataOwner; import org.apache.isis.applib.layout.component.CollectionLayoutData; import org.apache.isis.applib.layout.component.DomainObjectLayoutData; import org.apache.isis.applib.layout.component.DomainObjectLayoutDataOwner; import org.apache.isis.applib.layout.component.FieldSet; import org.apache.isis.applib.layout.component.Grid; import org.apache.isis.applib.layout.component.HasBookmarking; import org.apache.isis.applib.layout.component.HasCssClass; import org.apache.isis.applib.layout.component.HasCssClassFa; import org.apache.isis.applib.layout.component.HasDescribedAs; import org.apache.isis.applib.layout.component.HasHidden; import org.apache.isis.applib.layout.component.HasNamed; import org.apache.isis.applib.layout.component.PropertyLayoutData; import org.apache.isis.applib.services.grid.GridSystemService; import org.apache.isis.applib.services.i18n.TranslationService; import org.apache.isis.applib.services.jaxb.JaxbService; import org.apache.isis.applib.services.message.MessageService; import org.apache.isis.core.metamodel.deployment.DeploymentCategoryProvider; import org.apache.isis.core.metamodel.facetapi.Facet; 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.HiddenFacetForActionXml; import org.apache.isis.core.metamodel.facets.actions.layout.NamedFacetForActionXml; import org.apache.isis.core.metamodel.facets.actions.layout.PromptStyleFacetForActionXml; import org.apache.isis.core.metamodel.facets.actions.position.ActionPositionFacet; import org.apache.isis.core.metamodel.facets.all.describedas.DescribedAsFacet; import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet; import org.apache.isis.core.metamodel.facets.all.named.NamedFacet; import org.apache.isis.core.metamodel.facets.collections.collection.defaultview.DefaultViewFacet; 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.collections.sortedby.SortedByFacet; import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet; import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaFacet; import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaPosition; import org.apache.isis.core.metamodel.facets.members.order.annotprop.MemberOrderFacetXml; import org.apache.isis.core.metamodel.facets.object.bookmarkpolicy.BookmarkPolicyFacet; import org.apache.isis.core.metamodel.facets.object.domainobjectlayout.BookmarkPolicyFacetForDomainObjectXml; import org.apache.isis.core.metamodel.facets.object.domainobjectlayout.CssClassFaFacetForDomainObjectXml; import org.apache.isis.core.metamodel.facets.object.domainobjectlayout.CssClassFacetForDomainObjectXml; import org.apache.isis.core.metamodel.facets.object.domainobjectlayout.DescribedAsFacetForDomainObjectXml; import org.apache.isis.core.metamodel.facets.object.domainobjectlayout.NamedFacetForDomainObjectXml; import org.apache.isis.core.metamodel.facets.object.domainobjectlayout.PluralFacetForDomainObjectXml; import org.apache.isis.core.metamodel.facets.object.paged.PagedFacet; import org.apache.isis.core.metamodel.facets.object.plural.PluralFacet; import org.apache.isis.core.metamodel.facets.objectvalue.labelat.LabelAtFacet; import org.apache.isis.core.metamodel.facets.objectvalue.multiline.MultiLineFacet; import org.apache.isis.core.metamodel.facets.objectvalue.renderedadjusted.RenderedAdjustedFacet; import org.apache.isis.core.metamodel.facets.objectvalue.typicallen.TypicalLengthFacet; 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.PromptStyleFacetForPropertyXml; 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.facets.properties.propertylayout.UnchangingFacetForPropertyXml; 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; import org.apache.isis.core.metamodel.specloader.SpecificationLoader; public abstract class GridSystemServiceAbstract<G extends Grid> implements GridSystemService<G> { private static final Logger LOG = LoggerFactory.getLogger(GridSystemServiceAbstract.class); private final Class<G> gridImplementation; private final String tns; private final String schemaLocation; public GridSystemServiceAbstract( final Class<G> gridImplementation, final String tns, final String schemaLocation) { this.gridImplementation = gridImplementation; this.tns = tns; this.schemaLocation = schemaLocation; } // ////////////////////////////////////// @Programmatic @Override public Class<G> gridImplementation() { return gridImplementation; } @Programmatic @Override public String tns() { return tns; } @Programmatic @Override public String schemaLocation() { return schemaLocation; } // ////////////////////////////////////// @Programmatic @Override public void normalize(final G grid, final Class<?> domainClass) { if(!gridImplementation.isAssignableFrom(grid.getClass())) { // ignore any other grid implementations return; } final boolean valid = validateAndNormalize( grid, domainClass); if (valid) { overwriteFacets(grid, domainClass); if(LOG.isDebugEnabled()) { LOG.debug("Grid:\n\n" + jaxbService.toXml(grid) + "\n\n"); } } else { if(!deploymentCategoryProvider.getDeploymentCategory().isProduction()) { messageService.warnUser("Grid metadata errors for " + grid.getDomainClass().getName() + "; check the error log"); } LOG.error("Grid metadata errors:\n\n" + jaxbService.toXml(grid) + "\n\n"); } } /** * Mandatory hook method for subclasses, where they must ensure that all object members (properties, collections * and actions) are in the grid metadata, typically by deriving this information from other existing metadata * (eg facets from annotations) or just by applying default rules. */ protected abstract boolean validateAndNormalize( final Grid grid, final Class<?> domainClass); /** * Overwrites (replaces) any existing facets in the metamodel with info taken from the grid. * * <p> * This code uses {@link FacetUtil#addOrReplaceFacet(Facet)} because the layout might be changed multiple times. * </p> */ protected void overwriteFacets( final G fcGrid, final Class<?> domainClass) { final ObjectSpecification objectSpec = specificationLoader.loadSpecification(domainClass); 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)); final AtomicInteger propertySequence = new AtomicInteger(0); fcGrid.visit(new Grid.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 DomainObjectLayoutData domainObjectLayoutData) { FacetUtil.addOrReplaceFacet(BookmarkPolicyFacetForDomainObjectXml.create(domainObjectLayoutData, objectSpec)); FacetUtil.addOrReplaceFacet(CssClassFacetForDomainObjectXml.create(domainObjectLayoutData, objectSpec)); FacetUtil.addOrReplaceFacet(CssClassFaFacetForDomainObjectXml.create(domainObjectLayoutData, objectSpec)); FacetUtil.addOrReplaceFacet(DescribedAsFacetForDomainObjectXml.create(domainObjectLayoutData, objectSpec)); FacetUtil.addOrReplaceFacet(NamedFacetForDomainObjectXml.create(domainObjectLayoutData, objectSpec)); FacetUtil.addOrReplaceFacet(PluralFacetForDomainObjectXml.create(domainObjectLayoutData, objectSpec)); } @Override public void visit(final ActionLayoutData actionLayoutData) { final ActionLayoutDataOwner actionLayoutDataOwner = actionLayoutData.getOwner(); final ObjectAction objectAction = objectActionById.get(actionLayoutData.getId()); if(objectAction == null) { return; } String memberOrderName = null; int memberOrderSequence; if(actionLayoutDataOwner instanceof FieldSet) { final FieldSet fieldSet = (FieldSet) actionLayoutDataOwner; final List<PropertyLayoutData> properties = fieldSet.getProperties(); for (PropertyLayoutData propertyLayoutData : properties) { final String propertyId = propertyLayoutData.getId(); // any will do; choose the first one that we know is valid if(oneToOneAssociationById.containsKey(propertyId)) { memberOrderName = propertyLayoutData.getId(); break; } } memberOrderSequence = actionPropertyGroupSequence++; } else if(actionLayoutDataOwner instanceof PropertyLayoutData) { final PropertyLayoutData propertyLayoutData = (PropertyLayoutData) actionLayoutDataOwner; memberOrderName = propertyLayoutData.getId(); memberOrderSequence = actionPropertySequence++; } else if(actionLayoutDataOwner instanceof CollectionLayoutData) { final CollectionLayoutData collectionLayoutData = (CollectionLayoutData) actionLayoutDataOwner; memberOrderName = collectionLayoutData.getId(); memberOrderSequence = actionCollectionSequence++; } else { // don't add: any existing metadata should be preserved memberOrderName = null; memberOrderSequence = actionDomainObjectSequence++; } if(memberOrderName != null) { FacetUtil.addOrReplaceFacet( new MemberOrderFacetXml(memberOrderName, "" + memberOrderSequence, translationService, objectAction)); } // fix up the action position if required if(actionLayoutDataOwner instanceof FieldSet) { if(actionLayoutData.getPosition() == null || actionLayoutData.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.BELOW || actionLayoutData.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.RIGHT) { actionLayoutData.setPosition(org.apache.isis.applib.annotation.ActionLayout.Position.PANEL); } } else if(actionLayoutDataOwner instanceof PropertyLayoutData) { if(actionLayoutData.getPosition() == null || actionLayoutData.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.PANEL_DROPDOWN || actionLayoutData.getPosition() == org.apache.isis.applib.annotation.ActionLayout.Position.PANEL) { actionLayoutData.setPosition(org.apache.isis.applib.annotation.ActionLayout.Position.BELOW); } } else { // doesn't do anything for DomainObject or Collection actionLayoutData.setPosition(null); } FacetUtil.addOrReplaceFacet(ActionPositionFacetForActionXml.create(actionLayoutData, objectAction)); FacetUtil.addOrReplaceFacet(BookmarkPolicyFacetForActionXml.create(actionLayoutData, objectAction)); FacetUtil.addOrReplaceFacet(CssClassFacetForActionXml.create(actionLayoutData, objectAction)); FacetUtil.addOrReplaceFacet(CssClassFaFacetForActionXml.create(actionLayoutData, objectAction)); FacetUtil.addOrReplaceFacet(DescribedAsFacetForActionXml.create(actionLayoutData, objectAction)); FacetUtil.addOrReplaceFacet(HiddenFacetForActionXml.create(actionLayoutData, objectAction)); FacetUtil.addOrReplaceFacet(NamedFacetForActionXml.create(actionLayoutData, objectAction)); FacetUtil.addOrReplaceFacet(PromptStyleFacetForActionXml.create(actionLayoutData, objectAction)); } @Override public void visit(final PropertyLayoutData propertyLayoutData) { final OneToOneAssociation oneToOneAssociation = oneToOneAssociationById.get(propertyLayoutData.getId()); if(oneToOneAssociation == null) { return; } FacetUtil.addOrReplaceFacet(CssClassFacetForPropertyXml.create(propertyLayoutData, oneToOneAssociation)); FacetUtil.addOrReplaceFacet(DescribedAsFacetForPropertyXml.create(propertyLayoutData, oneToOneAssociation)); FacetUtil.addOrReplaceFacet(HiddenFacetForPropertyXml.create(propertyLayoutData, oneToOneAssociation)); FacetUtil.addOrReplaceFacet(LabelAtFacetForPropertyXml.create(propertyLayoutData, oneToOneAssociation)); FacetUtil.addOrReplaceFacet(MultiLineFacetForPropertyXml.create(propertyLayoutData, oneToOneAssociation)); FacetUtil.addOrReplaceFacet(NamedFacetForPropertyXml.create(propertyLayoutData, oneToOneAssociation)); FacetUtil.addOrReplaceFacet( PromptStyleFacetForPropertyXml.create(propertyLayoutData, oneToOneAssociation)); FacetUtil.addOrReplaceFacet( RenderedAdjustedFacetForPropertyXml.create(propertyLayoutData, oneToOneAssociation)); FacetUtil.addOrReplaceFacet( UnchangingFacetForPropertyXml.create(propertyLayoutData, oneToOneAssociation)); FacetUtil.addOrReplaceFacet(TypicalLengthFacetForPropertyXml.create(propertyLayoutData, oneToOneAssociation)); // @MemberOrder#name based on owning property group, @MemberOrder#sequence monotonically increasing // nb for any given field set the sequence won't reset to zero; however this is what we want so that // table columns are shown correctly (by fieldset, then property order within that fieldset). final FieldSet fieldSet = propertyLayoutData.getOwner(); final String groupName = fieldSet.getName(); final String sequence = "" + (propertySequence.incrementAndGet()); FacetUtil.addOrReplaceFacet( new MemberOrderFacetXml(groupName, sequence, translationService, oneToOneAssociation)); } @Override public void visit(final CollectionLayoutData collectionLayoutData) { final OneToManyAssociation oneToManyAssociation = oneToManyAssociationById.get(collectionLayoutData.getId()); if(oneToManyAssociation == null) { return; } FacetUtil.addOrReplaceFacet(CssClassFacetForCollectionXml.create(collectionLayoutData, oneToManyAssociation)); FacetUtil.addOrReplaceFacet( DefaultViewFacetForCollectionXml.create(collectionLayoutData, oneToManyAssociation)); FacetUtil.addOrReplaceFacet( DescribedAsFacetForCollectionXml.create(collectionLayoutData, oneToManyAssociation)); FacetUtil.addOrReplaceFacet(HiddenFacetForCollectionXml.create(collectionLayoutData, oneToManyAssociation)); FacetUtil.addOrReplaceFacet(NamedFacetForCollectionXml.create(collectionLayoutData, oneToManyAssociation)); FacetUtil.addOrReplaceFacet(PagedFacetForCollectionXml.create(collectionLayoutData, oneToManyAssociation)); FacetUtil.addOrReplaceFacet(SortedByFacetForCollectionXml.create(collectionLayoutData, oneToManyAssociation)); // @MemberOrder#name based on the collection's id (so that each has a single "member group") final String groupName = collectionLayoutData.getId(); final String sequence = "" + collectionSequence++; FacetUtil.addOrReplaceFacet( new MemberOrderFacetXml(groupName, sequence, translationService, oneToManyAssociation)); } }); } protected static List<OneToOneAssociation> getOneToOneAssociations(final ObjectSpecification objectSpec) { List associations = objectSpec.getAssociations(Contributed.INCLUDED, ObjectAssociation.Filters.PROPERTIES); return associations; } protected static List<OneToManyAssociation> getOneToManyAssociations(final ObjectSpecification objectSpec) { List associations = objectSpec.getAssociations(Contributed.INCLUDED, ObjectAssociation.Filters.COLLECTIONS); return associations; } protected static class Tuple<T> { public final T first; public 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] */ protected 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); } // ////////////////////////////////////// @Programmatic @Override public void complete(final G grid, final Class<?> domainClass) { normalize(grid, domainClass); final ObjectSpecification objectSpec = specificationLoader.loadSpecification(domainClass); grid.visit(new Grid.VisitorAdapter() { @Override public void visit(final ActionLayoutData actionLayoutData) { final ObjectAction objectAction = objectSpec.getObjectAction(actionLayoutData.getId()); setBookmarkingIfAny(actionLayoutData, objectAction); setCssClassIfAny(actionLayoutData, objectAction); setCssClassFaIfAny(actionLayoutData, objectAction); setDescribedAsIfAny(actionLayoutData, objectAction); setHiddenIfAny(actionLayoutData, objectAction); setNamedIfAny(actionLayoutData, objectAction); setActionPositionIfAny(actionLayoutData, objectAction); } @Override public void visit(final CollectionLayoutData collectionLayoutData) { final ObjectAssociation collection = objectSpec.getAssociation(collectionLayoutData.getId()); setCssClassIfAny(collectionLayoutData, collection); setDefaultViewIfAny(collectionLayoutData, collection); setDescribedAsIfAny(collectionLayoutData, collection); setHiddenIfAny(collectionLayoutData, collection); setNamedIfAny(collectionLayoutData, collection); setPagedIfAny(collectionLayoutData, collection); setSortedByIfAny(collectionLayoutData, collection); } @Override public void visit(final PropertyLayoutData propertyLayoutData) { final ObjectAssociation property = objectSpec.getAssociation(propertyLayoutData.getId()); setCssClassIfAny(propertyLayoutData, property); setDescribedAsIfAny(propertyLayoutData, property); setHiddenIfAny(propertyLayoutData, property); setNamedIfAny(propertyLayoutData, property); setLabelPositionIfAny(propertyLayoutData, property); setMultiLineIfAny(propertyLayoutData, property); setRenderedAsDayBeforeIfAny(propertyLayoutData, property); setTypicalLengthIfAny(propertyLayoutData, property); } @Override public void visit(final DomainObjectLayoutData domainObjectLayoutData) { setBookmarkingIfAny(domainObjectLayoutData, objectSpec); setCssClassIfAny(domainObjectLayoutData, objectSpec); setCssClassFaIfAny(domainObjectLayoutData, objectSpec); setDescribedAsIfAny(domainObjectLayoutData, objectSpec); setNamedIfAny(domainObjectLayoutData, objectSpec); setPluralIfAny(domainObjectLayoutData, objectSpec); } }); } private static boolean isDoOp(final Facet facet) { return facet != null && !facet.isNoop(); } protected void setBookmarkingIfAny( final HasBookmarking hasBookmarking, final FacetHolder facetHolder) { final BookmarkPolicyFacet bookmarkPolicyFacet = facetHolder.getFacet(BookmarkPolicyFacet.class); if(isDoOp(bookmarkPolicyFacet)) { final BookmarkPolicy bookmarking = bookmarkPolicyFacet.value(); if(bookmarking != null) { hasBookmarking.setBookmarking(bookmarking); } } } protected void setCssClassIfAny( final HasCssClass hasCssClass, final FacetHolder facetHolder) { final CssClassFacet cssClassFacet = facetHolder.getFacet(CssClassFacet.class); if(isDoOp(cssClassFacet)) { try { // try...finally because CSS class may vary by object, and we pass in only null final String cssClass = cssClassFacet.cssClass(null); if(!Strings.isNullOrEmpty(cssClass)) { hasCssClass.setCssClass(cssClass); } } catch(Exception ignore) { // ignore } } } protected void setCssClassFaIfAny( final HasCssClassFa hasCssClassFa, final FacetHolder facetHolder) { final CssClassFaFacet cssClassFaFacet = facetHolder.getFacet(CssClassFaFacet.class); if (isDoOp(cssClassFaFacet)) { final String cssClassFa = cssClassFaFacet.value(); final CssClassFaPosition position = cssClassFaFacet.getPosition(); if(!Strings.isNullOrEmpty(cssClassFa)) { hasCssClassFa.setCssClassFa(cssClassFa); hasCssClassFa.setCssClassFaPosition(position.toActionLayoutPosition()); } } } protected void setDefaultViewIfAny( final CollectionLayoutData collectionLayoutData, final FacetHolder facetHolder) { final DefaultViewFacet defaultViewFacet = facetHolder.getFacet(DefaultViewFacet.class); if(isDoOp(defaultViewFacet)) { final String defaultView = defaultViewFacet.value(); if(!Strings.isNullOrEmpty(defaultView)) { collectionLayoutData.setDefaultView(defaultView); } } } protected void setDescribedAsIfAny( final HasDescribedAs hasDescribedAs, final FacetHolder facetHolder) { final DescribedAsFacet describedAsFacet = facetHolder.getFacet(DescribedAsFacet.class); if(isDoOp(describedAsFacet)) { final String describedAs = describedAsFacet.value(); if(!Strings.isNullOrEmpty(describedAs)) { hasDescribedAs.setDescribedAs(describedAs); } } } protected void setHiddenIfAny( final HasHidden hasHidden, final FacetHolder facetHolder) { final HiddenFacet hiddenFacet = facetHolder.getFacet(HiddenFacet.class); if (isDoOp(hiddenFacet)) { final Where where = hiddenFacet.where(); if(where != null) { hasHidden.setHidden(where); } } } protected void setLabelPositionIfAny( final PropertyLayoutData propertyLayoutData, final FacetHolder facetHolder) { final LabelAtFacet labelAtFacet = facetHolder.getFacet(LabelAtFacet.class); if(isDoOp(labelAtFacet)) { final LabelPosition labelPosition = labelAtFacet.label(); if(labelPosition != null) { propertyLayoutData.setLabelPosition(labelPosition); } } } protected void setMultiLineIfAny( final PropertyLayoutData propertyLayoutData, final FacetHolder facetHolder) { final MultiLineFacet multiLineFacet = facetHolder.getFacet(MultiLineFacet.class); if(isDoOp(multiLineFacet)) { final int numberOfLines = multiLineFacet.numberOfLines(); if(numberOfLines > 0) { propertyLayoutData.setMultiLine(numberOfLines); } } } protected void setNamedIfAny( final HasNamed hasNamed, final FacetHolder facetHolder) { final NamedFacet namedFacet = facetHolder.getFacet(NamedFacet.class); if(isDoOp(namedFacet)) { final String named = namedFacet.value(); if(!Strings.isNullOrEmpty(named)){ hasNamed.setNamed(named); } final boolean escaped = namedFacet.escaped(); if(!escaped) { hasNamed.setNamedEscaped(escaped); } } } protected void setPagedIfAny( final CollectionLayoutData collectionLayoutData, final FacetHolder facetHolder) { final PagedFacet pagedFacet = facetHolder.getFacet(PagedFacet.class); if(isDoOp(pagedFacet)) { final int value = pagedFacet.value(); if(value > 0) { collectionLayoutData.setPaged(value); } } } protected void setPluralIfAny( final DomainObjectLayoutData domainObjectLayoutData, final FacetHolder facetHolder) { final PluralFacet pluralFacet = facetHolder.getFacet(PluralFacet.class); if(isDoOp(pluralFacet)) { final String plural = pluralFacet.value(); if(!Strings.isNullOrEmpty(plural)) { domainObjectLayoutData.setPlural(plural); } } } protected void setActionPositionIfAny( final ActionLayoutData actionLayoutData, final FacetHolder facetHolder) { final ActionPositionFacet actionPositionFacet = facetHolder.getFacet(ActionPositionFacet.class); if(isDoOp(actionPositionFacet)) { final ActionLayout.Position position = actionPositionFacet.position(); if(position != null) { actionLayoutData.setPosition(position); } } } protected void setRenderedAsDayBeforeIfAny( final PropertyLayoutData propertyLayoutData, final FacetHolder facetHolder) { final RenderedAdjustedFacet renderedAdjustedFacet = facetHolder.getFacet(RenderedAdjustedFacet.class); if(isDoOp(renderedAdjustedFacet)) { final int adjusted = renderedAdjustedFacet.value(); propertyLayoutData.setRenderedAsDayBefore(adjusted != 0); } } protected void setSortedByIfAny( final CollectionLayoutData collectionLayoutData, final FacetHolder facetHolder) { final SortedByFacet sortedByFacet = facetHolder.getFacet(SortedByFacet.class); if(isDoOp(sortedByFacet)) { final Class<? extends Comparator<?>> className = sortedByFacet.value(); if(className != null) { collectionLayoutData.setSortedBy(className.getCanonicalName()); } } } protected void setTypicalLengthIfAny( final PropertyLayoutData propertyLayoutData, final FacetHolder facetHolder) { final TypicalLengthFacet typicalLengthFacet = facetHolder.getFacet(TypicalLengthFacet.class); if(isDoOp(typicalLengthFacet)) { final int typicalLength = typicalLengthFacet.value(); if(typicalLength > 0) { propertyLayoutData.setTypicalLength(typicalLength); } } } @Programmatic @Override public void minimal(final G grid, final Class<?> domainClass) { normalize(grid, domainClass); grid.visit(new Grid.VisitorAdapter() { @Override public void visit(final ActionLayoutData actionLayoutData) { actionLayoutData.getOwner().getActions().remove(actionLayoutData); } @Override public void visit(final CollectionLayoutData collectionLayoutData) { collectionLayoutData.getOwner().getCollections().remove(collectionLayoutData); } @Override public void visit(final PropertyLayoutData propertyLayoutData) { propertyLayoutData.getOwner().getProperties().remove(propertyLayoutData); } @Override public void visit(final DomainObjectLayoutData domainObjectLayoutData) { final DomainObjectLayoutDataOwner owner = domainObjectLayoutData.getOwner(); owner.setDomainObject(new DomainObjectLayoutData()); } }); } // ////////////////////////////////////// @javax.inject.Inject protected SpecificationLoader specificationLoader; @javax.inject.Inject protected TranslationService translationService; @javax.inject.Inject protected JaxbService jaxbService; @javax.inject.Inject protected DomainObjectContainer container; @javax.inject.Inject protected MessageService messageService; @javax.inject.Inject DeploymentCategoryProvider deploymentCategoryProvider; }