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.Type;
023import org.apache.isis.applib.annotation.Where;
024import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
025import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
026import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacetUtils;
027import org.apache.isis.core.metamodel.facets.members.resolve.RenderFacet;
028import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
029import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
030import org.apache.isis.viewer.restfulobjects.applib.Rel;
031import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
032import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder;
033import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
034import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
035import org.apache.isis.viewer.restfulobjects.rendering.domaintypes.CollectionDescriptionReprRenderer;
036
037import com.google.common.collect.Lists;
038
039public class ObjectCollectionReprRenderer extends AbstractObjectMemberReprRenderer<ObjectCollectionReprRenderer, OneToManyAssociation> {
040
041    public ObjectCollectionReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final String collectionId, final JsonRepresentation representation) {
042        super(resourceContext, linkFollower, collectionId, RepresentationType.OBJECT_COLLECTION, representation, Where.PARENTED_TABLES);
043    }
044
045    @Override
046    public JsonRepresentation render() {
047
048        renderMemberContent();
049        
050        final RenderFacet renderFacet = objectMember.getFacet(RenderFacet.class);
051        boolean eagerlyRender = renderFacet != null && renderFacet.value() == Type.EAGERLY;
052        
053        if ((mode.isInline() && eagerlyRender) || mode.isStandalone() || mode.isMutated() || mode.isEventSerialization() || !objectAdapter.representsPersistent()) {
054            addValue();
055        }
056        if(!mode.isEventSerialization()) {
057            putDisabledReasonIfDisabled();
058        }
059
060        if (mode.isStandalone() || mode.isMutated()) {
061            addExtensionsIsisProprietaryChangedObjects();
062        }
063
064        return representation;
065    }
066
067    // ///////////////////////////////////////////////////
068    // value
069    // ///////////////////////////////////////////////////
070
071    private void addValue() {
072        final ObjectAdapter valueAdapter = objectMember.get(objectAdapter);
073        if (valueAdapter == null) {
074            return;
075        }
076        
077        final RenderFacet renderFacet = objectMember.getFacet(RenderFacet.class);
078        boolean eagerlyRender = renderFacet != null && renderFacet.value() == Type.EAGERLY && rendererContext.canEagerlyRender(valueAdapter);
079
080        final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(valueAdapter);
081        final List<JsonRepresentation> list = Lists.newArrayList();
082        for (final ObjectAdapter elementAdapter : facet.iterable(valueAdapter)) {
083
084            final LinkBuilder valueLinkBuilder = DomainObjectReprRenderer.newLinkToBuilder(rendererContext, Rel.VALUE, elementAdapter);
085            if(eagerlyRender) {
086                final DomainObjectReprRenderer renderer = new DomainObjectReprRenderer(getRendererContext(), getLinkFollowSpecs(), JsonRepresentation.newMap());
087                renderer.with(elementAdapter);
088                if(mode.isEventSerialization()) {
089                    renderer.asEventSerialization();
090                }
091
092                valueLinkBuilder.withValue(renderer.render());
093            }
094
095            list.add(valueLinkBuilder.build());
096        }
097
098        representation.mapPut("value", list);
099    }
100
101    // ///////////////////////////////////////////////////
102    // details link
103    // ///////////////////////////////////////////////////
104
105    /**
106     * Mandatory hook method to support x-ro-follow-links
107     */
108    @Override
109    protected void followDetailsLink(final JsonRepresentation detailsLink) {
110        final ObjectCollectionReprRenderer renderer = new ObjectCollectionReprRenderer(getRendererContext(), getLinkFollowSpecs(), null, JsonRepresentation.newMap());
111        renderer.with(new ObjectAndCollection(objectAdapter, objectMember)).asFollowed();
112        detailsLink.mapPut("value", renderer.render());
113    }
114
115    // ///////////////////////////////////////////////////
116    // mutators
117    // ///////////////////////////////////////////////////
118
119    @Override
120    protected void addMutatorsIfEnabled() {
121        if (usability().isVetoed()) {
122            return;
123        }
124
125        final CollectionSemantics semantics = CollectionSemantics.determine(objectMember);
126        addMutatorLink(semantics.getAddToKey());
127        addMutatorLink(semantics.getRemoveFromKey());
128
129        return;
130    }
131
132    private void addMutatorLink(final String key) {
133        final Map<String, MutatorSpec> mutators = objectMemberType.getMutators();
134        final MutatorSpec mutatorSpec = mutators.get(key);
135        addLinkFor(mutatorSpec);
136    }
137
138    // ///////////////////////////////////////////////////
139    // extensions and links
140    // ///////////////////////////////////////////////////
141
142    @Override
143    protected void addLinksToFormalDomainModel() {
144        final LinkBuilder linkBuilder = CollectionDescriptionReprRenderer.newLinkToBuilder(rendererContext, Rel.DESCRIBEDBY, objectAdapter.getSpecification(), objectMember);
145        getLinks().arrayAdd(linkBuilder.build());
146    }
147
148    @Override
149    protected void addLinksIsisProprietary() {
150        // none
151    }
152
153    @Override
154    protected void putExtensionsIsisProprietary() {
155        final CollectionSemantics semantics = CollectionSemantics.determine(objectMember);
156        getExtensions().mapPut("collectionSemantics", semantics.name().toLowerCase());
157    }
158
159
160}