001package io.jstach.jstachio.spi;
002
003import java.util.ArrayList;
004import java.util.List;
005import java.util.ServiceLoader;
006
007import io.jstach.jstachio.JStachio;
008
009/**
010 * Creates JStachios mainly with the {@link ServiceLoader} or a {@link Builder}.
011 *
012 * @author agentgt
013 *
014 */
015public final class JStachioFactory {
016
017        /**
018         * @hidden
019         */
020        private JStachioFactory() {
021
022        }
023
024        /**
025         * Provides a singleton JStachio resolved by the {@link ServiceLoader}
026         * @return service loader based jstachio.
027         */
028        public static JStachio defaultJStachio() {
029                return Holder.INSTANCE;
030        }
031
032        /**
033         * A <em>mutable</em> builder to create {@link JStachio} from
034         * {@link JStachioExtension}s.
035         * @return empty builder
036         */
037        public static Builder builder() {
038                return new Builder();
039        }
040
041        private static class Holder extends AbstractJStachio {
042
043                private static Holder INSTANCE = Holder.of();
044
045                private final JStachioExtensions extensions;
046
047                public Holder(JStachioExtensions extensions) {
048                        this.extensions = extensions;
049                }
050
051                private static Holder of() {
052                        Iterable<JStachioExtension> it = ServiceLoader.load(JStachioExtension.class);
053                        return new Holder(JStachioExtensions.of(it));
054                }
055
056                @Override
057                public JStachioExtensions extensions() {
058                        return this.extensions;
059                }
060
061        }
062
063        /**
064         * Builder for creating jstachios.
065         *
066         * @author agent
067         *
068         */
069        public static class Builder {
070
071                private List<JStachioExtension> extensions = new ArrayList<>();
072
073                /**
074                 * Constructor is hidden for now.
075                 */
076                private Builder() {
077                }
078
079                /**
080                 * Adds an extension
081                 * @param extension not null
082                 * @return this
083                 */
084                public Builder add(JStachioExtension extension) {
085                        extensions.add(extension);
086                        return this;
087                }
088
089                /**
090                 * Add extensions.
091                 *
092                 * Useful for adding ServiceLoader results: <pre>
093                 * <code class="language-java">
094                 * builder.add(ServiceLoader.load(JStachioExtension.class));
095                 * </code> </pre>
096                 * @param extensions not null
097                 * @return this
098                 */
099                public Builder add(Iterable<JStachioExtension> extensions) {
100                        extensions.forEach(this.extensions::add);
101                        return this;
102                }
103
104                /**
105                 * Builds a JStachio by coalescing the extensions.
106                 *
107                 * @apiNote See {@link JStachioExtensions} for logic on how the extensions are
108                 * consolidated.
109                 * @return resolved JStachio
110                 */
111                public JStachio build() {
112                        return new DefaultJStachio(JStachioExtensions.of(extensions));
113                }
114
115                /**
116                 * Current mutable list of extensions.
117                 * @return mutable list of extensions
118                 */
119                public List<JStachioExtension> extensions() {
120                        return extensions;
121                }
122
123        }
124
125}