001/**
002 *  Licensed to the Apache Software Foundation (ASF) under one or more
003 *  contributor license agreements.  See the NOTICE file distributed with
004 *  this work for additional information regarding copyright ownership.
005 *  The ASF licenses this file to You under the Apache License, Version 2.0
006 *  (the "License"); you may not use this file except in compliance with
007 *  the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 *  Unless required by applicable law or agreed to in writing, software
012 *  distributed under the License is distributed on an "AS IS" BASIS,
013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 *  See the License for the specific language governing permissions and
015 *  limitations under the License.
016 */
017package org.apache.isis.viewer.restfulobjects.rendering.domainobjects;
018
019import java.util.List;
020import java.util.Map;
021
022import org.apache.isis.applib.annotation.Render;
023import org.apache.isis.applib.annotation.Render.Type;
024import org.apache.isis.applib.annotation.Where;
025import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
026import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
027import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacetUtils;
028import org.apache.isis.core.metamodel.facets.members.resolve.RenderFacet;
029import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
030import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
031import org.apache.isis.viewer.restfulobjects.applib.Rel;
032import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
033import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder;
034import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
035import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
036import org.apache.isis.viewer.restfulobjects.rendering.domaintypes.CollectionDescriptionReprRenderer;
037
038import com.google.common.collect.Lists;
039
040public class ObjectCollectionReprRenderer extends AbstractObjectMemberReprRenderer<ObjectCollectionReprRenderer, OneToManyAssociation> {
041
042    public ObjectCollectionReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final String collectionId, final JsonRepresentation representation) {
043        super(resourceContext, linkFollower, collectionId, RepresentationType.OBJECT_COLLECTION, representation, Where.PARENTED_TABLES);
044    }
045
046    @Override
047    public JsonRepresentation render() {
048
049        renderMemberContent();
050        
051        final RenderFacet renderFacet = objectMember.getFacet(RenderFacet.class);
052        boolean eagerlyRender = renderFacet != null && renderFacet.value() == Type.EAGERLY;
053        
054        if ((mode.isInline() && eagerlyRender) || mode.isStandalone() || mode.isMutated() || mode.isEventSerialization() || !objectAdapter.representsPersistent()) {
055            addValue();
056        }
057        if(!mode.isEventSerialization()) {
058            putDisabledReasonIfDisabled();
059        }
060
061        if (mode.isStandalone() || mode.isMutated()) {
062            addExtensionsIsisProprietaryChangedObjects();
063        }
064
065        return representation;
066    }
067
068    // ///////////////////////////////////////////////////
069    // value
070    // ///////////////////////////////////////////////////
071
072    private void addValue() {
073        final ObjectAdapter valueAdapter = objectMember.get(objectAdapter);
074        if (valueAdapter == null) {
075            return;
076        }
077        
078        final RenderFacet renderFacet = objectMember.getFacet(RenderFacet.class);
079        boolean eagerlyRender = renderFacet != null && renderFacet.value() == Type.EAGERLY && rendererContext.canEagerlyRender(valueAdapter);
080
081        final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(valueAdapter);
082        final List<JsonRepresentation> list = Lists.newArrayList();
083        for (final ObjectAdapter elementAdapter : facet.iterable(valueAdapter)) {
084
085            final LinkBuilder valueLinkBuilder = DomainObjectReprRenderer.newLinkToBuilder(rendererContext, Rel.VALUE, elementAdapter);
086            if(eagerlyRender) {
087                final DomainObjectReprRenderer renderer = new DomainObjectReprRenderer(getRendererContext(), getLinkFollowSpecs(), JsonRepresentation.newMap());
088                renderer.with(elementAdapter);
089                if(mode.isEventSerialization()) {
090                    renderer.asEventSerialization();
091                }
092
093                valueLinkBuilder.withValue(renderer.render());
094            }
095
096            list.add(valueLinkBuilder.build());
097        }
098
099        representation.mapPut("value", list);
100    }
101
102    // ///////////////////////////////////////////////////
103    // details link
104    // ///////////////////////////////////////////////////
105
106    /**
107     * Mandatory hook method to support x-ro-follow-links
108     */
109    @Override
110    protected void followDetailsLink(final JsonRepresentation detailsLink) {
111        final ObjectCollectionReprRenderer renderer = new ObjectCollectionReprRenderer(getRendererContext(), getLinkFollowSpecs(), null, JsonRepresentation.newMap());
112        renderer.with(new ObjectAndCollection(objectAdapter, objectMember)).asFollowed();
113        detailsLink.mapPut("value", renderer.render());
114    }
115
116    // ///////////////////////////////////////////////////
117    // mutators
118    // ///////////////////////////////////////////////////
119
120    @Override
121    protected void addMutatorsIfEnabled() {
122        if (usability().isVetoed()) {
123            return;
124        }
125
126        final CollectionSemantics semantics = CollectionSemantics.determine(objectMember);
127        addMutatorLink(semantics.getAddToKey());
128        addMutatorLink(semantics.getRemoveFromKey());
129
130        return;
131    }
132
133    private void addMutatorLink(final String key) {
134        final Map<String, MutatorSpec> mutators = memberType.getMutators();
135        final MutatorSpec mutatorSpec = mutators.get(key);
136        addLinkFor(mutatorSpec);
137    }
138
139    // ///////////////////////////////////////////////////
140    // extensions and links
141    // ///////////////////////////////////////////////////
142
143    @Override
144    protected void addLinksToFormalDomainModel() {
145        final LinkBuilder linkBuilder = CollectionDescriptionReprRenderer.newLinkToBuilder(rendererContext, Rel.DESCRIBEDBY, objectAdapter.getSpecification(), objectMember);
146        getLinks().arrayAdd(linkBuilder.build());
147    }
148
149    @Override
150    protected void addLinksIsisProprietary() {
151        // none
152    }
153
154    @Override
155    protected void putExtensionsIsisProprietary() {
156        final CollectionSemantics semantics = CollectionSemantics.determine(objectMember);
157        getExtensions().mapPut("collectionSemantics", semantics.name().toLowerCase());
158    }
159
160
161}