/** * 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.hal; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * An HAL resource representation as defined in the * <a href="https://tools.ietf.org/html/draft-kelly-json-hal-06#section-3">RFC specification</a>. * <p> * It's a resource object with two reserved properties: * </p> * <ul> * <li>"_links": links to other resources</li> * <li>"_embedded": embedded resources</li> * </ul> * * For instance: * <pre> * GET /orders/523 HTTP/1.1 * Host: example.org * Accept: application/hal+json * * HTTP/1.1 200 OK * Content-Type: application/hal+json * * { * "_links": { * "self": { "href": "/orders/523" }, * "warehouse": { "href": "/warehouse/56" }, * "invoice": { "href": "/invoices/873" } * }, * "currency": "USD", * "status": "shipped", * "total": 10.20 * } * </pre> */ public class HalRepresentation { /** * Links as defined in the <a href="https://tools.ietf.org/html/draft-kelly-json-hal-06#section-4.1.1">specification</a> * is a map whose keys are rel and values can be either an object link or an array of object links. * <p> * So Object can be a List<Link> or a {@link Link} * </p> */ @JsonProperty("_links") @JsonInclude(JsonInclude.Include.NON_DEFAULT) private final Map<String, Object> links = new HashMap<>(); @JsonProperty("_embedded") @JsonInclude(JsonInclude.Include.NON_DEFAULT) private final Map<String, Object> embedded = new HashMap<>(); /** * Default constructor required by Jackson. */ public HalRepresentation() { } /** * Adds the self link. * * @param href the resource href * @return itself */ public HalRepresentation self(String href) { addLink("self", new Link(href)); return this; } /** * Adds the self link. * * @param link the link * @return itself */ public HalRepresentation self(Link link) { addLink("self", link); return this; } /** * Adds a link with the specified rel and href. * * @param rel the rel * @param href the href * @return itself */ public HalRepresentation link(String rel, String href) { addLink(rel, new Link(href)); return this; } /** * Adds a link with the specified rel and link representation. * * @param rel the rel * @param link the link representation * @return itself */ public HalRepresentation link(String rel, Link link) { addLink(rel, link); return this; } /** * Returns the resource's links. * * @return map of links */ public Object getLink(String rel) { return links.get(rel); } /** * Returns the resource's links. * * @return map of links */ public Map<String, Object> getLinks() { return links; } private void addLink(String rel, Link link) { Object obj = links.get(rel); if (obj == null) { links.put(rel, link); } else if (obj instanceof List) { //noinspection unchecked List<Link> linksForRel = (List<Link>) obj; linksForRel.add(link); links.put(rel, linksForRel); } else if (obj instanceof Link){ Link linkCopy = (Link) obj; List<Link> linksForRel = new ArrayList<>(); linksForRel.add(linkCopy); linksForRel.add(link); links.put(rel, linksForRel); } } /** * Adds an embedded resource or array of resources. * * @param rel the relation type * @param embedded the resource (can be an array of resources) * @return itself */ public HalRepresentation embedded(String rel, Object embedded) { this.embedded.put(rel, embedded); return this; } /** * Returns the embedded resources. * * @return the map of embedded resources */ public Map<String, Object> getEmbedded() { return embedded; } }