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}