Package org.apache.isis.viewer.json.viewer.resources.domainobjects

Source Code of org.apache.isis.viewer.json.viewer.resources.domainobjects.AbstractObjectMemberReprRenderer

/**
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package org.apache.isis.viewer.json.viewer.resources.domainobjects;

import org.codehaus.jackson.node.NullNode;

import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.consent.Consent;
import org.apache.isis.core.metamodel.facetapi.Facet;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
import org.apache.isis.viewer.json.applib.JsonRepresentation;
import org.apache.isis.viewer.json.applib.RepresentationType;
import org.apache.isis.viewer.json.applib.links.Rel;
import org.apache.isis.viewer.json.viewer.ResourceContext;
import org.apache.isis.viewer.json.viewer.representations.LinkFollower;
import org.apache.isis.viewer.json.viewer.representations.ReprRendererAbstract;

public abstract class AbstractObjectMemberReprRenderer<R extends ReprRendererAbstract<R, ObjectAndMember<T>>, T extends ObjectMember> extends ReprRendererAbstract<R, ObjectAndMember<T>> {

    protected enum Mode {
        INLINE, FOLLOWED, STANDALONE, MUTATED, ARGUMENTS;

        public boolean isInline() {
            return this == INLINE;
        }

        public boolean isFollowed() {
            return this == FOLLOWED;
        }

        public boolean isStandalone() {
            return this == STANDALONE;
        }

        public boolean isMutated() {
            return this == MUTATED;
        }

        public boolean isArguments() {
            return this == ARGUMENTS;
        }
    }

    protected ObjectAdapterLinkTo linkTo;

    protected ObjectAdapter objectAdapter;
    protected MemberType memberType;
    protected T objectMember;
    protected Mode mode = Mode.INLINE; // unless we determine otherwise

    public AbstractObjectMemberReprRenderer(final ResourceContext resourceContext, final LinkFollower linkFollower, final RepresentationType representationType, final JsonRepresentation representation) {
        super(resourceContext, linkFollower, representationType, representation);
    }

    @Override
    public R with(final ObjectAndMember<T> objectAndMember) {
        this.objectAdapter = objectAndMember.getObjectAdapter();
        this.objectMember = objectAndMember.getMember();
        this.memberType = MemberType.determineFrom(objectMember);
        usingLinkTo(new DomainObjectLinkTo());

        // done eagerly so can use as criteria for x-ro-follow-links
        representation.mapPut(memberType.getJsProp(), objectMember.getId());
        representation.mapPut("memberType", memberType.getName());

        return cast(this);
    }

    /**
     * Must be called after {@link #with(ObjectAndMember)} (which provides the
     * {@link #objectAdapter}).
     */
    public R usingLinkTo(final ObjectAdapterLinkTo linkTo) {
        this.linkTo = linkTo.usingResourceContext(resourceContext).with(objectAdapter);
        return cast(this);
    }

    /**
     * Indicate that this is a standalone representation.
     */
    public R asStandalone() {
        mode = Mode.STANDALONE;
        return cast(this);
    }

    /**
     * Indicate that this is a representation to include as the result of a
     * followed link.
     */
    public R asFollowed() {
        mode = Mode.FOLLOWED;
        return cast(this);
    }

    /**
     * Indicates that the representation was produced as the result of a
     * resource that mutated the state.
     *
     * <p>
     * The effect of this is to suppress the link to self.
     */
    public R asMutated() {
        mode = Mode.MUTATED;
        return cast(this);
    }

    public R asArguments() {
        mode = Mode.ARGUMENTS;
        return cast(this);
    }

    /**
     * For subclasses to call from their {@link #render()} method.
     */
    protected void renderMemberContent() {
        if (mode.isInline()) {
            addDetailsLinkIfPersistent();
        }

        if (mode.isStandalone()) {
            addLinkToSelf();
        }

        if (mode.isStandalone() || mode.isMutated()) {
            addLinkToUp();
        }

        if (mode.isFollowed() || mode.isStandalone() || mode.isMutated()) {
            addMutatorsIfEnabled();

            putExtensionsIsisProprietary();
            addLinksToFormalDomainModel();
            addLinksIsisProprietary();
        }
    }

    private void addLinkToSelf() {
        getLinks().arrayAdd(linkTo.memberBuilder(Rel.SELF, memberType, objectMember).build());
    }

    private void addLinkToUp() {
        getLinks().arrayAdd(linkTo.builder(Rel.UP).build());
    }

    protected abstract void addMutatorsIfEnabled();

    /**
     * For subclasses to call back to when {@link #addMutatorsIfEnabled() adding
     * mutators}.
     */
    protected void addLinkFor(final MutatorSpec mutatorSpec) {
        if (!hasMemberFacet(mutatorSpec.mutatorFacetType)) {
            return;
        }
        final JsonRepresentation arguments = mutatorArgs(mutatorSpec);
        final RepresentationType representationType = memberType.getRepresentationType();
        final JsonRepresentation mutatorLink = linkToForMutatorInvoke().memberBuilder(mutatorSpec.rel, memberType, objectMember, representationType, mutatorSpec.suffix).withHttpMethod(mutatorSpec.httpMethod).withArguments(arguments).build();
        getLinks().arrayAdd(mutatorLink);
    }

    /**
     * Hook to allow actions to render invoke links that point to the
     * contributing service.
     */
    protected ObjectAdapterLinkTo linkToForMutatorInvoke() {
        return linkTo;
    }

    /**
     * Default implementation (common to properties and collections) that can be
     * overridden (ie by actions) if required.
     */
    protected JsonRepresentation mutatorArgs(final MutatorSpec mutatorSpec) {
        if (mutatorSpec.arguments.isNone()) {
            return null;
        }
        if (mutatorSpec.arguments.isOne()) {
            final JsonRepresentation repr = JsonRepresentation.newMap();
            repr.mapPut("value", NullNode.getInstance()); // force a null into
                                                          // the map
            return repr;
        }
        // overridden by actions
        throw new UnsupportedOperationException("override mutatorArgs() to populate for many arguments");
    }

    private void addDetailsLinkIfPersistent() {
        if (!objectAdapter.isPersistent()) {
            return;
        }
        final JsonRepresentation link = linkTo.memberBuilder(Rel.DETAILS, memberType, objectMember).build();
        getLinks().arrayAdd(link);

        final LinkFollower membersLinkFollower = getLinkFollower();
        final LinkFollower detailsLinkFollower = membersLinkFollower.follow("links[rel=%s]", Rel.DETAILS.getName());
        if (membersLinkFollower.matches(representation) && detailsLinkFollower.matches(link)) {
            followDetailsLink(link);
        }
        return;
    }

    protected abstract void followDetailsLink(JsonRepresentation detailsLink);

    protected final void putDisabledReasonIfDisabled() {
        final String disabledReasonRep = usability().getReason();
        representation.mapPut("disabledReason", disabledReasonRep);
    }

    protected abstract void putExtensionsIsisProprietary();

    protected abstract void addLinksToFormalDomainModel();

    protected abstract void addLinksIsisProprietary();

    /**
     * Convenience method.
     */
    public boolean isMemberVisible() {
        return visibility().isAllowed();
    }

    protected <F extends Facet> F getMemberSpecFacet(final Class<F> facetType) {
        final ObjectSpecification otoaSpec = objectMember.getSpecification();
        return otoaSpec.getFacet(facetType);
    }

    protected boolean hasMemberFacet(final Class<? extends Facet> facetType) {
        return objectMember.getFacet(facetType) != null;
    }

    protected Consent usability() {
        return objectMember.isUsable(getSession(), objectAdapter);
    }

    protected Consent visibility() {
        return objectMember.isVisible(getSession(), objectAdapter);
    }

}
TOP

Related Classes of org.apache.isis.viewer.json.viewer.resources.domainobjects.AbstractObjectMemberReprRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.