001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *        http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 */
019package org.apache.isis.viewer.restfulobjects.rendering.service.conneg;
020
021import java.util.List;
022import java.util.Objects;
023
024import javax.ws.rs.core.MediaType;
025import javax.ws.rs.core.Response;
026import javax.xml.bind.annotation.XmlRootElement;
027
028import org.apache.isis.commons.internal.base._Strings;
029import org.apache.isis.commons.internal.collections._Lists;
030import org.apache.isis.commons.internal.factory._InstanceUtil;
031import org.apache.isis.core.metamodel.interactions.managed.ManagedAction;
032import org.apache.isis.core.metamodel.interactions.managed.ManagedCollection;
033import org.apache.isis.core.metamodel.interactions.managed.ManagedProperty;
034import org.apache.isis.core.metamodel.spec.ManagedObject;
035import org.apache.isis.viewer.restfulobjects.applib.RestfulResponse;
036import org.apache.isis.viewer.restfulobjects.rendering.IResourceContext;
037import org.apache.isis.viewer.restfulobjects.rendering.RestfulObjectsApplicationException;
038import org.apache.isis.viewer.restfulobjects.rendering.domainobjects.ObjectAndActionInvocation;
039
040public abstract class ContentNegotiationServiceAbstract implements ContentNegotiationService {
041
042    @Override
043    public Response.ResponseBuilder buildResponse(
044            final IResourceContext renderContext2,
045            final ManagedObject objectAdapter) {
046        return null;
047    }
048
049    @Override
050    public Response.ResponseBuilder buildResponse(
051            final IResourceContext renderContext2,
052            final ManagedProperty objectAndProperty)  {
053        return null;
054    }
055
056    @Override
057    public Response.ResponseBuilder buildResponse(
058            final IResourceContext renderContext2,
059            final ManagedCollection objectAndCollection) {
060        return null;
061    }
062
063    @Override
064    public Response.ResponseBuilder buildResponse(
065            final IResourceContext renderContext2,
066            final ManagedAction objectAndAction)  {
067        return null;
068    }
069
070    @Override
071    public Response.ResponseBuilder buildResponse(
072            final IResourceContext renderContext2,
073            final ObjectAndActionInvocation objectAndActionInvocation) {
074        return null;
075    }
076
077    // -- convenience methods for subclasses (possibly hooks)
078
079    /**
080     * Potential hook to allow a domain object to be mapped.
081     */
082    protected Object objectOf(final ManagedObject objectAdapter) {
083        return objectAdapter.getPojo();
084    }
085
086    protected Object returnedObjectOf(final ObjectAndActionInvocation objectAndActionInvocation) {
087        final ManagedObject returnedAdapter = objectAndActionInvocation.getReturnedAdapter();
088        return objectOf(returnedAdapter);
089    }
090
091    protected Class<?> loadClass(final String cls) {
092        final Class<?> domainType;
093        try {
094            domainType = _InstanceUtil.loadClass(cls);
095        }catch (final Exception ex) {
096            throw RestfulObjectsApplicationException.createWithCause(RestfulResponse.HttpStatusCode.BAD_REQUEST, ex);
097        }
098
099        return domainType;
100    }
101
102    protected void ensureJaxbAnnotated(final Class<?> domainType) {
103        if(domainType.getAnnotation(XmlRootElement.class) == null) {
104            throw RestfulObjectsApplicationException.createWithMessage(RestfulResponse.HttpStatusCode.BAD_REQUEST, "Requested domain Type '" + domainType.getName() + "' is not annotated with JAXB @XmlRootElement annotation");
105        }
106    }
107
108    protected void ensureDomainObjectAssignable(final String xRoDomainType, final Class<?> domainType, final Object domainObject) {
109        if(!domainType.isAssignableFrom(domainObject.getClass())) {
110            throw RestfulObjectsApplicationException.createWithMessage(
111                    RestfulResponse.HttpStatusCode.NOT_ACCEPTABLE,
112                    "Requested object of type '%s' however the object returned by the domain object is not assignable (is '%s')",
113                    xRoDomainType, domainObject.getClass().getName());
114        }
115    }
116
117    protected boolean mediaTypeParameterMatches(
118            final List<MediaType> acceptableMediaTypes,
119            final String parameter, final String parameterValue) {
120        for (MediaType mediaType : acceptableMediaTypes) {
121            final String paramValue = sanitize(mediaType.getParameters().get(parameter));
122            if (Objects.equals(paramValue, parameterValue)) {
123                return true;
124            }
125        }
126        return false;
127    }
128
129    protected List<String> mediaTypeParameterList(
130            final List<MediaType> acceptableMediaTypes,
131            final String parameter) {
132        final List<String> paramList = _Lists.newArrayList();
133        for (MediaType mediaType : acceptableMediaTypes) {
134            final String paramValue = sanitize(mediaType.getParameters().get(parameter));
135            _Strings.splitThenStream(paramValue, ",")
136            .map(String::trim)
137            .forEach(paramList::add);
138        }
139        return paramList;
140    }
141
142
143    /**
144     * Remove any single quotes.
145     */
146    private String sanitize(String mediaParam) {
147        if (mediaParam == null) {
148            return null;
149        }
150        mediaParam = mediaParam.trim();
151        if(mediaParam.startsWith("'")) {
152            mediaParam = mediaParam.substring(1);
153        }
154        if(mediaParam.endsWith("'")) {
155            mediaParam = mediaParam.substring(0, mediaParam.length()-1);
156        }
157        return mediaParam;
158    }
159
160}