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;
021
022import java.util.List;
023import java.util.Map;
024import java.util.stream.Stream;
025import javax.ws.rs.core.MediaType;
026import org.apache.isis.core.commons.internal.collections._Lists;
027import org.apache.isis.core.commons.internal.collections._Maps;
028import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
029import org.apache.isis.core.metamodel.spec.ManagedObject;
030import org.apache.isis.core.metamodel.spec.ObjectSpecification;
031import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
032import org.apache.isis.viewer.restfulobjects.applib.Rel;
033import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
034import org.apache.isis.viewer.restfulobjects.rendering.domainobjects.DomainObjectReprRenderer;
035import org.apache.isis.viewer.restfulobjects.rendering.domainobjects.JsonValueEncoder;
036import org.apache.isis.viewer.restfulobjects.rendering.domaintypes.DomainTypeReprRenderer;
037
038public abstract class ReprRendererAbstract<R extends ReprRendererAbstract<R, T>, T> implements ReprRenderer<R, T> {
039    protected final IResourceContext resourceContext;
040    protected final JsonValueEncoder jsonValueEncoder;
041    private final LinkFollowSpecs linkFollower;
042    private final RepresentationType representationType;
043    protected final JsonRepresentation representation;
044    private final Map<String, String> mediaTypeParams = _Maps.newLinkedHashMap();
045    private final InteractionInitiatedBy interactionInitiatedBy;
046    protected boolean includesSelf;
047
048    public ReprRendererAbstract(final IResourceContext resourceContext, final LinkFollowSpecs linkFollower, final RepresentationType representationType, final JsonRepresentation representation) {
049        this.resourceContext = resourceContext;
050        this.jsonValueEncoder = resourceContext.getServiceRegistry().lookupServiceElseFail(JsonValueEncoder.class);
051        this.linkFollower = asProvidedElseCreate(linkFollower);
052        this.representationType = representationType;
053        this.representation = representation;
054        this.interactionInitiatedBy = determineInteractionInitiatedByFrom(this.resourceContext);
055    }
056
057    private static InteractionInitiatedBy determineInteractionInitiatedByFrom(final IResourceContext resourceContext) {
058        return resourceContext.getInteractionInitiatedBy();
059    }
060
061    protected InteractionInitiatedBy getInteractionInitiatedBy() {
062        return interactionInitiatedBy;
063    }
064
065    public LinkFollowSpecs getLinkFollowSpecs() {
066        return linkFollower;
067    }
068
069    private LinkFollowSpecs asProvidedElseCreate(final LinkFollowSpecs linkFollower) {
070        if (linkFollower != null) {
071            return linkFollower;
072        }
073        return LinkFollowSpecs.create(resourceContext.getFollowLinks());
074    }
075
076    @Override
077    public MediaType getMediaType() {
078        return representationType.getJsonMediaType(mediaTypeParams);
079    }
080
081    protected void addMediaTypeParams(String param, String paramValue) {
082        mediaTypeParams.put(param, paramValue);
083    }
084
085    @SuppressWarnings("unchecked")
086    public R includesSelf() {
087        this.includesSelf = true;
088        return (R) this;
089    }
090
091    public R withLink(final Rel rel, final String href) {
092        if (href != null) {
093            getLinks().arrayAdd(LinkBuilder.newBuilder(resourceContext, rel.getName(), representationType, href).build());
094        }
095        return cast(this);
096    }
097
098    public R withLink(final Rel rel, final JsonRepresentation link) {
099        final String relStr = link.getString("rel");
100        if (relStr == null || !relStr.equals(rel.getName())) {
101            throw new IllegalArgumentException("Provided link does not have a \'rel\' of \'" + rel.getName() + "\'; was: " + link);
102        }
103        if (link != null) {
104            getLinks().arrayAdd(link);
105        }
106        return cast(this);
107    }
108
109    /**
110     * Will lazily create links array as required
111     */
112    protected JsonRepresentation getLinks() {
113        JsonRepresentation links = representation.getArray("links");
114        if (links == null) {
115            links = JsonRepresentation.newArray();
116            representation.mapPut("links", links);
117        }
118        return links;
119    }
120
121    protected void addLink(final Rel rel, final ObjectSpecification objectSpec) {
122        if (objectSpec == null) {
123            return;
124        }
125        final LinkBuilder linkBuilder = DomainTypeReprRenderer.newLinkToBuilder(getResourceContext(), rel, objectSpec);
126        JsonRepresentation link = linkBuilder.build();
127        getLinks().arrayAdd(link);
128        final LinkFollowSpecs linkFollower = getLinkFollowSpecs().follow("links");
129        if (linkFollower.matches(link)) {
130            final DomainTypeReprRenderer renderer = new DomainTypeReprRenderer(getResourceContext(), linkFollower, JsonRepresentation.newMap()).with(objectSpec);
131            link.mapPut("value", renderer.render());
132        }
133    }
134
135    /**
136     * Will lazily create extensions map as required
137     */
138    protected JsonRepresentation getExtensions() {
139        JsonRepresentation extensions = representation.getMap("extensions");
140        if (extensions == null) {
141            extensions = JsonRepresentation.newMap();
142            representation.mapPut("extensions", extensions);
143        }
144        return extensions;
145    }
146
147    public R withExtensions(final JsonRepresentation extensions) {
148        if (!extensions.isMap()) {
149            throw new IllegalArgumentException("extensions must be a map");
150        }
151        representation.mapPut("extensions", extensions);
152        return cast(this);
153    }
154
155    @SuppressWarnings("unchecked")
156    protected static <R extends ReprRendererAbstract<R, T>, T> R cast(final ReprRendererAbstract<R, T> builder) {
157        return (R) builder;
158    }
159
160    @Override
161    public abstract JsonRepresentation render();
162
163    /**
164     * Convenience for representations that are returned from objects that
165
166     * mutate state.
167     */
168    protected final void addExtensionsIsisProprietaryChangedObjects() {
169        // TODO: have removed UpdateNotifier, plan is to re-introduce using the IsisTransaction 
170        // enlisted objects (which would also allow newly-created objects to be shown)
171        final List<ManagedObject> changedObjects = _Lists.newArrayList(); // updateNotifier.getChangedObjects();
172        final List<ManagedObject> disposedObjects = _Lists.newArrayList(); // updateNotifier.getDisposedObjects();
173        addToExtensions("changed", changedObjects);
174        addToExtensions("disposed", disposedObjects);
175    }
176
177    private void addToExtensions(final String key, final List<ManagedObject> adapters) {
178        if (adapters == null || adapters.isEmpty()) {
179            return;
180        }
181        final JsonRepresentation adapterList = JsonRepresentation.newArray();
182        getExtensions().mapPut(key, adapterList);
183        for (final org.apache.isis.core.metamodel.spec.ManagedObject adapter : adapters) {
184            adapterList.arrayAdd(DomainObjectReprRenderer.newLinkToBuilder(getResourceContext(), Rel.VALUE, adapter).build());
185        }
186    }
187
188    protected Stream<ManagedObject> streamServiceAdapters() {
189        final org.apache.isis.core.metamodel.context.MetaModelContext metaModelContext = resourceContext.getMetaModelContext();
190        return metaModelContext.streamServiceAdapters();
191    }
192
193    @java.lang.SuppressWarnings("all")
194    public IResourceContext getResourceContext() {
195        return this.resourceContext;
196    }
197
198    @java.lang.SuppressWarnings("all")
199    public JsonValueEncoder getJsonValueEncoder() {
200        return this.jsonValueEncoder;
201    }
202}