Created
December 11, 2018 12:20
-
-
Save mp911de/92bbec63f0bbfc98362e2d786c2fb1e6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Copyright 2018 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 io.r2dbc.spi.plugin; | |
| import io.r2dbc.spi.ConnectionFactory; | |
| import java.security.AccessController; | |
| import java.security.PrivilegedAction; | |
| import java.util.ServiceLoader; | |
| /** | |
| * Provides access to R2DBC {@link ConnectionFactoryProvider connection factories} for programmatic lookup. | |
| * R2DBC driver can expose their functionality as plugin by using Java's {@link ServiceLoader} mechanism with registering a {@link ConnectionFactoryProvider}.<p> | |
| * This class accepts {@link ConnectionFactoryOptions} to determine a {@link ConnectionFactoryProvider} and to create a {@link ConnectionFactory}. | |
| * | |
| * @author Mark Paluch | |
| * @see ServiceLoader | |
| * @see ConnectionFactoryProvider | |
| */ | |
| public abstract class ConnectionFactories { | |
| private ConnectionFactories() { | |
| } | |
| /** | |
| * Creates a {@link ConnectionFactory} using registered R2DBC plugins through Java's {@link ServiceLoader} mechanism. | |
| * | |
| * @param connectionFactoryOptions | |
| * @return | |
| * @throws IllegalArgumentException if there is no {@link ConnectionFactoryProvider} can create a {@link ConnectionFactory} from {@link ConnectionFactoryOptions}. | |
| */ | |
| public ConnectionFactory createConnectionFactory(ConnectionFactoryOptions connectionFactoryOptions) { | |
| ServiceLoader<ConnectionFactoryProvider> providers = loadService(ConnectionFactoryProvider.class, ConnectionFactories.class.getClassLoader()); | |
| for (ConnectionFactoryProvider provider : providers) { | |
| if (provider.supports(connectionFactoryOptions)) { | |
| return provider.createConnectionFactory(); | |
| } | |
| } | |
| throw new IllegalArgumentException(String.format("No suitable ConnectionFactoryProvider found for %s", connectionFactoryOptions)); | |
| } | |
| /** | |
| * Returns whether a {@link ConnectionFactory} using registered R2DBC plugins through Java's {@link ServiceLoader} mechanism supports the configuration supplied through | |
| * {@link ConnectionFactoryOptions}. | |
| * | |
| * @param connectionFactoryOptions | |
| * @return | |
| */ | |
| public boolean supports(ConnectionFactoryOptions connectionFactoryOptions) { | |
| ServiceLoader<ConnectionFactoryProvider> providers = loadService(ConnectionFactoryProvider.class, ConnectionFactories.class.getClassLoader()); | |
| for (ConnectionFactoryProvider provider : providers) { | |
| if (provider.supports(connectionFactoryOptions)) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| private static <T> ServiceLoader<T> loadService(Class<T> service, ClassLoader classLoader) { | |
| return AccessController.doPrivileged( | |
| (PrivilegedAction<ServiceLoader<T>>) () -> ServiceLoader.load(service, classLoader) | |
| ); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Copyright 2018 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 io.r2dbc.spi.plugin; | |
| import io.r2dbc.spi.Nullable; | |
| import java.time.Duration; | |
| import java.util.Collections; | |
| import java.util.HashMap; | |
| import java.util.LinkedHashMap; | |
| import java.util.Map; | |
| /** | |
| * @author Mark Paluch | |
| */ | |
| public class ConnectionFactoryOptions { | |
| /** | |
| * Port number. | |
| */ | |
| public static final Option<Integer> PORT = Option.valueOf("port"); | |
| /** | |
| * Endpoint host name. | |
| */ | |
| public static final Option<String> HOST = Option.valueOf("host"); | |
| /** | |
| * User for login. | |
| */ | |
| public static final Option<String> USER = Option.valueOf("user"); | |
| /** | |
| * Password for login. | |
| */ | |
| public static final Option<CharSequence> PASSWORD = Option.valueOf("password"); | |
| /** | |
| * Initial database name. | |
| */ | |
| public static final Option<String> DATABASE = Option.valueOf("database"); | |
| /** | |
| * Driver name. | |
| */ | |
| public static final Option<String> DRIVER = Option.valueOf("driver"); | |
| /** | |
| * Driver protocol name. Typically represented as {@code tcp} or a database vendor-specific protocol string. | |
| */ | |
| public static final Option<String> PROTOCOL = Option.valueOf("protocol"); | |
| /** | |
| * Configures whether to support SSL. | |
| */ | |
| public static final Option<Boolean> SSL = Option.valueOf("ssl"); | |
| /** | |
| * Connection timeout. | |
| */ | |
| public static final Option<Duration> CONNECT_TIMEOUT = Option.valueOf("connectTimeout"); | |
| private final Map<Option<?>, Object> options; | |
| private ConnectionFactoryOptions(Map<Option<?>, Object> options) { | |
| this.options = options; | |
| } | |
| public static Builder builder() { | |
| return new Builder(); | |
| } | |
| @Nullable | |
| @SuppressWarnings("unchecked") | |
| public <T> T getValue(Option<T> option) { | |
| return (T) this.options.get(option); | |
| } | |
| @Nullable | |
| public <T> T getRequiredValue(Option<T> option) { | |
| T value = getValue(option); | |
| if (value != null) { | |
| return value; | |
| } | |
| throw new IllegalStateException("Value for option " + option + " is null!"); | |
| } | |
| @Override | |
| public String toString() { | |
| StringBuffer sb = new StringBuffer(); | |
| sb.append(getClass().getSimpleName()).append(' ').append(this.options); | |
| return sb.toString(); | |
| } | |
| public static class Builder { | |
| private final Map<Option<?>, Object> options = new HashMap<>(); | |
| private Builder() { | |
| } | |
| public <T> Builder option(Option<T> option, T value) { | |
| this.options.put(option, value); | |
| return this; | |
| } | |
| public ConnectionFactoryOptions build() { | |
| return new ConnectionFactoryOptions(Collections.unmodifiableMap(new LinkedHashMap<>(options))); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Copyright 2018 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 io.r2dbc.spi.plugin; | |
| import io.r2dbc.spi.ConnectionFactory; | |
| /** | |
| * @author Mark Paluch | |
| */ | |
| public interface ConnectionFactoryProvider { | |
| boolean supports(ConnectionFactoryOptions options); | |
| ConnectionFactory createConnectionFactory(); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Copyright 2018 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 io.r2dbc.spi.plugin; | |
| import java.util.concurrent.ConcurrentHashMap; | |
| import java.util.concurrent.ConcurrentMap; | |
| import java.util.concurrent.atomic.AtomicInteger; | |
| /** | |
| * A pool of {@link Option}s. | |
| * | |
| * @param <T> the type of the {@link Option}. | |
| */ | |
| abstract class ConstantPool<T extends Option<?>> { | |
| private final ConcurrentMap<String, T> constants = new ConcurrentHashMap<>(); | |
| private final AtomicInteger nextId = new AtomicInteger(1); | |
| /** | |
| * Returns the {@link Option} which is assigned to the specified {@code name}. | |
| * If there's no such {@link Option}, a new one will be created and returned. | |
| * Once created, the subsequent calls with the same {@code name} will always return the previously created one | |
| * (i.e. singleton.) | |
| * | |
| * @param name the name of the {@link Option} | |
| */ | |
| public T valueOf(String name) { | |
| checkNotNullAndNotEmpty(name); | |
| return getOrCreate(name); | |
| } | |
| /** | |
| * Get existing constant by name or creates new one if not exists. Threadsafe | |
| * | |
| * @param name the name of the {@link Constant} | |
| */ | |
| private T getOrCreate(String name) { | |
| T constant = constants.get(name); | |
| if (constant == null) { | |
| T tempConstant = newConstant(nextId(), name); | |
| constant = constants.putIfAbsent(name, tempConstant); | |
| if (constant == null) { | |
| return tempConstant; | |
| } | |
| } | |
| return constant; | |
| } | |
| private static String checkNotNullAndNotEmpty(String name) { | |
| if (name == null || name.isEmpty()) { | |
| throw new IllegalArgumentException("empty name"); | |
| } | |
| return name; | |
| } | |
| protected abstract T newConstant(int id, String name); | |
| private int nextId() { | |
| return nextId.getAndIncrement(); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Copyright 2018 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 io.r2dbc.spi.plugin; | |
| /** | |
| * @author Mark Paluch | |
| */ | |
| public class Option<T> { | |
| private static final ConstantPool<Option<Object>> pool = new ConstantPool<Option<Object>>() { | |
| @Override | |
| protected Option<Object> newConstant(int id, String name) { | |
| return new Option<Object>(id, name); | |
| } | |
| }; | |
| private final int id; | |
| private final String name; | |
| private Option(int id, String name) { | |
| this.id = id; | |
| this.name = name; | |
| } | |
| /** | |
| * Returns the {@link Option} of the specified name. | |
| */ | |
| @SuppressWarnings("unchecked") | |
| public static <T> Option<T> valueOf(String name) { | |
| return (Option<T>) pool.valueOf(name); | |
| } | |
| public String name() { | |
| return name; | |
| } | |
| @Override | |
| public String toString() { | |
| return name(); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment