001// Generated by delombok at Thu Mar 19 15:24:58 GMT 2020 002/* 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 */ 020package org.apache.isis.viewer.restfulobjects.rendering.domainobjects; 021 022import java.util.List; 023import java.util.Map; 024import java.util.stream.Stream; 025import com.fasterxml.jackson.databind.node.NullNode; 026import org.apache.isis.applib.annotation.SemanticsOf; 027import org.apache.isis.applib.annotation.Where; 028import org.apache.isis.core.commons.internal.collections._Lists; 029import org.apache.isis.core.commons.internal.collections._Maps; 030import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy; 031import org.apache.isis.core.metamodel.spec.ManagedObject; 032import org.apache.isis.core.metamodel.spec.ObjectSpecification; 033import org.apache.isis.core.metamodel.spec.feature.ObjectAction; 034import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter; 035import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation; 036import org.apache.isis.viewer.restfulobjects.applib.Rel; 037import org.apache.isis.viewer.restfulobjects.applib.RepresentationType; 038import org.apache.isis.viewer.restfulobjects.rendering.IResourceContext; 039import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs; 040import org.apache.isis.viewer.restfulobjects.rendering.domaintypes.ActionDescriptionReprRenderer; 041 042public class ObjectActionReprRenderer extends AbstractObjectMemberReprRenderer<ObjectActionReprRenderer, ObjectAction> { 043 public ObjectActionReprRenderer(IResourceContext resourceContext) { 044 this(resourceContext, null, null, JsonRepresentation.newMap()); 045 } 046 047 public ObjectActionReprRenderer(final IResourceContext resourceContext, final LinkFollowSpecs linkFollowSpecs, String actionId, final JsonRepresentation representation) { 048 super(resourceContext, linkFollowSpecs, actionId, RepresentationType.OBJECT_ACTION, representation, Where.OBJECT_FORMS); 049 } 050 051 @Override 052 public JsonRepresentation render() { 053 renderMemberContent(); 054 putDisabledReasonIfDisabled(); 055 if (mode.isStandalone() || mode.isMutated()) { 056 addParameterDetails(); 057 } 058 return representation; 059 } 060 061 // /////////////////////////////////////////////////// 062 // details link 063 // /////////////////////////////////////////////////// 064 /** 065 * Mandatory hook method to support x-ro-follow-links 066 */ 067 @Override 068 protected void followDetailsLink(final JsonRepresentation detailsLink) { 069 final ObjectActionReprRenderer renderer = new ObjectActionReprRenderer(getResourceContext(), getLinkFollowSpecs(), null, JsonRepresentation.newMap()); 070 renderer.with(new ObjectAndAction(objectAdapter, objectMember)).usingLinkTo(linkTo).asFollowed(); 071 detailsLink.mapPut("value", renderer.render()); 072 } 073 074 // /////////////////////////////////////////////////// 075 // mutators 076 // /////////////////////////////////////////////////// 077 @Override 078 protected void addMutatorLinksIfEnabled() { 079 if (usability().isVetoed()) { 080 return; 081 } 082 final Map<String, MutatorSpec> mutators = objectMemberType.getMutators(); 083 final SemanticsOf actionSemantics = objectMember.getSemantics(); 084 final String mutator = InvokeKeys.getKeyFor(actionSemantics); 085 final MutatorSpec mutatorSpec = mutators.get(mutator); 086 addLinkFor(mutatorSpec); 087 } 088 089 @Override 090 protected ObjectAdapterLinkTo linkToForMutatorInvoke() { 091 if (true /*!objectMember.isContributed()*/) { 092 return super.linkToForMutatorInvoke(); 093 } 094 final DomainServiceLinkTo linkTo = new DomainServiceLinkTo(); 095 return linkTo.usingUrlBase(getResourceContext()).with(contributingServiceAdapter()); 096 } 097 098 private ManagedObject contributingServiceAdapter() { 099 final ObjectSpecification serviceType = objectMember.getOnType(); 100 final Stream<ManagedObject> serviceAdapters = streamServiceAdapters(); 101 return serviceAdapters.filter(serviceAdapter -> serviceAdapter.getSpecification() == serviceType).findFirst().orElseThrow(() -> new IllegalStateException("Unable to locate contributing service")); // fail fast 102 } 103 104 @Override 105 protected JsonRepresentation mutatorArgs(final MutatorSpec mutatorSpec) { 106 final JsonRepresentation argMap = JsonRepresentation.newMap(); 107 final org.apache.isis.core.commons.collections.Can<org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter> parameters = objectMember.getParameters(); 108 for (int i = 0; i < objectMember.getParameterCount(); i++) { 109 argMap.mapPut(parameters.getElseFail(i).getId() + ".value", argValueFor(i)); 110 } 111 return argMap; 112 } 113 114 private Object argValueFor(final int i) { 115 // force a null into the map 116 return NullNode.getInstance(); 117 } 118 119 // /////////////////////////////////////////////////// 120 // parameter details 121 // /////////////////////////////////////////////////// 122 private ObjectActionReprRenderer addParameterDetails() { 123 final Map<String, Object> parameters = _Maps.newLinkedHashMap(); 124 for (int i = 0; i < objectMember.getParameterCount(); i++) { 125 final ObjectActionParameter param = objectMember.getParameters().getElseFail(i); 126 final Object paramDetails = paramDetails(param, getInteractionInitiatedBy()); 127 parameters.put(param.getId(), paramDetails); 128 } 129 representation.mapPut("parameters", parameters); 130 return this; 131 } 132 133 private Object paramDetails(final ObjectActionParameter param, final InteractionInitiatedBy interactionInitiatedBy) { 134 final JsonRepresentation paramRep = JsonRepresentation.newMap(); 135 paramRep.mapPut("num", param.getNumber()); 136 paramRep.mapPut("id", param.getId()); 137 paramRep.mapPut("name", param.getName()); 138 paramRep.mapPut("description", param.getDescription()); 139 final Object paramChoices = choicesFor(param, interactionInitiatedBy); 140 if (paramChoices != null) { 141 paramRep.mapPut("choices", paramChoices); 142 } 143 final Object paramDefault = defaultFor(param); 144 if (paramDefault != null) { 145 paramRep.mapPut("default", paramDefault); 146 } 147 return paramRep; 148 } 149 150 private Object choicesFor(final ObjectActionParameter param, final InteractionInitiatedBy interactionInitiatedBy) { 151 final org.apache.isis.core.commons.collections.Can<org.apache.isis.core.metamodel.spec.ManagedObject> choiceAdapters = param.getChoices(objectAdapter, null, interactionInitiatedBy); 152 if (choiceAdapters == null || choiceAdapters.isEmpty()) { 153 return null; 154 } 155 final List<Object> list = _Lists.newArrayList(); 156 for (final org.apache.isis.core.metamodel.spec.ManagedObject choiceAdapter : choiceAdapters) { 157 // REVIEW: previously was using the spec of the parameter, but think instead it should be the spec of the adapter itself 158 // final ObjectSpecification choiceSpec = param.getSpecification(); 159 list.add(DomainObjectReprRenderer.valueOrRef(resourceContext, super.getJsonValueEncoder(), choiceAdapter)); 160 } 161 return list; 162 } 163 164 private Object defaultFor(final ObjectActionParameter param) { 165 final ManagedObject defaultAdapter = param.getDefault(objectAdapter, null, null); 166 if (defaultAdapter == null) { 167 return null; 168 } 169 // REVIEW: previously was using the spec of the parameter, but think instead it should be the spec of the adapter itself 170 // final ObjectSpecification defaultSpec = param.getSpecification(); 171 return DomainObjectReprRenderer.valueOrRef(resourceContext, super.getJsonValueEncoder(), defaultAdapter); 172 } 173 174 // /////////////////////////////////////////////////// 175 // extensions and links 176 // /////////////////////////////////////////////////// 177 @Override 178 protected void addLinksToFormalDomainModel() { 179 if (resourceContext.suppressDescribedByLinks()) { 180 return; 181 } 182 final JsonRepresentation link = ActionDescriptionReprRenderer.newLinkToBuilder(resourceContext, Rel.DESCRIBEDBY, objectAdapter.getSpecification(), objectMember).build(); 183 getLinks().arrayAdd(link); 184 } 185 186 @Override 187 protected void addLinksIsisProprietary() { 188 // umm... 189 if (false /*objectMember.isContributed() */) { 190 final ManagedObject serviceAdapter = contributingServiceAdapter(); 191 final JsonRepresentation contributedByLink = DomainObjectReprRenderer.newLinkToBuilder(resourceContext, Rel.CONTRIBUTED_BY, serviceAdapter).build(); 192 getLinks().arrayAdd(contributedByLink); 193 } 194 } 195 196 @Override 197 protected void putExtensionsIsisProprietary() { 198 getExtensions().mapPut("actionType", objectMember.getType().name().toLowerCase()); 199 final SemanticsOf semantics = objectMember.getSemantics(); 200 getExtensions().mapPut("actionSemantics", semantics.getCamelCaseName()); 201 } 202}