Link.java
/*
* #%L
* wcm.io
* %%
* Copyright (C) 2014 wcm.io
* %%
* Licensed 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.
* #L%
*/
package io.wcm.caravan.hal.resource;
import java.util.List;
import java.util.regex.Pattern;
import org.osgi.annotation.versioning.ProviderType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ListMultimap;
/**
* Bean representation of a HAL link.
*/
@ProviderType
public final class Link implements HalObject {
/**
* Pattern that will hit an RFC 6570 URI template.
*/
private static final Pattern URI_TEMPLATE_PATTERN = Pattern.compile("\\{.+\\}");
private final ObjectNode model;
private HalResource context;
/**
* @param model JSON model
*/
public Link(JsonNode model) {
if (!(model instanceof ObjectNode)) {
throw new IllegalArgumentException("the given model must be of type ObjectNode");
}
this.model = (ObjectNode)model;
}
/**
* @param model JSON model
*/
public Link(ObjectNode model) {
this.model = model;
}
/**
* Creates a link with a new model that only contains the given URI
* @param href the URI to put in the "href" property
*/
public Link(String href) {
this.model = JsonNodeFactory.instance.objectNode();
this.setHref(href);
}
@Override
public ObjectNode getModel() {
return model;
}
/**
* @return the type
*/
public String getType() {
return model.path("type").asText(null);
}
/**
* @param type the type to set
* @return Link
*/
public Link setType(String type) {
model.put("type", type);
return this;
}
/**
* @return the deprecation
*/
public String getDeprecation() {
return model.path("deprecation").asText(null);
}
/**
* @param deprecation the deprecation to set
* @return Link
*/
public Link setDeprecation(String deprecation) {
model.put("deprecation", deprecation);
return this;
}
/**
* @return the name
*/
public String getName() {
return model.path("name").asText(null);
}
/**
* @param name the name to set
* @return Link
*/
public Link setName(String name) {
model.put("name", name);
return this;
}
/**
* @return the profile
*/
public String getProfile() {
return model.path("profile").asText(null);
}
/**
* @param profile the profile to set
* @return Link
*/
public Link setProfile(String profile) {
model.put("profile", profile);
return this;
}
/**
* @return the title
*/
public String getTitle() {
return model.path("title").asText(null);
}
/**
* @param title the title to set
* @return Link
*/
public Link setTitle(String title) {
model.put("title", title);
return this;
}
/**
* @return the hreflang
*/
public String getHreflang() {
return model.path("hreflang").asText(null);
}
/**
* @param hreflang the hreflang to set
* @return Link
*/
public Link setHreflang(String hreflang) {
model.put("hreflang", hreflang);
return this;
}
/**
* @return the href
*/
public String getHref() {
return model.path("href").asText(null);
}
/**
* @param href the href to set
* @return Link
*/
public Link setHref(String href) {
model.put("href", href);
if (href != null && URI_TEMPLATE_PATTERN.matcher(href).find()) {
setTemplated(true);
}
return this;
}
/**
* @return is templated
*/
public boolean isTemplated() {
return model.path("templated").asBoolean();
}
/**
* @param templated the templated to set
* @return Link
*/
public Link setTemplated(boolean templated) {
model.put("templated", templated);
return this;
}
/**
* Removes this link from its context resource's JSON representation
* @throws IllegalStateException if this link was never added to a resource, or has already been removed
*/
public void remove() {
if (context == null) {
throw new IllegalStateException("link with href=" + getHref() + " can not be removed, because it's not part of a HAL resource tree");
}
// iterate over all links grouped by relation (because for removal we need to know the relation)
ListMultimap<String, Link> allLinks = context.getLinks();
for (String relation : allLinks.keySet()) {
List<Link> links = allLinks.get(relation);
// use an indexed for-loop, because we need to know the index to properly remove the link
for (int i = 0; i < links.size(); i++) {
if (links.get(i).getModel() == model) {
context.removeLink(relation, i);
context = null;
return;
}
}
}
throw new IllegalStateException("the last known context resource of link with href=" + getHref() + " no longer contains this link");
}
/**
* @param contextResource the HAL resource that contains this link
*/
void setContext(HalResource contextResource) {
context = contextResource;
}
@Override
public int hashCode() {
return model.toString().hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Link)) {
return false;
}
else {
return model.toString().equals(((Link)obj).model.toString());
}
}
}