/** * Copyright (c) 2013-2016, The SeedStack authors <http://seedstack.org> * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.seedstack.seed.rest.internal.jsonhome; import org.seedstack.seed.SeedException; import org.seedstack.seed.rest.internal.RestErrorCode; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * Defines the hints representation as defined by the * <a href="http://tools.ietf.org/html/draft-nottingham-json-home-03#section-4">IETF draft</a>. * * @see org.seedstack.seed.rest.internal.jsonhome.JsonHome */ public class Hints { private List<String> allow = new ArrayList<>(); private Map<String, Object> formats = new TreeMap<>(); private List<String> acceptPath = new ArrayList<>(); private List<String> acceptPost = new ArrayList<>(); private List<String> acceptRanges = new ArrayList<>(); private List<String> acceptPrefer = new ArrayList<>(); private URI docs; private List<String> preconditionReq = new ArrayList<>(); private List<AuthorizationRequired> authReq = new ArrayList<>(); private Status status; public enum Status { GONE, DEPRECATED } /** * Merges the current hints with hints comming from another method of the resource. * * @param hints the hints to merge */ public void merge(Hints hints) { this.allow.addAll(hints.getAllow()); this.formats.putAll(hints.getFormats()); this.acceptPath.addAll(hints.getAcceptPath()); this.acceptPost.addAll(hints.getAcceptPost()); this.acceptRanges.addAll(hints.getAcceptRanges()); this.acceptPrefer.addAll(hints.getAcceptPrefer()); mergeDocs(hints); preconditionReq.addAll(hints.getPreconditionReq()); authReq.addAll(hints.getAuthReq()); mergeStatus(hints); } /** * Merges docs. If the other resource has a different docs link, it throws a {@code SeedException}. * * @param hints the hints to merge */ private void mergeDocs(Hints hints) { if (docs != null) { if (hints.getDocs() != null && !docs.equals(hints.getDocs())) { throw SeedException.createNew(RestErrorCode.CANNOT_MERGE_RESOURCES_WITH_DIFFERENT_DOC) .put("oldDoc", docs).put("newDoc", hints.getDocs()); } } else { this.docs = hints.getDocs(); } } /** * Merges the status. If one of the resource have different status the status will be * chosen according to the following priorities: * <ol> * <li>GONE</li> * <li>DEPRECATED</li> * <li>NONE</li> * </ol> * * @param hints the hints to merge */ private void mergeStatus(Hints hints) { if (status != null) { if (hints.getStatus() != null && !status.equals(hints.getStatus())) { switch (hints.getStatus()) { case GONE: status = Status.GONE; break; case DEPRECATED: if (status != Status.GONE) { status = Status.DEPRECATED; } break; } } } else { this.status = hints.getStatus(); } } public List<String> getAllow() { return allow; } public void addAllow(String allow) { this.allow.add(allow); } public Map<String, Object> getFormats() { return formats; } public void format(String mediaType, Object representation) { this.formats.put(mediaType, representation); } public List<String> getAcceptPath() { return acceptPath; } public void acceptPath(String acceptPath) { this.acceptPath.add(acceptPath); } public List<String> getAcceptPost() { return acceptPost; } public void acceptPost(String acceptPost) { this.acceptPost.add(acceptPost); } public List<String> getAcceptRanges() { return acceptRanges; } public void acceptRanges(String acceptRanges) { this.acceptRanges.add(acceptRanges); } public List<String> getAcceptPrefer() { return acceptPrefer; } public void acceptPrefer(String acceptPrefer) { this.acceptPrefer.add(acceptPrefer); } public URI getDocs() { return docs; } public void setDocs(URI docs) { this.docs = docs; } public List<String> getPreconditionReq() { return preconditionReq; } public void preconditionReq(String preconditionReq) { this.preconditionReq.add(preconditionReq); } public List<AuthorizationRequired> getAuthReq() { return authReq; } public void authReq(AuthorizationRequired authReq) { this.authReq.add(authReq); } public Status getStatus() { return status; } public void setStatus(Status status) { this.status = status; } public Map<String, Object> toRepresentation() { HashMap<String, Object> repr = new HashMap<>(); addOptional(repr, "allow", allow); addOptional(repr, "formats", formats); addOptional(repr, "accept-patch", acceptPath); addOptional(repr, "accept-post", acceptPost); addOptional(repr, "accept-ranges", acceptRanges); addOptional(repr, "accept-prefer", acceptPrefer); addOptional(repr, "docs", docs); addOptional(repr, "precondition-req", preconditionReq); addOptional(repr, "auth-req", authReq); addOptional(repr, "status", status); return repr; } private void addOptional(Map<String, Object> representation, String name, Object object) { if (object == null) { return; } boolean isEmptyCollection = Collection.class.isAssignableFrom(object.getClass()) && ((Collection) object).isEmpty(); boolean isEmptyMap = Map.class.isAssignableFrom(object.getClass()) && ((Map) object).isEmpty(); if (!isEmptyCollection && !isEmptyMap) { representation.put(name, object); } } }