/* * Copyright 2012 Erlend Hamnaberg * * 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 net.hamnaberg.json; import net.hamnaberg.json.extension.Extended; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.URI; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javaslang.control.Option; import net.hamnaberg.json.io.JsonSerializer; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import static javaslang.control.Option.of; public final class Collection extends Extended<Collection> implements Writable { Collection(Json.JObject value) { super(value); } @Override protected Collection copy(Json.JObject value) { return new Collection(value); } public static Collection create(URI href, List<Link> links, List<Item> items, List<Query> queries, Template template, Error error) { return create(of(href), links, items, queries, of(template), of(error)); } public static Collection create(Option<URI> href, List<Link> links, List<Item> items, List<Query> queries, Option<Template> template, Option<Error> error) { Map<String, Json.JValue> map = new LinkedHashMap<>(); map.put("version", Json.jString(Version.ONE.getIdentifier())); href.forEach(value -> map.put("href", Json.jString(value.toString()))); if (!links.isEmpty()) { map.put("links", Json.jArray(links.stream() .map(Extended::asJson) .collect(Collectors.toList()))); } if (!items.isEmpty()) { map.put("items", Json.jArray(items.stream() .map(Extended::asJson) .collect(Collectors.toList()))); } if (!queries.isEmpty()) { map.put("queries", Json.jArray(queries.stream() .map(Extended::asJson) .collect(Collectors.toList()))); } template.forEach(value -> map.put("template", value.asJson())); error.forEach(value -> map.put("error", value.asJson())); Collection coll = new Collection(Json.jObject(map)); coll.validate(); return coll; } public Version getVersion() { return Version.ONE; } public Option<URI> getHref() { return delegate.getAsString("href").map(URI::create); } public List<Link> getLinks() { return Link.fromArray(delegate.getAsArrayOrEmpty("links")); } public List<Item> getItems() { return Item.fromArray(delegate.getAsArrayOrEmpty("items")); } public List<Query> getQueries() { return Query.fromArray(delegate.getAsArrayOrEmpty("queries")); } public boolean hasTemplate() { return delegate.containsKey("template"); } public Option<Template> getTemplate() { return delegate.getAsObject("template").map(Template::new); } public boolean hasError() { return delegate.containsKey("error"); } public Option<Error> getError() { return delegate.getAsObject("error").map(Error::new); } public Option<Link> linkByName(final String name) { return findLink(link -> of(name).equals(link.getName())); } public Option<Link> linkByRelAndName(final String rel, final String name) { return findLink(link -> rel.equals(link.getRel()) && of(name).equals(link.getName())); } public Option<Link> linkByRel(final String rel) { return findLink(link -> rel.equals(link.getRel())); } public List<Link> linksByRel(final String rel) { return filterLinks(link -> rel.equals(link.getRel())); } public Option<Query> queryByRel(final String rel) { return findQuery(query -> rel.equals(query.getRel())); } public Option<Query> queryByName(final String name) { return findQuery(query -> of(name).equals(query.getName())); } public Option<Query> queryByRelAndName(final String rel, final String name) { return findQuery(query -> rel.equals(query.getRel()) && of(name).equals(query.getName())); } public Option<Link> findLink(Predicate<Link> predicate) { return Option.ofOptional(getLinks().stream().filter(predicate).findFirst()); } public List<Link> filterLinks(Predicate<Link> predicate) { return getLinks().stream().filter(predicate).collect(Collectors.<Link>toList()); } public Option<Item> findItem(Predicate<Item> predicate) { return Option.ofOptional(getItems().stream().filter(predicate).findFirst()); } public List<Item> filterItems(Predicate<Item> predicate) { return getItems().stream().filter(predicate).collect(Collectors.<Item>toList()); } public List<Item> filterItemsByProfile(final URI profile) { return filterItems(item -> item.linkByRel("profile").map(link -> link.getHref().equals(profile)).getOrElse(true)); } public Option<Item> getFirstItem() { return Option.ofOptional(getItems().stream().findFirst()); } public Option<Query> findQuery(Predicate<Query> predicate) { return Option.ofOptional(getQueries().stream().filter(predicate).findFirst()); } public List<Query> filterQueries(Predicate<Query> predicate) { return getQueries().stream().filter(predicate).collect(Collectors.<Query>toList()); } public Builder toBuilder() { Builder builder = new Builder(getHref()); builder.addItems(getItems()); builder.addLinks(getLinks()); builder.addQueries(getQueries()); getTemplate().forEach(builder::withTemplate); getError().forEach(builder::withError); return builder; } public void writeTo(OutputStream stream) throws IOException { writeTo(new OutputStreamWriter(stream, Charset.forName("UTF-8"))); } public void writeTo(Writer writer) throws IOException { JsonSerializer.write( Json.jObject("collection", asJson()), writer ); } @Override public String toString() { return Json.jObject("collection", asJson()).nospaces(); } public void validate() { getLinks().forEach(Link::validate); getItems().forEach(Item::validate); getQueries().forEach(Query::validate); getTemplate().forEach(Template::validate); getError().forEach(Error::validate); } public static Builder builder(URI href) { return new Builder(of(href)); } public static Builder builder() { return new Builder(); } public static class Builder { private Option<URI> href; private final List<Item> itemBuilder = new ArrayList<Item>(); private final List<Link> linkBuilder = new ArrayList<Link>(); private final List<Query> queryBuilder = new ArrayList<Query>(); private Option<Template> template = Option.none(); private Option<Error> error = Option.none(); public Builder() { this(Option.none()); } public Builder(URI href) { this(of(href)); } public Builder(Option<URI> href) { this.href = href; } public Builder withHref(URI href) { this.href = of(href); return this; } public Builder addItem(Item item) { itemBuilder.add(item); return this; } public Builder addItems(Iterable<Item> items) { addToList(items, itemBuilder); return this; } public Builder addQuery(Query query) { queryBuilder.add(query); return this; } public Builder addQueries(Iterable<Query> queries) { addToList(queries, queryBuilder); return this; } public Builder addLink(Link link) { linkBuilder.add(link); return this; } public Builder addLinks(Iterable<Link> links) { addToList(links, linkBuilder); return this; } public Builder withError(Error error) { this.error = of(error); return this; } public Builder withTemplate(Template template) { this.template = of(template); return this; } private <A> void addToList(Iterable<A> iterable, List<A> list) { StreamSupport.stream(iterable.spliterator(), false).forEach(list::add); } public Collection build() { return Collection.create(href, linkBuilder, itemBuilder, queryBuilder, template, error); } } }