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.domaintypes; 018 019import java.util.List; 020 021import org.apache.isis.core.metamodel.spec.ObjectSpecification; 022import org.apache.isis.core.metamodel.spec.feature.Contributed; 023import org.apache.isis.core.metamodel.spec.feature.ObjectAction; 024import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation; 025import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation; 026import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation; 027import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation; 028import org.apache.isis.viewer.restfulobjects.applib.Rel; 029import org.apache.isis.viewer.restfulobjects.applib.RepresentationType; 030import org.apache.isis.viewer.restfulobjects.rendering.LinkBuilder; 031import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs; 032import org.apache.isis.viewer.restfulobjects.rendering.RendererContext; 033import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererAbstract; 034 035import org.codehaus.jackson.node.NullNode; 036 037import com.google.common.base.Strings; 038 039public class DomainTypeReprRenderer extends ReprRendererAbstract<DomainTypeReprRenderer, ObjectSpecification> { 040 041 public static LinkBuilder newLinkToBuilder(final RendererContext resourceContext, final Rel rel, final ObjectSpecification objectSpec) { 042 final String typeFullName = objectSpec.getSpecId().asString(); 043 final String url = "domain-types/" + typeFullName; 044 return LinkBuilder.newBuilder(resourceContext, rel.getName(), RepresentationType.DOMAIN_TYPE, url); 045 } 046 047 private ObjectSpecification objectSpecification; 048 049 public DomainTypeReprRenderer(final RendererContext resourceContext, final LinkFollowSpecs linkFollower, final JsonRepresentation representation) { 050 super(resourceContext, linkFollower, RepresentationType.DOMAIN_TYPE, representation); 051 } 052 053 @Override 054 public DomainTypeReprRenderer with(final ObjectSpecification objectSpecification) { 055 this.objectSpecification = objectSpecification; 056 return cast(this); 057 } 058 059 @Override 060 public JsonRepresentation render() { 061 062 if (objectSpecification == null) { 063 throw new IllegalStateException("ObjectSpecification not specified"); 064 } 065 066 // self 067 if (includesSelf) { 068 final JsonRepresentation selfLink = newLinkToBuilder(getRendererContext(), Rel.SELF, objectSpecification).build(); 069 getLinks().arrayAdd(selfLink); 070 } 071 072 representation.mapPut("canonicalName", objectSpecification.getFullIdentifier()); 073 addMembers(); 074 075 addTypeActions(); 076 077 putExtensionsNames(); 078 putExtensionsDescriptionIfAvailable(); 079 putExtensionsIfService(); 080 081 return representation; 082 } 083 084 private void addMembers() { 085 final JsonRepresentation membersList = JsonRepresentation.newArray(); 086 representation.mapPut("members", membersList); 087 final List<ObjectAssociation> associations = objectSpecification.getAssociations(Contributed.EXCLUDED); 088 for (final ObjectAssociation association : associations) { 089 if (association.isOneToOneAssociation()) { 090 final OneToOneAssociation property = (OneToOneAssociation) association; 091 final LinkBuilder linkBuilder = PropertyDescriptionReprRenderer.newLinkToBuilder(getRendererContext(), Rel.PROPERTY, objectSpecification, property); 092 membersList.arrayAdd(linkBuilder.build()); 093 } else if (association.isOneToManyAssociation()) { 094 final OneToManyAssociation collection = (OneToManyAssociation) association; 095 final LinkBuilder linkBuilder = CollectionDescriptionReprRenderer.newLinkToBuilder(getRendererContext(), Rel.PROPERTY, objectSpecification, collection); 096 membersList.arrayAdd(linkBuilder.build()); 097 } 098 } 099 final List<ObjectAction> actions = objectSpecification.getObjectActions(Contributed.INCLUDED); 100 for (final ObjectAction action : actions) { 101 final LinkBuilder linkBuilder = ActionDescriptionReprRenderer.newLinkToBuilder(getRendererContext(), Rel.ACTION, objectSpecification, action); 102 membersList.arrayAdd(linkBuilder.build()); 103 } 104 } 105 106 private JsonRepresentation getTypeActions() { 107 JsonRepresentation typeActions = representation.getArray("typeActions"); 108 if (typeActions == null) { 109 typeActions = JsonRepresentation.newArray(); 110 representation.mapPut("typeActions", typeActions); 111 } 112 return typeActions; 113 } 114 115 private void addTypeActions() { 116 getTypeActions().arrayAdd(linkToIsSubtypeOf()); 117 getTypeActions().arrayAdd(linkToIsSupertypeOf()); 118 } 119 120 private JsonRepresentation linkToIsSubtypeOf() { 121 final String url = "domain-types/" + objectSpecification.getSpecId().asString() + "/type-actions/isSubtypeOf/invoke"; 122 123 final LinkBuilder linkBuilder = LinkBuilder.newBuilder(getRendererContext(), Rel.INVOKE.andParam("typeaction", "isSubtypeOf"), RepresentationType.TYPE_ACTION_RESULT, url); 124 final JsonRepresentation arguments = argumentsTo(getRendererContext(), "supertype", null); 125 final JsonRepresentation link = linkBuilder.withArguments(arguments).build(); 126 return link; 127 } 128 129 private JsonRepresentation linkToIsSupertypeOf() { 130 final String url = "domain-types/" + objectSpecification.getSpecId().asString() + "/type-actions/isSupertypeOf/invoke"; 131 132 final LinkBuilder linkBuilder = LinkBuilder.newBuilder(getRendererContext(), Rel.INVOKE.andParam("typeaction", "isSupertypeOf"), RepresentationType.TYPE_ACTION_RESULT, url); 133 final JsonRepresentation arguments = argumentsTo(getRendererContext(), "subtype", null); 134 final JsonRepresentation link = linkBuilder.withArguments(arguments).build(); 135 return link; 136 } 137 138 public static JsonRepresentation argumentsTo(final RendererContext resourceContext, final String paramName, final ObjectSpecification objectSpec) { 139 final JsonRepresentation arguments = JsonRepresentation.newMap(); 140 final JsonRepresentation link = JsonRepresentation.newMap(); 141 arguments.mapPut(paramName, link); 142 if (objectSpec != null) { 143 link.mapPut("href", resourceContext.urlFor("domain-types/" + objectSpec.getSpecId().asString())); 144 } else { 145 link.mapPut("href", NullNode.instance); 146 } 147 return arguments; 148 } 149 150 protected void putExtensionsNames() { 151 final String singularName = objectSpecification.getSingularName(); 152 getExtensions().mapPut("friendlyName", singularName); 153 154 final String pluralName = objectSpecification.getPluralName(); 155 getExtensions().mapPut("pluralName", pluralName); 156 } 157 158 protected void putExtensionsDescriptionIfAvailable() { 159 final String description = objectSpecification.getDescription(); 160 if (!Strings.isNullOrEmpty(description)) { 161 getExtensions().mapPut("description", description); 162 } 163 } 164 165 protected void putExtensionsIfService() { 166 getExtensions().mapPut("isService", objectSpecification.isService()); 167 } 168 169}