/* * Copyright 2013-2016 the original author or authors. * * 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. */ package org.springframework.hateoas.hal; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.springframework.hateoas.IanaRels; import org.springframework.hateoas.Link; import org.springframework.hateoas.Links; import org.springframework.hateoas.UriTemplate; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; /** * Default implementation of {@link CurieProvider} rendering a single configurable {@link UriTemplate} based curie. * * @author Oliver Gierke * @author Jeff Stano * @since 0.9 */ public class DefaultCurieProvider implements CurieProvider { private final Map<String, UriTemplate> curies; private final String defaultCurie; /** * Creates a new {@link DefaultCurieProvider} for the given name and {@link UriTemplate}. The curie will be used to * expand previously unprefixed, non-IANA link relations. * * @param name must not be {@literal null} or empty. * @param uriTemplate must not be {@literal null} and contain exactly one template variable. */ public DefaultCurieProvider(String name, UriTemplate uriTemplate) { this(Collections.singletonMap(name, uriTemplate)); } /** * Creates a new {@link DefaultCurieProvider} for the given curies. If more than one curie is given, no default curie * will be registered. Use {@link #DefaultCurieProvider(Map, String)} to define which of the provided curies shall be * used as the default one. * * @param curies must not be {@literal null}. * @see #DefaultCurieProvider(String, UriTemplate) * @since 0.19 */ public DefaultCurieProvider(Map<String, UriTemplate> curies) { this(curies, null); } /** * Creates a new {@link DefaultCurieProvider} for the given curies using the one with the given name as default, which * means to expand unprefixed, non-IANA link relations. * * @param curies must not be {@literal null}. * @param defaultCurieName can be {@literal null}. * @since 0.19 */ public DefaultCurieProvider(Map<String, UriTemplate> curies, String defaultCurieName) { Assert.notNull(curies, "Curies must not be null!"); for (Entry<String, UriTemplate> entry : curies.entrySet()) { String name = entry.getKey(); UriTemplate template = entry.getValue(); Assert.hasText(name, "Curie name must not be null or empty!"); Assert.notNull(template, "UriTemplate must not be null!"); Assert.isTrue(template.getVariableNames().size() == 1, String.format("Expected a single template variable in the UriTemplate %s!", template.toString())); } this.defaultCurie = StringUtils.hasText(defaultCurieName) ? defaultCurieName : curies.size() == 1 ? curies.keySet().iterator().next() : null; this.curies = Collections.unmodifiableMap(curies); } /* * (non-Javadoc) * @see org.springframework.hateoas.hal.CurieProvider#getCurieInformation() */ @Override public Collection<? extends Object> getCurieInformation(Links links) { List<Curie> result = new ArrayList<Curie>(curies.size()); for (Entry<String, UriTemplate> source : curies.entrySet()) { String name = source.getKey(); UriTemplate template = source.getValue(); result.add(new Curie(name, getCurieHref(name, template))); } return Collections.unmodifiableCollection(result); } /* * (non-Javadoc) * @see org.springframework.hateoas.hal.CurieProvider#getNamespacedRelFrom(org.springframework.hateoas.Link) */ @Override public String getNamespacedRelFrom(Link link) { return getNamespacedRelFor(link.getRel()); } /* * (non-Javadoc) * @see org.springframework.hateoas.hal.CurieProvider#getNamespacedRelFrom(java.lang.String) */ @Override public String getNamespacedRelFor(String rel) { boolean prefixingNeeded = defaultCurie != null && !IanaRels.isIanaRel(rel) && !rel.contains(":"); return prefixingNeeded ? String.format("%s:%s", defaultCurie, rel) : rel; } /** * Returns the href for the {@link Curie} instance to be created. Will prepend the current application URI (servlet * mapping) in case the template is not an absolute one in the first place. * * @param name will never be {@literal null} or empty. * @param template will never be {@literal null}. * @return the {@link String} to be used as href in the {@link Curie} to be created, must not be {@literal null}. */ protected String getCurieHref(String name, UriTemplate template) { if (template.toString().startsWith("http")) { return template.toString(); } String applicationUri = ServletUriComponentsBuilder.fromCurrentServletMapping().build().expand().toString(); return applicationUri.concat(template.toString()); } /** * Value object to get the curie {@link Link} rendered in JSON. * * @author Oliver Gierke */ protected static class Curie extends Link { private static final long serialVersionUID = 1L; private final String name; public Curie(String name, String href) { super(href, "curies"); this.name = name; } public String getName() { return name; } } }