Package org.apache.isis.core.metamodel.layoutmetadata.json

Source Code of org.apache.isis.core.metamodel.layoutmetadata.json.LayoutMetadataReaderFromJson

/**
*  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.*;
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.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.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.members.cssclass.CssClassFacet;
import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacet;
import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacetImpl;
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.objpropparam.typicallen.TypicalLengthFacet;
import org.apache.isis.core.metamodel.facets.propparam.multiline.MultiLineFacet;
import org.apache.isis.core.metamodel.layout.memberorderfacet.MemberOrderFacetComparator;
import org.apache.isis.core.metamodel.layoutmetadata.*;
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.ObjectSpecifications.MemberGroupLayoutHint;
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 LayoutMetadataReader {

    public Properties asProperties(Class<?> domainClass) {
        LayoutMetadata metadata;
        try {
            metadata = readMetadata(domainClass);
        } catch (Exception e) {
            throw new ReaderException("Failed to locate/parse " + domainClass.getName() + ".layout.json file (" + e.getMessage() + ")", e);
        }
        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);
       
        int[] memberSeq = {0};
        setProperties(metadata, props, memberSeq);
        setCollections(metadata, props, memberSeq);
        setFreestandingActions(metadata, props);

        return props;
    }

    private static void setMemberGroupLayoutColumnSpans(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(ColumnRepr input) {
                return input.span;
            }}));
        props.setProperty("class.memberGroupLayout.columnSpans", columnSpansStr);
    }

    private static void setMemberGroupLayoutColumnLists(LayoutMetadata metadata, int colIdx, String propkey, 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(LayoutMetadata metadata, Properties props, 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(LayoutMetadata metadata, Properties props, 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(Properties props, final String memberGroupName, final Map<String, MemberRepr> members, 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);

            final NamedFacetRepr named = memberRepr.named;
            if(named != null) {
                props.setProperty("member." + memberName + ".named.value", named.value);
            }
            final DescribedAsFacetRepr describedAs = memberRepr.describedAs;
            if(describedAs!= null) {
                props.setProperty("member." + memberName + ".describedAs.value", describedAs.value);
            }
            final CssClassFacetRepr cssClass = memberRepr.cssClass;
            if(cssClass!= null) {
                props.setProperty("member." + memberName + ".cssClass.value", cssClass.value);
            }
            final TypicalLengthFacetRepr typicalLength = memberRepr.typicalLength;
            if(typicalLength!= null) {
                props.setProperty("member." + memberName + ".typicalLength.value", ""+typicalLength.value);
            }
            final MultiLineFacetRepr multiLine = memberRepr.multiLine;
            if(multiLine!= null) {
                props.setProperty("member." + memberName + ".multiLine.numberOfLines", ""+multiLine.numberOfLines);
            }
            final LabelAtFacetRepr labelAt = memberRepr.labelAt;
            if(labelAt!= null) {
                props.setProperty("member." + memberName + ".labelAt.value", ""+labelAt.value);
            }
            final PagedFacetRepr paged = memberRepr.paged;
            if(paged != null) {
                props.setProperty("member." + memberName + ".paged.value", ""+paged.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 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());
            }
           
            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);
                    String nameKey = "action." + actionName + ".memberOrder.name";
                    props.setProperty(nameKey, memberName);
                    setRemainingActionProperties(props, "action", actionName, actionRepr, ++actSeq);
                }
            }
        }
    }

    private static void setFreestandingActions(LayoutMetadata metadata, 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(Properties props, 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 NamedFacetRepr actionNamed = actionRepr.named;
        if(actionNamed != null) {
            props.setProperty(prefix +"." + actionName + ".named.value", actionNamed.value);
        }
        final DescribedAsFacetRepr describedAs = actionRepr.describedAs;
        if(describedAs!= null) {
            props.setProperty(prefix +"." + actionName + ".describedAs.value", describedAs.value);
        }
        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);
        }
    }

    public LayoutMetadata asLayoutMetadata(Class<?> domainClass) throws ReaderException {
        try {
            return readMetadata(domainClass);
        } catch (IOException e) {
            throw new ReaderException(e);
        } catch (RuntimeException e) {
            throw new ReaderException(e);
        }
    }

    // //////////////////////////////////////

    private LayoutMetadata readMetadata(Class<?> domainClass) throws IOException {
        final String content = ClassExtensions.resourceContent(domainClass, ".layout.json");
        return readMetadata(content);
    }

    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(ObjectSpecification objectSpec) {
        final LayoutMetadata metadata = new LayoutMetadata();
        metadata.setColumns(Lists.<ColumnRepr>newArrayList());
       
        final MemberGroupLayoutFacet mglf = objectSpec.getFacet(MemberGroupLayoutFacet.class);
        final ColumnSpans columnSpans = mglf.getColumnSpans();
       
        Set<String> actionIdsForAssociations = Sets.newTreeSet();
       
        ColumnRepr columnRepr;
       
        columnRepr = addColumnWithSpan(metadata, columnSpans.getLeft());
        updateColumnMemberGroups(objectSpec, MemberGroupLayoutHint.LEFT, columnRepr, actionIdsForAssociations);
       
        columnRepr = addColumnWithSpan(metadata, columnSpans.getMiddle());
        updateColumnMemberGroups(objectSpec, MemberGroupLayoutHint.MIDDLE, columnRepr, actionIdsForAssociations);
       
        columnRepr = addColumnWithSpan(metadata, columnSpans.getRight());
        updateColumnMemberGroups(objectSpec, MemberGroupLayoutHint.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(ObjectSpecification objectSpec, final MemberGroupLayoutHint hint, ColumnRepr columnRepr, 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 (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 (ObjectAssociation assoc : associationsInGroup) {
                final MemberRepr memberRepr = newMemberRepr(objectSpec, assoc, actionIdsForAssociations);
                memberGroupRepr.members.put(assoc.getId(), memberRepr);
            }
        }
    }
    private static void addActions(ObjectSpecification objectSpec, final LayoutMetadata metadata, Set<String> actionIdsForAssociations) {
        Map<String, ActionRepr> actions = Maps.newLinkedHashMap();
        final List<ObjectAction> actionsOf = actionsOf(objectSpec, actionIdsForAssociations);
        for(ObjectAction action: actionsOf) {
            actions.put(action.getId(), newActionRepr(objectSpec, action));
        }
        metadata.setActions(actions);
    }

    private static ActionRepr newActionRepr(ObjectSpecification objectSpec, ObjectAction action) {
        ActionRepr actionRepr = new ActionRepr();
       
        CssClassFacet cssClassFacet = action.getFacet(CssClassFacet.class);
        if(cssClassFacet != null && !cssClassFacet.isNoop()) {
            CssClassFacetRepr cssClassFacetRepr = new CssClassFacetRepr();
            cssClassFacetRepr.value = cssClassFacet.value();
            actionRepr.cssClass = cssClassFacetRepr;
        }
        DescribedAsFacet describedAsFacet = action.getFacet(DescribedAsFacet.class);
        if(describedAsFacet != null && !describedAsFacet.isNoop() && !Strings.isNullOrEmpty(describedAsFacet.value())) {
            DescribedAsFacetRepr describedAsFacetRepr = new DescribedAsFacetRepr();
            describedAsFacetRepr.value = describedAsFacet.value();
            actionRepr.describedAs = describedAsFacetRepr;
        }
        NamedFacet namedFacet = action.getFacet(NamedFacet.class);
        if(namedFacet != null && !namedFacet.isNoop()) {
            NamedFacetRepr namedFacetRepr = new NamedFacetRepr();
            namedFacetRepr.value = namedFacet.value();
            actionRepr.named = namedFacetRepr;
        }
       
        return actionRepr;
    }

    private static void updateCollectionColumnRepr(ObjectSpecification objectSpec, ColumnRepr columnRepr, Set<String> actionIdsOfAssociations) {
        final List<ObjectAssociation> objectAssociations = collectionsOf(objectSpec);
        columnRepr.collections = Maps.newLinkedHashMap();
        for(ObjectAssociation assoc: objectAssociations) {
            final MemberRepr memberRepr = newMemberRepr(objectSpec, assoc, actionIdsOfAssociations);
            columnRepr.collections.put(assoc.getId(), memberRepr);
        }
    }


    private static MemberRepr newMemberRepr(ObjectSpecification objectSpec, ObjectAssociation assoc, Set<String> actionIdsForAssociations) {
        final MemberRepr memberRepr = new MemberRepr();

        CssClassFacet cssClassFacet = assoc.getFacet(CssClassFacet.class);
        if(cssClassFacet != null && !cssClassFacet.isNoop()) {
            CssClassFacetRepr cssClassFacetRepr = new CssClassFacetRepr();
            cssClassFacetRepr.value = cssClassFacet.value();
            memberRepr.cssClass = cssClassFacetRepr;
        }
        DescribedAsFacet describedAsFacet = assoc.getFacet(DescribedAsFacet.class);
        if(describedAsFacet != null && !describedAsFacet.isNoop() && !Strings.isNullOrEmpty(describedAsFacet.value())) {
            DescribedAsFacetRepr describedAsFacetRepr = new DescribedAsFacetRepr();
            describedAsFacetRepr.value = describedAsFacet.value();
            memberRepr.describedAs = describedAsFacetRepr;
        }
        NamedFacet namedFacet = assoc.getFacet(NamedFacet.class);
        if(namedFacet != null && !namedFacet.isNoop()) {
            NamedFacetRepr namedFacetRepr = new NamedFacetRepr();
            namedFacetRepr.value = namedFacet.value();
            memberRepr.named = namedFacetRepr;
        }
        DisabledFacet disabledFacet = assoc.getFacet(DisabledFacet.class);
        if(disabledFacet != null && !disabledFacet.isNoop()) {
            DisabledFacetRepr disabledFacetRepr = new DisabledFacetRepr();
            if(disabledFacet instanceof DisabledFacetImpl) {
                DisabledFacetImpl disabledFacetImpl = (DisabledFacetImpl) disabledFacet;
                disabledFacetRepr.reason = Strings.emptyToNull(disabledFacetImpl.getReason());
            }
            disabledFacetRepr.when = whenAlwaysToNull(disabledFacet.when());
            disabledFacetRepr.where = whereAnywhereToNull(disabledFacet.where());
            memberRepr.disabled = disabledFacetRepr;
        }
        HiddenFacet hiddenFacet = assoc.getFacet(HiddenFacet.class);
        if(hiddenFacet != null && !hiddenFacet.isNoop()) {
            HiddenFacetRepr hiddenFacetRepr = new HiddenFacetRepr();
            hiddenFacetRepr.when = whenAlwaysToNull(hiddenFacet.when());
            hiddenFacetRepr.where = whereAnywhereToNull(hiddenFacet.where());
            memberRepr.hidden = hiddenFacetRepr;
        }
        MultiLineFacet multiLineFacet = assoc.getFacet(MultiLineFacet.class);
        if(multiLineFacet != null && !multiLineFacet.isNoop()) {
            MultiLineFacetRepr multiLineFacetRepr = new MultiLineFacetRepr();
            multiLineFacetRepr.numberOfLines = multiLineFacet.numberOfLines();
            memberRepr.multiLine = multiLineFacetRepr;
        }
        PagedFacet pagedFacet = assoc.getFacet(PagedFacet.class);
        if(pagedFacet != null && !pagedFacet.isNoop()) {
            PagedFacetRepr pagedFacetRepr = new PagedFacetRepr();
            pagedFacetRepr.value = pagedFacet.value();
            memberRepr.paged = pagedFacetRepr;
        }
        RenderFacet renderFacet = assoc.getFacet(RenderFacet.class);
        if(renderFacet != null && !renderFacet.isNoop()) {
            RenderFacetRepr renderFacetRepr = new RenderFacetRepr();
            renderFacetRepr.value = renderFacet.value();
            memberRepr.render = renderFacetRepr;
        }
        TypicalLengthFacet typicalLengthFacet = assoc.getFacet(TypicalLengthFacet.class);
        if(typicalLengthFacet != null && !typicalLengthFacet.isNoop()) {
            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(Where where) {
        return where != Where.ANYWHERE? where: null;
    }

    private static When whenAlwaysToNull(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(ObjectAction o1, 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(ObjectAction t) {
                        return !excludedActionIds.contains(t.getId());
                    }
                };
    }

    @Override
    public String toString() {
        return getClass().getName();
    }

}
TOP

Related Classes of org.apache.isis.core.metamodel.layoutmetadata.json.LayoutMetadataReaderFromJson

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.