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