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.Where; 023import org.apache.isis.core.metamodel.adapter.ObjectAdapter; 024import org.apache.isis.core.metamodel.spec.ObjectSpecification; 025import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation; 026import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation; 027import org.apache.isis.viewer.restfulobjects.applib.Rel; 028import org.apache.isis.viewer.restfulobjects.applib.RepresentationType; 029import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs; 030import org.apache.isis.viewer.restfulobjects.rendering.RendererContext; 031import org.apache.isis.viewer.restfulobjects.rendering.domaintypes.PropertyDescriptionReprRenderer; 032import org.codehaus.jackson.node.NullNode; 033 034import com.google.common.collect.Lists; 035 036public class ObjectPropertyReprRenderer extends AbstractObjectMemberReprRenderer<ObjectPropertyReprRenderer, OneToOneAssociation> { 037 038 public ObjectPropertyReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final String propertyId, final JsonRepresentation representation) { 039 super(resourceContext, linkFollower, propertyId, RepresentationType.OBJECT_PROPERTY, representation, Where.OBJECT_FORMS); 040 } 041 042 @Override 043 public JsonRepresentation render() { 044 // id and memberType are rendered eagerly 045 046 renderMemberContent(); 047 addValue(); 048 049 putDisabledReasonIfDisabled(); 050 051 if (mode.isStandalone() || mode.isMutated()) { 052 addChoices(); 053 addExtensionsIsisProprietaryChangedObjects(); 054 } 055 056 return representation; 057 } 058 059 // /////////////////////////////////////////////////// 060 // value 061 // /////////////////////////////////////////////////// 062 063 private void addValue() { 064 final ObjectAdapter valueAdapter = objectMember.get(objectAdapter); 065 066 // use the runtime type if we have a value, else the compile time type of the member otherwise 067 final ObjectSpecification specification = valueAdapter != null? valueAdapter.getSpecification(): objectMember.getSpecification(); 068 069 DomainObjectReprRenderer.appendValueAndFormatOrRef(rendererContext, valueAdapter, specification, representation); 070 } 071 072 // /////////////////////////////////////////////////// 073 // details link 074 // /////////////////////////////////////////////////// 075 076 /** 077 * Mandatory hook method to support x-ro-follow-links 078 */ 079 @Override 080 protected void followDetailsLink(final JsonRepresentation detailsLink) { 081 final ObjectPropertyReprRenderer renderer = new ObjectPropertyReprRenderer(getRendererContext(), getLinkFollowSpecs(), null, JsonRepresentation.newMap()); 082 renderer.with(new ObjectAndProperty(objectAdapter, objectMember)).asFollowed(); 083 detailsLink.mapPut("value", renderer.render()); 084 } 085 086 // /////////////////////////////////////////////////// 087 // mutators 088 // /////////////////////////////////////////////////// 089 090 @Override 091 protected void addMutatorsIfEnabled() { 092 if (usability().isVetoed()) { 093 return; 094 } 095 final Map<String, MutatorSpec> mutators = memberType.getMutators(); 096 for (final String mutator : mutators.keySet()) { 097 final MutatorSpec mutatorSpec = mutators.get(mutator); 098 addLinkFor(mutatorSpec); 099 } 100 return; 101 } 102 103 // /////////////////////////////////////////////////// 104 // choices 105 // /////////////////////////////////////////////////// 106 107 private ObjectPropertyReprRenderer addChoices() { 108 final Object propertyChoices = propertyChoices(); 109 if (propertyChoices != null) { 110 representation.mapPut("choices", propertyChoices); 111 } 112 return this; 113 } 114 115 private Object propertyChoices() { 116 final ObjectAdapter[] choiceAdapters = objectMember.getChoices(objectAdapter); 117 if (choiceAdapters == null || choiceAdapters.length == 0) { 118 return null; 119 } 120 final List<Object> list = Lists.newArrayList(); 121 for (final ObjectAdapter choiceAdapter : choiceAdapters) { 122 // REVIEW: previously was using the spec of the member, but think instead it should be the spec of the adapter itself 123 // final ObjectSpecification choiceSpec = objectMember.getSpecification(); 124 125 // REVIEW: check that it works for ToDoItem$Category, though... 126 final ObjectSpecification choiceSpec = objectAdapter.getSpecification(); 127 list.add(DomainObjectReprRenderer.valueOrRef(rendererContext, choiceAdapter, choiceSpec)); 128 } 129 return list; 130 } 131 132 // /////////////////////////////////////////////////// 133 // extensions and links 134 // /////////////////////////////////////////////////// 135 136 @Override 137 protected void addLinksToFormalDomainModel() { 138 getLinks().arrayAdd(PropertyDescriptionReprRenderer.newLinkToBuilder(getRendererContext(), Rel.DESCRIBEDBY, objectAdapter.getSpecification(), objectMember).build()); 139 } 140 141 @Override 142 protected void addLinksIsisProprietary() { 143 // none 144 } 145 146 @Override 147 protected void putExtensionsIsisProprietary() { 148 // none 149 } 150 151}