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}