/**
* 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.layoutmetadata.json;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.isis.applib.annotation.MemberGroupLayout.ColumnSpans;
import org.apache.isis.applib.annotation.Render;
import org.apache.isis.applib.annotation.Render.Type;
import org.apache.isis.applib.annotation.When;
import org.apache.isis.applib.annotation.Where;
import org.apache.isis.applib.filter.Filter;
import org.apache.isis.applib.services.grid.GridService;
import org.apache.isis.core.commons.lang.ClassExtensions;
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.members.cssclass.CssClassFacet;
import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacet;
import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacetAbstractImpl;
import org.apache.isis.core.metamodel.facets.members.order.MemberOrderFacet;
import org.apache.isis.core.metamodel.facets.members.render.RenderFacet;
import org.apache.isis.core.metamodel.facets.object.membergroups.MemberGroupLayoutFacet;
import org.apache.isis.core.metamodel.facets.object.paged.PagedFacet;
import org.apache.isis.core.metamodel.facets.objectvalue.multiline.MultiLineFacet;
import org.apache.isis.core.metamodel.facets.objectvalue.typicallen.TypicalLengthFacet;
import org.apache.isis.core.metamodel.layout.memberorderfacet.MemberOrderFacetComparator;
import org.apache.isis.core.metamodel.layoutmetadata.ActionLayoutFacetRepr;
import org.apache.isis.core.metamodel.layoutmetadata.ActionRepr;
import org.apache.isis.core.metamodel.layoutmetadata.CollectionLayoutFacetRepr;
import org.apache.isis.core.metamodel.layoutmetadata.ColumnRepr;
import org.apache.isis.core.metamodel.layoutmetadata.CssClassFaFacetRepr;
import org.apache.isis.core.metamodel.layoutmetadata.CssClassFacetRepr;
import org.apache.isis.core.metamodel.layoutmetadata.DefaultViewFacetRepr;
import org.apache.isis.core.metamodel.layoutmetadata.DescribedAsFacetRepr;
import org.apache.isis.core.metamodel.layoutmetadata.DisabledFacetRepr;
import org.apache.isis.core.metamodel.layoutmetadata.HiddenFacetRepr;
import org.apache.isis.core.metamodel.layoutmetadata.LayoutMetadata;
import org.apache.isis.core.metamodel.layoutmetadata.LayoutMetadataReader2;
import org.apache.isis.core.metamodel.layoutmetadata.MemberGroupRepr;
import org.apache.isis.core.metamodel.layoutmetadata.MemberRepr;
import org.apache.isis.core.metamodel.layoutmetadata.MultiLineFacetRepr;
import org.apache.isis.core.metamodel.layoutmetadata.NamedFacetRepr;
import org.apache.isis.core.metamodel.layoutmetadata.PagedFacetRepr;
import org.apache.isis.core.metamodel.layoutmetadata.PropertyLayoutFacetRepr;
import org.apache.isis.core.metamodel.layoutmetadata.RenderFacetRepr;
import org.apache.isis.core.metamodel.layoutmetadata.TypicalLengthFacetRepr;
import org.apache.isis.core.metamodel.services.ServicesInjector;
import org.apache.isis.core.metamodel.services.ServicesInjectorAware;
import org.apache.isis.core.metamodel.services.grid.fixedcols.applib.Hint;
import org.apache.isis.core.metamodel.spec.ActionType;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.metamodel.spec.ObjectSpecifications;
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;
public class LayoutMetadataReaderFromJson implements LayoutMetadataReader2, ServicesInjectorAware {
private static final Logger LOG = LoggerFactory.getLogger(LayoutMetadataReaderFromJson.class);
@Override
public Support support() {
return Support.entitiesOnly();
}
public Properties asProperties(final Class<?> domainClass) {
final LayoutMetadata metadata = readMetadata(domainClass);
if(metadata == null) {
return null;
}
if(metadata.getColumns() == null || metadata.getColumns().size() != 4) {
throw new ReaderException("JSON metadata must have precisely 4 columns (prop/prop/prop/coll)");
}
final Properties props = new Properties();
setMemberGroupLayoutColumnSpans(metadata, props);
setMemberGroupLayoutColumnLists(metadata, 0, "left", props);
setMemberGroupLayoutColumnLists(metadata, 1, "middle", props);
setMemberGroupLayoutColumnLists(metadata, 2, "right", props);
final int[] memberSeq = {0};
setProperties(metadata, props, memberSeq);
setCollections(metadata, props, memberSeq);
setFreestandingActions(metadata, props);
return props;
}
private static void setMemberGroupLayoutColumnSpans(final LayoutMetadata metadata, final Properties props) {
final List<ColumnRepr> columns = metadata.getColumns();
final String columnSpansStr = Joiner.on(",").join(Iterables.transform(columns, new Function<ColumnRepr,Integer>(){
@Override
public Integer apply(final ColumnRepr input) {
return input.span;
}}));
props.setProperty("class.memberGroupLayout.columnSpans", columnSpansStr);
}
private static void setMemberGroupLayoutColumnLists(final LayoutMetadata metadata, final int colIdx, final String propkey, final Properties props) {
final ColumnRepr column = metadata.getColumns().get(colIdx);
final Map<String, MemberGroupRepr> memberGroups = column.memberGroups;
final String val = memberGroups != null ? Joiner.on(",").join(memberGroups.keySet()) : "";
props.setProperty("class.memberGroupLayout." + propkey, val);
}
private static void setProperties(final LayoutMetadata metadata, final Properties props, final int[] memberSeq) {
final List<ColumnRepr> columns = metadata.getColumns();
for (final ColumnRepr columnRepr : columns) {
final Map<String, MemberGroupRepr> memberGroups = columnRepr.memberGroups;
if(memberGroups == null) {
continue;
}
for (final String memberGroupName : memberGroups.keySet()) {
final MemberGroupRepr memberGroup = memberGroups.get(memberGroupName);
final Map<String, MemberRepr> members = memberGroup.members;
if(members == null) {
continue;
}
setMembersAndAssociatedActions(props, memberGroupName, members, memberSeq);
}
}
}
private static void setCollections(final LayoutMetadata metadata, final Properties props, final int[] memberSeq) {
final ColumnRepr columnRepr = metadata.getColumns().get(3);
final Map<String, MemberRepr> collections = columnRepr.collections;
setMembersAndAssociatedActions(props, null, collections, memberSeq);
}
private static void setMembersAndAssociatedActions(final Properties props, final String memberGroupName, final Map<String, MemberRepr> members, final int[] memberSeq) {
for(final String memberName: members.keySet()) {
props.setProperty("member." + memberName + ".memberOrder.sequence", ""+ ++memberSeq[0]);
if(memberGroupName != null) {
props.setProperty("member." + memberName + ".memberOrder.name", memberGroupName);
}
final MemberRepr memberRepr = members.get(memberName);
// actions
final Map<String, ActionRepr> actions = memberRepr.actions;
if(actions != null) {
int actSeq = 0;
for(final String actionName: actions.keySet()) {
final ActionRepr actionRepr = actions.get(actionName);
final String nameKey = "action." + actionName + ".memberOrder.name";
props.setProperty(nameKey, memberName);
setRemainingActionProperties(props, "action", actionName, actionRepr, ++actSeq);
}
}
// propertyLayout
final PropertyLayoutFacetRepr propertyLayout = memberRepr.propertyLayout;
if(propertyLayout!= null) {
if(propertyLayout.cssClass != null) {
props.setProperty("member." + memberName + ".propertyLayout.cssClass", propertyLayout.cssClass);
}
if(propertyLayout.describedAs != null) {
props.setProperty("member." + memberName + ".propertyLayout.describedAs", propertyLayout.describedAs);
}
if(propertyLayout.hidden != null) {
props.setProperty("member." + memberName + ".propertyLayout.hidden", ""+propertyLayout.hidden);
}
if(propertyLayout.labelPosition != null) {
props.setProperty("member." + memberName + ".propertyLayout.labelPosition", ""+propertyLayout.labelPosition);
}
if(propertyLayout.multiLine > 1) {
props.setProperty("member." + memberName + ".propertyLayout.multiLine", "" + propertyLayout.multiLine);
}
if(propertyLayout.named != null) {
props.setProperty("member." + memberName + ".propertyLayout.named", propertyLayout.named);
}
//
{
props.setProperty("member." + memberName + ".propertyLayout.namedEscaped", ""+propertyLayout.namedEscaped);
}
//
{
props.setProperty("member." + memberName + ".propertyLayout.renderedAsDayBefore", "" + propertyLayout.renderedAsDayBefore);
}
if(propertyLayout.typicalLength > 0) {
props.setProperty("member." + memberName + ".propertyLayout.typicalLength", "" + propertyLayout.typicalLength);
}
}
// collectionLayout
final CollectionLayoutFacetRepr collectionLayout = memberRepr.collectionLayout;
if(collectionLayout!= null) {
if(collectionLayout.cssClass != null) {
props.setProperty("member." + memberName + ".collectionLayout.cssClass", collectionLayout.cssClass);
}
if(collectionLayout.describedAs != null) {
props.setProperty("member." + memberName + ".collectionLayout.describedAs", collectionLayout.describedAs);
}
if(collectionLayout.defaultView != null) {
props.setProperty("member." + memberName + ".collectionLayout.defaultView", collectionLayout.defaultView);
}
if(collectionLayout.hidden != null) {
props.setProperty("member." + memberName + ".collectionLayout.hidden", ""+collectionLayout.hidden);
}
if(collectionLayout.named != null) {
props.setProperty("member." + memberName + ".collectionLayout.named", collectionLayout.named);
}
//
{
props.setProperty("member." + memberName + ".collectionLayout.namedEscaped", ""+collectionLayout.namedEscaped);
}
if(collectionLayout.paged > 0) {
props.setProperty("member." + memberName + ".collectionLayout.paged", "" + collectionLayout.paged);
}
if(collectionLayout.render != null) {
props.setProperty("member." + memberName + ".collectionLayout.render", ""+collectionLayout.render);
}
if(collectionLayout.sortedBy != null) {
props.setProperty("member." + memberName + ".collectionLayout.sortedBy", collectionLayout.sortedBy);
}
}
// deprecated - properties & collections
final CssClassFacetRepr cssClass = memberRepr.cssClass;
if(cssClass!= null) {
props.setProperty("member." + memberName + ".cssClass.value", cssClass.value);
}
final DescribedAsFacetRepr describedAs = memberRepr.describedAs;
if(describedAs!= null) {
props.setProperty("member." + memberName + ".describedAs.value", describedAs.value);
}
final DisabledFacetRepr disabled = memberRepr.disabled;
if(disabled != null) {
// same default as in Disabled.when()
final When disabledWhen = disabled.when!=null?disabled.when: When.ALWAYS;
props.setProperty("member." + memberName + ".disabled.when", disabledWhen.toString());
// same default as in Disabled.where()
final Where disabledWhere = disabled.where!=null?disabled.where: Where.ANYWHERE;
props.setProperty("member." + memberName + ".disabled.where", disabledWhere.toString());
// same default as in Disabled.reason()
final String disabledReason = disabled.reason!=null?disabled.reason: "";
props.setProperty("member." + memberName + ".disabled.reason", disabledReason);
}
final HiddenFacetRepr hidden = memberRepr.hidden;
if(hidden != null) {
// same default as in Hidden.when()
final When hiddenWhen = hidden.when!=null?hidden.when: When.ALWAYS;
props.setProperty("member." + memberName + ".hidden.when", hiddenWhen.toString());
// same default as in Hidden.where()
final Where hiddenWhere = hidden.where!=null?hidden.where: Where.ANYWHERE;
props.setProperty("member." + memberName + ".hidden.where", hiddenWhere.toString());
}
final NamedFacetRepr named = memberRepr.named;
if(named != null) {
props.setProperty("member." + memberName + ".named.value", named.value);
}
// deprecated - properties
final MultiLineFacetRepr multiLine = memberRepr.multiLine;
if(multiLine!= null) {
props.setProperty("member." + memberName + ".multiLine.numberOfLines", ""+multiLine.numberOfLines);
}
final TypicalLengthFacetRepr typicalLength = memberRepr.typicalLength;
if(typicalLength!= null) {
props.setProperty("member." + memberName + ".typicalLength.value", ""+typicalLength.value);
}
// deprecated - collections
final PagedFacetRepr paged = memberRepr.paged;
if(paged != null) {
props.setProperty("member." + memberName + ".paged.value", ""+paged.value);
}
final RenderFacetRepr render = memberRepr.render;
if(render != null) {
// same default as in Render.Type.value()
final Type renderType = render.value!=null?render.value: Render.Type.EAGERLY;
props.setProperty("member." + memberName + ".render.value", renderType.toString());
}
}
}
private static void setFreestandingActions(final LayoutMetadata metadata, final Properties props) {
if(metadata.getActions() == null) {
return;
}
int xeq=0;
final Map<String, ActionRepr> actions = metadata.getActions();
for (final String actionName : actions.keySet()) {
final ActionRepr actionRepr = actions.get(actionName);
setRemainingActionProperties(props, "member", actionName, actionRepr, ++xeq);
}
}
private static void setRemainingActionProperties(
final Properties props,
final String prefix,
final String actionNameOrig,
final ActionRepr actionRepr,
final int seq) {
final String actionName = actionNameOrig + ("action".equals(prefix)?"":"()");
props.setProperty(prefix + "." + actionName + ".memberOrder.sequence", ""+ seq);
final ActionLayoutFacetRepr actionLayout = actionRepr.actionLayout;
if(actionLayout != null) {
if(actionLayout.bookmarking != null) {
props.setProperty(prefix + "." + actionName + ".actionLayout.bookmarking", ""+actionLayout.bookmarking);
}
if(actionLayout.cssClass != null) {
props.setProperty(prefix + "." + actionName + ".actionLayout.cssClass", actionLayout.cssClass);
}
if(actionLayout.cssClassFa != null) {
props.setProperty(prefix + "." + actionName + ".actionLayout.cssClassFa", actionLayout.cssClassFa);
}
if(actionLayout.cssClassFaPosition != null) {
props.setProperty(prefix + "." + actionName + ".actionLayout.cssClassFaPosition", actionLayout.cssClassFaPosition);
}
if(actionLayout.describedAs != null) {
props.setProperty(prefix + "." + actionName + ".actionLayout.describedAs", actionLayout.describedAs);
}
if(actionLayout.hidden != null) {
props.setProperty(prefix + "." + actionName + ".actionLayout.hidden", ""+actionLayout.hidden);
}
if(actionLayout.named != null) {
props.setProperty(prefix + "." + actionName + ".actionLayout.named", actionLayout.named);
}
//
{
props.setProperty(prefix + "." + actionName + ".actionLayout.namedEscaped", ""+actionLayout.namedEscaped);
}
if(actionLayout.position != null) {
props.setProperty(prefix + "." + actionName + ".actionLayout.position", ""+actionLayout.position);
}
}
// deprecated
final CssClassFacetRepr cssClass = actionRepr.cssClass;
if(cssClass!= null) {
props.setProperty(prefix +"." + actionName + ".cssClass.value", cssClass.value);
}
final CssClassFaFacetRepr cssClassFa = actionRepr.cssClassFa;
if(cssClassFa != null) {
props.setProperty(prefix +"." + actionName + ".cssClassFa.value", cssClassFa.value);
props.setProperty(prefix +"." + actionName + ".cssClassFa.position", cssClassFa.position);
}
final DescribedAsFacetRepr describedAs = actionRepr.describedAs;
if(describedAs!= null) {
props.setProperty(prefix +"." + actionName + ".describedAs.value", describedAs.value);
}
final NamedFacetRepr actionNamed = actionRepr.named;
if(actionNamed != null) {
props.setProperty(prefix +"." + actionName + ".named.value", actionNamed.value);
}
}
public LayoutMetadata asLayoutMetadata(final Class<?> domainClass) {
return readMetadata(domainClass);
}
// //////////////////////////////////////
private final Set<Class<?>> blacklisted = Sets.newConcurrentHashSet();
private LayoutMetadata readMetadata(final Class<?> domainClass) {
final String content;
if(blacklisted.contains(domainClass)) {
return null;
}
try {
final GridService gridService = getGridService();
if(gridService.existsFor(domainClass)) {
blacklisted.add(domainClass);
return null;
}
} catch (IllegalArgumentException ex) {
// ignore
}
final String resourceName = domainClass.getSimpleName() + ".layout.json";
try {
content = ClassExtensions.resourceContentOf(domainClass, resourceName);
} catch (IOException | IllegalArgumentException ex) {
blacklisted.add(domainClass);
final String message = String .format(
"Failed to locate file %s (relative to %s.class); ex: %s)",
resourceName, domainClass.getName(), ex.getMessage());
LOG.debug(message);
return null;
}
try {
return readMetadata(content);
} catch(Exception ex) {
// note that we don't blacklist if the file exists but couldn't be parsed;
// the developer might fix so we will want to retry.
final String message = "Failed to parse " + domainClass.getName() + ".layout.json file (" + ex.getMessage() + ")";
LOG.warn(message);
return null;
}
}
LayoutMetadata readMetadata(final String content) {
final Gson gson = new GsonBuilder().create();
return gson.fromJson(content, LayoutMetadata.class);
}
// //////////////////////////////////////
private final static MemberOrderFacetComparator memberOrderFacetComparator = new MemberOrderFacetComparator(false);
/**
* not API
*/
public String asJson(final ObjectSpecification objectSpec) {
final LayoutMetadata metadata = new LayoutMetadata();
metadata.setColumns(Lists.<ColumnRepr>newArrayList());
final MemberGroupLayoutFacet mglf = objectSpec.getFacet(MemberGroupLayoutFacet.class);
final ColumnSpans columnSpans = mglf.getColumnSpans();
final Set<String> actionIdsForAssociations = Sets.newTreeSet();
ColumnRepr columnRepr;
columnRepr = addColumnWithSpan(metadata, columnSpans.getLeft());
updateColumnMemberGroups(objectSpec, Hint.LEFT, columnRepr, actionIdsForAssociations);
columnRepr = addColumnWithSpan(metadata, columnSpans.getMiddle());
updateColumnMemberGroups(objectSpec, Hint.MIDDLE, columnRepr, actionIdsForAssociations);
columnRepr = addColumnWithSpan(metadata, columnSpans.getRight());
updateColumnMemberGroups(objectSpec, Hint.RIGHT, columnRepr, actionIdsForAssociations);
columnRepr = addColumnWithSpan(metadata, columnSpans.getCollections());
updateCollectionColumnRepr(objectSpec, columnRepr, actionIdsForAssociations);
addActions(objectSpec, metadata, actionIdsForAssociations);
final Gson gson = new GsonBuilder().setPrettyPrinting().create();
return gson.toJson(metadata);
}
private static void updateColumnMemberGroups(final ObjectSpecification objectSpec, final Hint hint, final ColumnRepr columnRepr, final Set<String> actionIdsForAssociations) {
final List<ObjectAssociation> objectAssociations = propertiesOf(objectSpec);
final Map<String, List<ObjectAssociation>> associationsByGroup = ObjectAssociation.Util.groupByMemberOrderName(objectAssociations
);
final List<String> groupNames = ObjectSpecifications.orderByMemberGroups(objectSpec, associationsByGroup.keySet(), hint);
columnRepr.memberGroups = Maps.newLinkedHashMap();
for (final String groupName : groupNames) {
final MemberGroupRepr memberGroupRepr = new MemberGroupRepr();
columnRepr.memberGroups.put(groupName, memberGroupRepr);
final List<ObjectAssociation> associationsInGroup = associationsByGroup.get(groupName);
memberGroupRepr.members = Maps.newLinkedHashMap();
if(associationsInGroup == null) {
continue;
}
for (final ObjectAssociation assoc : associationsInGroup) {
final MemberRepr memberRepr = newMemberRepr(objectSpec, assoc, actionIdsForAssociations);
memberGroupRepr.members.put(assoc.getId(), memberRepr);
}
}
}
private static void addActions(final ObjectSpecification objectSpec, final LayoutMetadata metadata, final Set<String> actionIdsForAssociations) {
final Map<String, ActionRepr> actions = Maps.newLinkedHashMap();
final List<ObjectAction> actionsOf = actionsOf(objectSpec, actionIdsForAssociations);
for(final ObjectAction action: actionsOf) {
actions.put(action.getId(), newActionRepr(objectSpec, action));
}
metadata.setActions(actions);
}
private static ActionRepr newActionRepr(final ObjectSpecification objectSpec, final ObjectAction action) {
final ActionRepr actionRepr = new ActionRepr();
final CssClassFacet cssClassFacet = action.getFacet(CssClassFacet.class);
if(cssClassFacet != null && !cssClassFacet.isNoop()) {
final CssClassFacetRepr cssClassFacetRepr = new CssClassFacetRepr();
cssClassFacetRepr.value = cssClassFacet.cssClass(null);
actionRepr.cssClass = cssClassFacetRepr;
}
final DescribedAsFacet describedAsFacet = action.getFacet(DescribedAsFacet.class);
if(describedAsFacet != null && !describedAsFacet.isNoop() && !Strings.isNullOrEmpty(describedAsFacet.value())) {
final DescribedAsFacetRepr describedAsFacetRepr = new DescribedAsFacetRepr();
describedAsFacetRepr.value = describedAsFacet.value();
actionRepr.describedAs = describedAsFacetRepr;
}
final NamedFacet namedFacet = action.getFacet(NamedFacet.class);
if(namedFacet != null && !namedFacet.isNoop()) {
final NamedFacetRepr namedFacetRepr = new NamedFacetRepr();
namedFacetRepr.value = namedFacet.value();
actionRepr.named = namedFacetRepr;
}
return actionRepr;
}
private static void updateCollectionColumnRepr(final ObjectSpecification objectSpec, final ColumnRepr columnRepr, final Set<String> actionIdsOfAssociations) {
final List<ObjectAssociation> objectAssociations = collectionsOf(objectSpec);
columnRepr.collections = Maps.newLinkedHashMap();
for(final ObjectAssociation assoc: objectAssociations) {
final MemberRepr memberRepr = newMemberRepr(objectSpec, assoc, actionIdsOfAssociations);
columnRepr.collections.put(assoc.getId(), memberRepr);
}
}
private static MemberRepr newMemberRepr(final ObjectSpecification objectSpec, final ObjectAssociation assoc, final Set<String> actionIdsForAssociations) {
final MemberRepr memberRepr = new MemberRepr();
final CssClassFacet cssClassFacet = assoc.getFacet(CssClassFacet.class);
if(cssClassFacet != null && !cssClassFacet.isNoop()) {
final CssClassFacetRepr cssClassFacetRepr = new CssClassFacetRepr();
cssClassFacetRepr.value = cssClassFacet.cssClass(null);
memberRepr.cssClass = cssClassFacetRepr;
}
final DescribedAsFacet describedAsFacet = assoc.getFacet(DescribedAsFacet.class);
if(describedAsFacet != null && !describedAsFacet.isNoop() && !Strings.isNullOrEmpty(describedAsFacet.value())) {
final DescribedAsFacetRepr describedAsFacetRepr = new DescribedAsFacetRepr();
describedAsFacetRepr.value = describedAsFacet.value();
memberRepr.describedAs = describedAsFacetRepr;
}
final DefaultViewFacet defaultViewFacet = assoc.getFacet(DefaultViewFacet.class);
if(defaultViewFacet != null && !defaultViewFacet.isNoop() && !Strings.isNullOrEmpty(defaultViewFacet.value())) {
final DefaultViewFacetRepr defaultViewFacetRepr = new DefaultViewFacetRepr();
defaultViewFacetRepr.value = describedAsFacet.value();
}
final NamedFacet namedFacet = assoc.getFacet(NamedFacet.class);
if(namedFacet != null && !namedFacet.isNoop()) {
final NamedFacetRepr namedFacetRepr = new NamedFacetRepr();
namedFacetRepr.value = namedFacet.value();
memberRepr.named = namedFacetRepr;
}
final DisabledFacet disabledFacet = assoc.getFacet(DisabledFacet.class);
if(disabledFacet != null && !disabledFacet.isNoop()) {
final DisabledFacetRepr disabledFacetRepr = new DisabledFacetRepr();
if(disabledFacet instanceof DisabledFacetAbstractImpl) {
final DisabledFacetAbstractImpl disabledFacetImpl = (DisabledFacetAbstractImpl) disabledFacet;
disabledFacetRepr.reason = Strings.emptyToNull(disabledFacetImpl.getReason());
}
disabledFacetRepr.when = whenAlwaysToNull(disabledFacet.when());
disabledFacetRepr.where = whereAnywhereToNull(disabledFacet.where());
memberRepr.disabled = disabledFacetRepr;
}
// relies on the fact that HiddenFacetAbstract is multi-typed
final HiddenFacet hiddenFacet = assoc.getFacet(HiddenFacet.class);
if(hiddenFacet != null && !hiddenFacet.isNoop()) {
final HiddenFacetRepr hiddenFacetRepr = new HiddenFacetRepr();
hiddenFacetRepr.when = whenAlwaysToNull(hiddenFacet.when());
hiddenFacetRepr.where = whereAnywhereToNull(hiddenFacet.where());
memberRepr.hidden = hiddenFacetRepr;
}
final MultiLineFacet multiLineFacet = assoc.getFacet(MultiLineFacet.class);
if(multiLineFacet != null && !multiLineFacet.isNoop()) {
final MultiLineFacetRepr multiLineFacetRepr = new MultiLineFacetRepr();
multiLineFacetRepr.numberOfLines = multiLineFacet.numberOfLines();
memberRepr.multiLine = multiLineFacetRepr;
}
final PagedFacet pagedFacet = assoc.getFacet(PagedFacet.class);
if(pagedFacet != null && !pagedFacet.isNoop()) {
final PagedFacetRepr pagedFacetRepr = new PagedFacetRepr();
pagedFacetRepr.value = pagedFacet.value();
memberRepr.paged = pagedFacetRepr;
}
final RenderFacet renderFacet = assoc.getFacet(RenderFacet.class);
if(renderFacet != null && !renderFacet.isNoop()) {
final RenderFacetRepr renderFacetRepr = new RenderFacetRepr();
renderFacetRepr.value = renderFacet.value();
memberRepr.render = renderFacetRepr;
}
final TypicalLengthFacet typicalLengthFacet = assoc.getFacet(TypicalLengthFacet.class);
if(typicalLengthFacet != null && !typicalLengthFacet.isNoop()) {
final TypicalLengthFacetRepr typicalLengthFacetRepr = new TypicalLengthFacetRepr();
typicalLengthFacetRepr.value = typicalLengthFacet.value();
memberRepr.typicalLength = typicalLengthFacetRepr;
}
final List<ObjectAction> actions = objectSpec.getObjectActions(
ActionType.USER, Contributed.INCLUDED, ObjectAction.Filters.memberOrderOf(assoc));
if(!actions.isEmpty()) {
memberRepr.actions = Maps.newLinkedHashMap();
sortByMemberOrderFacet(actions);
for (final ObjectAction action : actions) {
final String actionId = action.getId();
memberRepr.actions.put(actionId, new ActionRepr());
actionIdsForAssociations.add(actionId);
}
}
return memberRepr;
}
private static Where whereAnywhereToNull(final Where where) {
return where != Where.ANYWHERE? where: null;
}
private static When whenAlwaysToNull(final When when) {
return when != When.ALWAYS? when: null;
}
private static void sortByMemberOrderFacet(final List<ObjectAction> actions) {
Collections.sort(actions, new Comparator<ObjectAction>() {
@Override
public int compare(final ObjectAction o1, final ObjectAction o2) {
final MemberOrderFacet m1 = o1.getFacet(MemberOrderFacet.class);
final MemberOrderFacet m2 = o2.getFacet(MemberOrderFacet.class);
return memberOrderFacetComparator.compare(m1, m2);
}});
}
private static ColumnRepr addColumnWithSpan(final LayoutMetadata metadata, final int span) {
final ColumnRepr col = new ColumnRepr();
metadata.getColumns().add(col);
col.span = span;
return col;
}
private static List<ObjectAssociation> propertiesOf(final ObjectSpecification objSpec) {
return objSpec.getAssociations(Contributed.EXCLUDED, ObjectAssociation.Filters.PROPERTIES);
}
private static List<ObjectAssociation> collectionsOf(final ObjectSpecification objSpec) {
return objSpec.getAssociations(Contributed.EXCLUDED, ObjectAssociation.Filters.COLLECTIONS);
}
private static List<ObjectAction> actionsOf(final ObjectSpecification objSpec, final Set<String> excludedActionIds) {
return objSpec.getObjectActions(ActionType.ALL, Contributed.INCLUDED, excluding(excludedActionIds));
}
@SuppressWarnings({ "deprecation" })
private static Filter<ObjectAction> excluding(final Set<String> excludedActionIds) {
return new Filter<ObjectAction>(){
@Override
public boolean accept(final ObjectAction t) {
return !excludedActionIds.contains(t.getId());
}
};
}
@Override
public String toString() {
return getClass().getName();
}
private GridService getGridService() {
return servicesInjector.lookupService(GridService.class);
}
private ServicesInjector servicesInjector;
@Override
public void setServicesInjector(final ServicesInjector servicesInjector) {
this.servicesInjector = servicesInjector;
}
}