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}