All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.hal4j.resources.ResourceBuilderSupport Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
package com.github.hal4j.resources;

import com.github.hal4j.resources.curie.CurieResolver;
import com.github.hal4j.uritemplate.URIBuilder;
import com.github.hal4j.uritemplate.URITemplate;

import java.net.URI;
import java.util.*;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.github.hal4j.resources.curie.CurieResolver.REL_CURIES;
import static com.github.hal4j.resources.HALLink.REL_SELF;
import static java.util.Arrays.asList;

public abstract class ResourceBuilderSupport> {

    private final CurieResolver resolver;

    protected Map> _links;

    protected Map> _embedded;

    protected Set resolvedNamespaces;

    private BindingContext context;

    protected ResourceBuilderSupport(CurieResolver resolver) {
        this.resolver = resolver;
    }

    protected abstract B _this();

    public final R asResource() {
        return build();
    }

    public B in(BindingContext ctx) {
        this.context = ctx;
        return _this();
    }

    public BindingContext context() {
        return context;
    }

    protected Map> links() {
        if (_links == null) {
            _links = new HashMap<>();
        }
        return _links;
    }

    protected Map> embedded() {
        if (_embedded == null) {
            _embedded = new HashMap<>();
        }
        return _embedded;
    }

    public Linker linkSelf() {
        return new Linker(URI.create(REL_SELF));
    }

    public B to(String uri) {
        return linkSelf().to(uri);
    }

    public B to(URIBuilder builder) {
        return linkSelf().to(builder);
    }

    public Linker link(URI rel) {
        return new Linker(rel);
    }

    public Linker link(String rel) {
        return new Linker(URI.create(rel));
    }

    private List mutableLinks(URI rel) {
        resolve(rel);
        return this.links().computeIfAbsent(rel.toString(), any -> new ArrayList<>());
    }

    public B embed(String rel, Object... objects) {
        return embed(URI.create(rel), objects);
    }

    public B embed(URI rel, Object... objects) {
        return embedAll(rel, asList(objects));
    }

    public B embedAll(String rel, Collection objects) {
        return embedAll(URI.create(rel), objects);
    }

    public B embedAll(URI rel, Collection objects) {
        resolve(rel);
        List existing = this.embedded().computeIfAbsent(rel.toString(), any -> new ArrayList<>());
        existing.addAll(objects);
        return _this();
    }

    private void resolve(URI uri) {
        if (uri == null) {
            throw new NullPointerException("uri");
        }
        String rel = uri.toString();
        int idx = rel.indexOf(':');
        if (idx < 0) return;
        if (idx == 1) {
            throw new IllegalArgumentException("Invalid relation: \"" + rel + "\"");
        }
        String ns = rel.substring(0, idx);
        if (resolvedNamespaces != null) {
            if (resolvedNamespaces.contains(ns)) return;
        } else {
            resolvedNamespaces = new HashSet<>();
        }
        resolvedNamespaces.add(ns);
        URITemplate resolved = resolver.resolve(ns);
        if (resolved != null) {
            HALLink link = HALLinkBuilder.uri(resolved.toString()).name(ns).build();
            this.link(REL_CURIES).to(link);
        }
    }

    public abstract R build();

    public B merge(ResourceSupport resource, MergeStrategy strategy) {
        resource.links().all().forEach((rel, list) -> {
            List links = list.stream().map(strategy::map).collect(Collectors.toList());
            this.links().put(rel, links);
        });
        resource.embedded().all().forEach((rel, list) -> {
            List objects = list.stream()
                    .map(object -> strategy.map(object, resource.context()))
                    .collect(Collectors.toList());
            this.embedded().put(rel, objects);
        });
        return _this();
    }

    public class Linker {

        private final URI rel;

        private boolean accepted = true;

        public Linker(URI rel) {
            this.rel = rel;
        }

        public Linker when(boolean condition) {
            this.accepted = condition;
            return this;
        }

        public Linker when(Predicate voter) {
            this.accepted = voter.test(rel);
            return this;
        }

        public Linker when(Supplier condition) {
            this.accepted = condition.get();
            return this;
        }

        public B to(HALLink link) {
            if (accepted) {
                List relLinks = mutableLinks(rel);
                relLinks.add(link);
            }
            return _this();
        }

        public B to(HALLinkBuilder linkBuilder) {
            if (accepted) {
                List relLinks = mutableLinks(rel);
                relLinks.add(linkBuilder.build());
            }
            return _this();
        }

        public B to(String uri) {
            return to(HALLinkBuilder.uri(uri));
        }

        public B to(URI href) {
            if (href == null) {
                throw new NullPointerException("href");
            }
            return to(href.toString());
        }

        public B to(URITemplate href) {
            if (href == null) {
                throw new NullPointerException("href");
            }
            return to(href.toString());
        }

        public B to(URIBuilder href) {
            if (href == null) {
                throw new NullPointerException("href");
            }
            return to(href.toString());
        }

        public B toAll(HALLinkBuilder... builders) {
            if (accepted) {
                List relLinks = mutableLinks(rel);
                Stream.of(builders).map(HALLinkBuilder::build).forEach(relLinks::add);
            }
            return _this();
        }

        public B toAll(Collection links) {
            if (accepted) {
                List relLinks = mutableLinks(rel);
                relLinks.addAll(links);
            }
            return _this();
        }

    }

}