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}