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        // id and memberType are rendered eagerly
049
050        renderMemberContent();
051        if (mode.isStandalone() || mode.isMutated() || !objectAdapter.representsPersistent()) {
052            addValue();
053        }
054        putDisabledReasonIfDisabled();
055
056        if (mode.isStandalone() || mode.isMutated()) {
057            addExtensionsIsisProprietaryChangedObjects();
058        }
059
060        return representation;
061    }
062
063    // ///////////////////////////////////////////////////
064    // value
065    // ///////////////////////////////////////////////////
066
067    private void addValue() {
068        final ObjectAdapter valueAdapter = objectMember.get(objectAdapter);
069        if (valueAdapter == null) {
070            return;
071        }
072        
073        final RenderFacet renderFacet = objectMember.getFacet(RenderFacet.class);
074        boolean eagerlyRender = renderFacet != null && renderFacet.value() == Type.EAGERLY;
075
076        final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(valueAdapter);
077        final List<JsonRepresentation> list = Lists.newArrayList();
078        for (final ObjectAdapter elementAdapter : facet.iterable(valueAdapter)) {
079
080            final LinkBuilder valueLinkBuilder = DomainObjectReprRenderer.newLinkToBuilder(rendererContext, Rel.VALUE, elementAdapter);
081            if(eagerlyRender) {
082                final DomainObjectReprRenderer renderer = new DomainObjectReprRenderer(getRendererContext(), getLinkFollowSpecs(), JsonRepresentation.newMap());
083                renderer.with(elementAdapter);
084                valueLinkBuilder.withValue(renderer.render());
085            }
086
087            list.add(valueLinkBuilder.build());
088        }
089
090        representation.mapPut("value", list);
091    }
092
093    // ///////////////////////////////////////////////////
094    // details link
095    // ///////////////////////////////////////////////////
096
097    /**
098     * Mandatory hook method to support x-ro-follow-links
099     */
100    @Override
101    protected void followDetailsLink(final JsonRepresentation detailsLink) {
102        final ObjectCollectionReprRenderer renderer = new ObjectCollectionReprRenderer(getRendererContext(), getLinkFollowSpecs(), null, JsonRepresentation.newMap());
103        renderer.with(new ObjectAndCollection(objectAdapter, objectMember)).asFollowed();
104        detailsLink.mapPut("value", renderer.render());
105    }
106
107    // ///////////////////////////////////////////////////
108    // mutators
109    // ///////////////////////////////////////////////////
110
111    @Override
112    protected void addMutatorsIfEnabled() {
113        if (usability().isVetoed()) {
114            return;
115        }
116
117        final CollectionSemantics semantics = CollectionSemantics.determine(objectMember);
118        addMutatorLink(semantics.getAddToKey());
119        addMutatorLink(semantics.getRemoveFromKey());
120
121        return;
122    }
123
124    private void addMutatorLink(final String key) {
125        final Map<String, MutatorSpec> mutators = memberType.getMutators();
126        final MutatorSpec mutatorSpec = mutators.get(key);
127        addLinkFor(mutatorSpec);
128    }
129
130    // ///////////////////////////////////////////////////
131    // extensions and links
132    // ///////////////////////////////////////////////////
133
134    @Override
135    protected void addLinksToFormalDomainModel() {
136        final LinkBuilder linkBuilder = CollectionDescriptionReprRenderer.newLinkToBuilder(rendererContext, Rel.DESCRIBEDBY, objectAdapter.getSpecification(), objectMember);
137        getLinks().arrayAdd(linkBuilder.build());
138    }
139
140    @Override
141    protected void addLinksIsisProprietary() {
142        // none
143    }
144
145    @Override
146    protected void putExtensionsIsisProprietary() {
147        final CollectionSemantics semantics = CollectionSemantics.determine(objectMember);
148        getExtensions().mapPut("collectionSemantics", semantics.name().toLowerCase());
149    }
150
151}