diff --git a/agent/src/main/java/io/atomix/agent/AtomixAgent.java b/agent/src/main/java/io/atomix/agent/AtomixAgent.java index 7317029fae..e26df4104c 100644 --- a/agent/src/main/java/io/atomix/agent/AtomixAgent.java +++ b/agent/src/main/java/io/atomix/agent/AtomixAgent.java @@ -21,7 +21,6 @@ import io.atomix.core.AtomixConfig; import io.atomix.rest.ManagedRestService; import io.atomix.rest.RestService; -import io.atomix.utils.config.Configs; import io.atomix.utils.net.Address; import io.atomix.utils.net.MalformedAddressException; import net.sourceforge.argparse4j.ArgumentParsers; @@ -34,7 +33,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; import java.util.List; /** @@ -105,7 +103,7 @@ public static void main(String[] args) throws Exception { // If a configuration was provided, merge the configuration's member information with the provided command line arguments. AtomixConfig config; if (configString != null) { - config = loadConfig(configString); + config = Atomix.config(configString); } else { config = new AtomixConfig(); } @@ -182,18 +180,6 @@ public static void main(String[] args) throws Exception { } } - /** - * Loads a configuration from the given file. - */ - private static AtomixConfig loadConfig(String config) { - File configFile = new File(config); - if (configFile.exists()) { - return Configs.load(configFile, AtomixConfig.class, Thread.currentThread().getContextClassLoader()); - } else { - return Configs.load(config, AtomixConfig.class, Thread.currentThread().getContextClassLoader()); - } - } - static MemberId parseMemberId(String address) { int endIndex = address.indexOf('@'); if (endIndex > 0) { diff --git a/cluster/src/main/java/io/atomix/cluster/AtomixCluster.java b/cluster/src/main/java/io/atomix/cluster/AtomixCluster.java index ec50609d62..8ff14665ed 100644 --- a/cluster/src/main/java/io/atomix/cluster/AtomixCluster.java +++ b/cluster/src/main/java/io/atomix/cluster/AtomixCluster.java @@ -32,7 +32,7 @@ import io.atomix.utils.concurrent.Futures; import io.atomix.utils.concurrent.SingleThreadContext; import io.atomix.utils.concurrent.ThreadContext; -import io.atomix.utils.config.Configs; +import io.atomix.utils.config.ConfigMapper; import io.atomix.utils.net.Address; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -233,7 +233,7 @@ public String toString() { * Loads a configuration from the given file. */ private static ClusterConfig loadConfig(File config, ClassLoader classLoader) { - return Configs.load(config, ClusterConfig.class, classLoader); + return new ConfigMapper(classLoader).loadResources(ClusterConfig.class, config.getAbsolutePath()); } /** diff --git a/config/pom.xml b/config/pom.xml deleted file mode 100644 index da75984609..0000000000 --- a/config/pom.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - 4.0.0 - - - io.atomix - atomix-parent - 2.1.0-SNAPSHOT - - - bundle - atomix-config - Atomix Config - - - - io.atomix - atomix - ${project.version} - - - io.atomix - atomix-raft - ${project.version} - test - - - io.atomix - atomix-primary-backup - ${project.version} - test - - - com.fasterxml.jackson.core - jackson-core - - - com.fasterxml.jackson.core - jackson-databind - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - - - commons-io - commons-io - 2.6 - test - - - - - - - org.apache.felix - maven-bundle-plugin - true - - - - io.atomix.core.config.* - - - !sun.nio.ch,!sun.misc,* - - - - - - - diff --git a/config/src/main/java/io/atomix/core/config/jackson/JacksonConfigProvider.java b/config/src/main/java/io/atomix/core/config/jackson/JacksonConfigProvider.java deleted file mode 100644 index af594b0d9c..0000000000 --- a/config/src/main/java/io/atomix/core/config/jackson/JacksonConfigProvider.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2018-present Open Networking Foundation - * - * 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.atomix.core.config.jackson; - -import com.fasterxml.jackson.annotation.JsonAutoDetect; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.core.io.IOContext; -import com.fasterxml.jackson.core.util.BufferRecycler; -import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import com.fasterxml.jackson.dataformat.yaml.YAMLParser; -import io.atomix.core.config.jackson.impl.ConfigPropertyNamingStrategy; -import io.atomix.core.config.jackson.impl.PartitionGroupDeserializer; -import io.atomix.core.config.jackson.impl.PrimitiveConfigDeserializer; -import io.atomix.core.config.jackson.impl.PrimitiveProtocolDeserializer; -import io.atomix.core.config.jackson.impl.ProfileDeserializer; -import io.atomix.core.profile.Profile; -import io.atomix.primitive.PrimitiveConfig; -import io.atomix.primitive.partition.PartitionGroupConfig; -import io.atomix.primitive.protocol.PrimitiveProtocolConfig; -import io.atomix.utils.config.Config; -import io.atomix.utils.config.ConfigProvider; -import io.atomix.utils.config.ConfigurationException; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.util.function.Function; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Jackson configuration provider. - */ -public class JacksonConfigProvider implements ConfigProvider { - private static final String YAML_EXT = ".yaml"; - private static final String YML_EXT = ".yml"; - private static final String JSON_EXT = ".json"; - - @Override - public boolean isConfigFile(File file) { - return isYaml(file) || isJson(file); - } - - private boolean isYaml(File file) { - return file.getName().endsWith(YAML_EXT) || file.getName().endsWith(YML_EXT); - } - - private boolean isJson(File file) { - return file.getName().endsWith(JSON_EXT); - } - - private boolean isJson(String config) { - return config.trim().startsWith("{") && config.trim().endsWith("}"); - } - - @Override - public C load(String config, Class type) { - if (isJson(config)) { - return loadJson(config, type); - } else { - return loadYaml(config, type); - } - } - - @Override - public C load(File file, Class type) { - if (isYaml(file)) { - return loadYaml(file, type); - } else if (isJson(file)) { - return loadJson(file, type); - } else { - throw new ConfigurationException("Unknown file type: " + file.getName()); - } - } - - private C loadYaml(File file, Class type) { - ObjectMapper mapper = new ObjectMapper(new InterpolatingYamlFactory()); - setupObjectMapper(mapper); - try { - return mapper.readValue(file, type); - } catch (IOException e) { - throw new ConfigurationException("Failed to parse YAML file", e); - } - } - - private C loadJson(File file, Class type) { - ObjectMapper mapper = new ObjectMapper(); - setupObjectMapper(mapper); - try { - return mapper.readValue(file, type); - } catch (IOException e) { - throw new ConfigurationException("Failed to parse JSON file", e); - } - } - - private C loadYaml(String config, Class type) { - ObjectMapper mapper = new ObjectMapper(new InterpolatingYamlFactory()); - setupObjectMapper(mapper); - try { - return mapper.readValue(config, type); - } catch (IOException e) { - throw new ConfigurationException("Failed to parse YAML file", e); - } - } - - private C loadJson(String config, Class type) { - ObjectMapper mapper = new ObjectMapper(); - setupObjectMapper(mapper); - try { - return mapper.readValue(config, type); - } catch (IOException e) { - throw new ConfigurationException("Failed to parse JSON file", e); - } - } - - private void setupObjectMapper(ObjectMapper mapper) { - mapper.setPropertyNamingStrategy(new ConfigPropertyNamingStrategy()); - mapper.setVisibility(mapper.getVisibilityChecker() - .withFieldVisibility(JsonAutoDetect.Visibility.ANY) - .withGetterVisibility(JsonAutoDetect.Visibility.ANY) - .withSetterVisibility(JsonAutoDetect.Visibility.ANY)); - mapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS); - mapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES); - mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); - mapper.configure(JsonParser.Feature.ALLOW_YAML_COMMENTS, true); - - SimpleModule module = new SimpleModule("PolymorphicTypes"); - module.addDeserializer(PartitionGroupConfig.class, new PartitionGroupDeserializer(getClass().getClassLoader())); - module.addDeserializer(PrimitiveProtocolConfig.class, new PrimitiveProtocolDeserializer(getClass().getClassLoader())); - module.addDeserializer(PrimitiveConfig.class, new PrimitiveConfigDeserializer(getClass().getClassLoader())); - module.addDeserializer(Profile.class, new ProfileDeserializer()); - mapper.registerModule(module); - } - - private static class InterpolatingYamlFactory extends YAMLFactory { - @Override - protected YAMLParser _createParser(InputStream in, IOContext ctxt) throws IOException { - return new InterpolatingYamlParser(ctxt, _getBufferRecycler(), _parserFeatures, _yamlParserFeatures, _objectCodec, _createReader(in, null, ctxt)); - } - - @Override - protected YAMLParser _createParser(Reader r, IOContext ctxt) throws IOException { - return new InterpolatingYamlParser(ctxt, _getBufferRecycler(), _parserFeatures, _yamlParserFeatures, _objectCodec, r); - } - } - - private static class InterpolatingYamlParser extends YAMLParser { - private final Pattern sysPattern = Pattern.compile("\\$\\{sys:([A-Za-z0-9-_.]+)\\}"); - private final Pattern envPattern = Pattern.compile("\\$\\{env:([A-Za-z0-9_]+)\\}"); - - InterpolatingYamlParser(IOContext ctxt, BufferRecycler br, int parserFeatures, int formatFeatures, ObjectCodec codec, Reader reader) { - super(ctxt, br, parserFeatures, formatFeatures, codec, reader); - } - - @Override - public String getText() throws IOException { - String value = super.getText(); - return value != null ? interpolateString(value) : null; - } - - @Override - public String getValueAsString() throws IOException { - return getValueAsString(null); - } - - @Override - public String getValueAsString(String defaultValue) throws IOException { - String value = super.getValueAsString(defaultValue); - return value != null ? interpolateString(value) : null; - } - - private String interpolateString(String value) { - value = interpolate(value, sysPattern, name -> System.getProperty(name)); - value = interpolate(value, envPattern, name -> System.getenv(name)); - return value; - } - - private String interpolate(String value, Pattern pattern, Function supplier) { - if (value == null) { - return null; - } - - Matcher matcher = pattern.matcher(value); - while (matcher.find()) { - String name = matcher.group(1); - String replace = supplier.apply(name); - String group = matcher.group(0); - if (group.equals(value)) { - return replace; - } - if (replace == null) { - replace = ""; - } - Pattern subPattern = Pattern.compile(Pattern.quote(group)); - value = subPattern.matcher(value).replaceAll(replace); - } - return value; - } - } -} diff --git a/config/src/main/resources/META-INF/services/io.atomix.utils.config.ConfigProvider b/config/src/main/resources/META-INF/services/io.atomix.utils.config.ConfigProvider deleted file mode 100644 index c4727a6309..0000000000 --- a/config/src/main/resources/META-INF/services/io.atomix.utils.config.ConfigProvider +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright 2018-present Open Networking Foundation -# -# 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. -# -io.atomix.core.config.jackson.JacksonConfigProvider \ No newline at end of file diff --git a/config/src/test/java/io/atomix/core/config/jackson/JacksonConfigProviderTest.java b/config/src/test/java/io/atomix/core/config/jackson/JacksonConfigProviderTest.java deleted file mode 100644 index d494a7e1e1..0000000000 --- a/config/src/test/java/io/atomix/core/config/jackson/JacksonConfigProviderTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2018-present Open Networking Foundation - * - * 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.atomix.core.config.jackson; - -import io.atomix.core.AtomixConfig; -import io.atomix.utils.config.ConfigProvider; -import org.apache.commons.io.IOUtils; -import org.junit.Ignore; -import org.junit.Test; - -import java.io.File; -import java.nio.charset.StandardCharsets; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -/** - * Jackson configuration provider test. - */ -public class JacksonConfigProviderTest { - @Test - public void testJson() throws Exception { - ConfigProvider provider = new JacksonConfigProvider(); - File file = new File(getClass().getClassLoader().getResource("config.json").getFile()); - assertTrue(provider.isConfigFile(file)); - AtomixConfig config = provider.load(file, AtomixConfig.class); - assertEquals("test", config.getClusterConfig().getName()); - assertEquals(1, config.getPrimitives().get("foo").getSerializerConfig().getTypes().size()); - } - - @Test - public void testYaml() throws Exception { - ConfigProvider provider = new JacksonConfigProvider(); - File file = new File(getClass().getClassLoader().getResource("config.yaml").getFile()); - assertTrue(provider.isConfigFile(file)); - AtomixConfig config = provider.load(file, AtomixConfig.class); - assertEquals("test", config.getClusterConfig().getName()); - assertEquals(1, config.getPrimitives().get("foo").getSerializerConfig().getTypes().size()); - } - - @Test - @Ignore - public void testEnvFile() throws Exception { - ConfigProvider provider = new JacksonConfigProvider(); - File file = new File(getClass().getClassLoader().getResource("env.yaml").getFile()); - assertTrue(provider.isConfigFile(file)); - AtomixConfig config = provider.load(file, AtomixConfig.class); - assertEquals("test", config.getPartitionGroups().values().iterator().next().getName()); - } - - @Test - @Ignore - public void testEnvString() throws Exception { - ConfigProvider provider = new JacksonConfigProvider(); - File file = new File(getClass().getClassLoader().getResource("env.yaml").getFile()); - AtomixConfig config = provider.load(IOUtils.toString(file.toURI(), StandardCharsets.UTF_8), AtomixConfig.class); - assertEquals("test", config.getPartitionGroups().values().iterator().next().getName()); - assertEquals(3, config.getPartitionGroups().values().iterator().next().getPartitions()); - } - - @Test - @Ignore - public void testSystemPropertyFile() throws Exception { - ConfigProvider provider = new JacksonConfigProvider(); - File file = new File(getClass().getClassLoader().getResource("sys.yaml").getFile()); - assertTrue(provider.isConfigFile(file)); - AtomixConfig config = provider.load(file, AtomixConfig.class); - assertEquals("test", config.getPartitionGroups().values().iterator().next().getName()); - } - - @Test - @Ignore - public void testSystemPropertyString() throws Exception { - ConfigProvider provider = new JacksonConfigProvider(); - File file = new File(getClass().getClassLoader().getResource("sys.yaml").getFile()); - assertTrue(provider.isConfigFile(file)); - AtomixConfig config = provider.load(IOUtils.toString(file.toURI(), StandardCharsets.UTF_8), AtomixConfig.class); - assertEquals("test", config.getPartitionGroups().values().iterator().next().getName()); - } -} diff --git a/config/src/test/resources/config.json b/config/src/test/resources/config.json deleted file mode 100644 index 557b6a24d1..0000000000 --- a/config/src/test/resources/config.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "cluster": { - "name": "test" - }, - "primitive-types": [ - "io.atomix.core.map.ConsistentMapType" - ], - "primitives": { - "foo": { - "type": "consistent-map", - "serializer": { - "types": [ - { - "type": "io.atomix.cluster.MemberId" - } - ] - } - } - } -} \ No newline at end of file diff --git a/config/src/test/resources/config.yaml b/config/src/test/resources/config.yaml deleted file mode 100644 index 5204f9b0b2..0000000000 --- a/config/src/test/resources/config.yaml +++ /dev/null @@ -1,13 +0,0 @@ -cluster: - name: test -primitive-types: - - io.atomix.core.map.ConsistentMapType -partition-groups: - foo: - type: primary-backup -primitives: - foo: - type: consistent-map - serializer: - types: - - type: io.atomix.cluster.MemberId \ No newline at end of file diff --git a/config/src/test/resources/env.yaml b/config/src/test/resources/env.yaml deleted file mode 100644 index c9def2a689..0000000000 --- a/config/src/test/resources/env.yaml +++ /dev/null @@ -1,8 +0,0 @@ -cluster: - name: test -primitive-types: - - io.atomix.core.map.ConsistentMapType -partition-groups: - - name: ${env:GROUP_NAME} - type: raft - partitions: ${env:NUM_PARTITIONS} \ No newline at end of file diff --git a/config/src/test/resources/sys.yaml b/config/src/test/resources/sys.yaml deleted file mode 100644 index a155948ae2..0000000000 --- a/config/src/test/resources/sys.yaml +++ /dev/null @@ -1,7 +0,0 @@ -cluster: - name: test -primitive-types: - - io.atomix.core.map.ConsistentMapType -partition-groups: - - name: ${sys:group.name} - type: raft \ No newline at end of file diff --git a/core/pom.xml b/core/pom.xml index ad2828b4fc..f6136f4377 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -54,6 +54,11 @@ atomix-utils ${project.version} + + com.typesafe + config + ${config.version} + javax.ws.rs javax.ws.rs-api diff --git a/core/src/main/java/io/atomix/core/Atomix.java b/core/src/main/java/io/atomix/core/Atomix.java index f3fcf4e175..ea0a0f9eb6 100644 --- a/core/src/main/java/io/atomix/core/Atomix.java +++ b/core/src/main/java/io/atomix/core/Atomix.java @@ -15,6 +15,7 @@ */ package io.atomix.core; +import com.google.common.collect.Streams; import io.atomix.cluster.AtomixCluster; import io.atomix.cluster.ClusterMembershipService; import io.atomix.cluster.Member; @@ -31,28 +32,34 @@ import io.atomix.core.multimap.ConsistentMultimap; import io.atomix.core.profile.Profile; import io.atomix.core.queue.WorkQueue; +import io.atomix.core.registry.RegistryService; +import io.atomix.core.registry.impl.DefaultRegistryService; import io.atomix.core.semaphore.DistributedSemaphore; import io.atomix.core.set.DistributedSet; import io.atomix.core.transaction.TransactionBuilder; import io.atomix.core.tree.DocumentTree; +import io.atomix.core.utils.config.PartitionGroupConfigMapper; +import io.atomix.core.utils.config.PrimitiveConfigMapper; +import io.atomix.core.utils.config.PrimitiveProtocolConfigMapper; +import io.atomix.core.utils.config.ProfileMapper; import io.atomix.core.value.AtomicValue; import io.atomix.primitive.DistributedPrimitive; import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveConfig; import io.atomix.primitive.PrimitiveInfo; import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.PrimitiveTypeRegistry; import io.atomix.primitive.partition.ManagedPartitionGroup; import io.atomix.primitive.partition.ManagedPartitionService; import io.atomix.primitive.partition.PartitionGroupConfig; -import io.atomix.primitive.partition.PartitionGroups; +import io.atomix.primitive.partition.PartitionGroupType; import io.atomix.primitive.partition.PartitionService; import io.atomix.primitive.partition.impl.DefaultPartitionService; import io.atomix.utils.concurrent.Futures; import io.atomix.utils.concurrent.SingleThreadContext; import io.atomix.utils.concurrent.ThreadContext; import io.atomix.utils.concurrent.Threads; -import io.atomix.utils.config.Configs; +import io.atomix.utils.config.ConfigMapper; +import io.atomix.utils.config.ConfigurationException; import io.atomix.utils.net.Address; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,6 +72,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.stream.Stream; import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; @@ -73,6 +81,67 @@ * Atomix! */ public class Atomix extends AtomixCluster implements PrimitivesService { + static final String[] DEFAULT_RESOURCES = new String[]{"atomix.conf", "atomix.json", "atomix.properties", "defaults.conf"}; + + private static String[] withDefaultResources(String config) { + return Streams.concat(Stream.of(config), Stream.of(DEFAULT_RESOURCES)).toArray(String[]::new); + } + + /** + * Returns a new Atomix configuration. + * + * @return a new Atomix configuration + */ + public static AtomixConfig config() { + return config(Thread.currentThread().getContextClassLoader()); + } + + /** + * Returns a new Atomix configuration. + * + * @return a new Atomix configuration + */ + public static AtomixConfig config(ClassLoader classLoader) { + return config(DEFAULT_RESOURCES, classLoader); + } + + /** + * Returns a new Atomix configuration from the given resource. + * + * @param resource the resource from which to return a new Atomix configuration + * @return a new Atomix configuration from the given resource + */ + public static AtomixConfig config(String resource) { + return config(resource, Thread.currentThread().getContextClassLoader()); + } + + /** + * Returns a new Atomix configuration from the given resource. + * + * @param resource the resource from which to return a new Atomix configuration + * @param classLoader the class loader + * @return a new Atomix configuration from the given resource + */ + public static AtomixConfig config(String resource, ClassLoader classLoader) { + return config(withDefaultResources(resource), classLoader); + } + + /** + * Returns a new Atomix configuration from the given resources. + * + * @param resources the resources from which to return a new Atomix configuration + * @param classLoader the class loader + * @return a new Atomix configuration from the given resource + */ + private static AtomixConfig config(String[] resources, ClassLoader classLoader) { + ConfigMapper mapper = new ConfigMapper( + classLoader, + new PartitionGroupConfigMapper(), + new PrimitiveConfigMapper(), + new PrimitiveProtocolConfigMapper(), + new ProfileMapper()); + return mapper.loadResources(AtomixConfig.class, resources); + } /** * Returns a new Atomix builder. @@ -80,7 +149,17 @@ public class Atomix extends AtomixCluster implements PrimitivesService { * @return a new Atomix builder */ public static Builder builder() { - return new Builder(); + return builder(Thread.currentThread().getContextClassLoader()); + } + + /** + * Returns a new Atomix builder. + * + * @param classLoader the class loader + * @return a new Atomix builder + */ + public static Builder builder(ClassLoader classLoader) { + return builder(config(DEFAULT_RESOURCES, classLoader)); } /** @@ -90,17 +169,18 @@ public static Builder builder() { * @return a new Atomix builder */ public static Builder builder(String config) { - return new Builder(loadConfig(config)); + return builder(config, Thread.currentThread().getContextClassLoader()); } /** * Returns a new Atomix builder. * - * @param configFile the configuration file with which to initialize the builder + * @param config the Atomix configuration + * @param classLoader the class loader * @return a new Atomix builder */ - public static Builder builder(File configFile) { - return new Builder(loadConfig(configFile)); + public static Builder builder(String config, ClassLoader classLoader) { + return new Builder(config(withDefaultResources(config), classLoader)); } /** @@ -116,44 +196,66 @@ public static Builder builder(AtomixConfig config) { protected static final Logger LOGGER = LoggerFactory.getLogger(Atomix.class); private final ScheduledExecutorService executorService; + private final RegistryService registry; private final ManagedPartitionService partitions; private final ManagedPrimitivesService primitives; - private final PrimitiveTypeRegistry primitiveTypes; private final boolean enableShutdownHook; private final ThreadContext threadContext = new SingleThreadContext("atomix-%d"); private Thread shutdownHook = null; public Atomix(String configFile) { - this(loadConfig(new File(System.getProperty("user.dir"), configFile))); + this(configFile, Thread.currentThread().getContextClassLoader()); + } + + public Atomix(String configFile, ClassLoader classLoader) { + this(config(withDefaultResources(configFile), classLoader)); } public Atomix(File configFile) { - this(loadConfig(configFile)); + this(configFile, Thread.currentThread().getContextClassLoader()); } - public Atomix(AtomixConfig config) { - this(config, Thread.currentThread().getContextClassLoader()); + public Atomix(File configFile, ClassLoader classLoader) { + this(configFile.getAbsolutePath(), classLoader); } - private Atomix(AtomixConfig config, ClassLoader classLoader) { + private Atomix(AtomixConfig config) { super(config.getClusterConfig()); config.getProfiles().forEach(profile -> profile.configure(config)); this.executorService = Executors.newScheduledThreadPool( Runtime.getRuntime().availableProcessors(), Threads.namedThreads("atomix-primitive-%d", LOGGER)); - this.primitiveTypes = new PrimitiveTypeRegistry(config.getPrimitiveTypes(), classLoader); - this.partitions = buildPartitionService(config, membershipService(), communicationService(), classLoader, primitiveTypes); + this.registry = new DefaultRegistryService(config.getRegistry()); + this.partitions = buildPartitionService(config, membershipService(), communicationService(), registry); this.primitives = new CorePrimitivesService( - executorService, + executorService(), membershipService(), communicationService(), eventingService(), - partitions, - config, - classLoader); + partitionService(), + registryService(), + config); this.enableShutdownHook = config.isEnableShutdownHook(); } + /** + * Returns the core Atomix executor service. + * + * @return the core Atomix executor service + */ + public ScheduledExecutorService executorService() { + return executorService; + } + + /** + * Returns the type registry service. + * + * @return the type registry service + */ + public RegistryService registryService() { + return registry; + } + /** * Returns the partition service. * @@ -180,7 +282,7 @@ public TransactionBuilder transactionBuilder(String name) { @Override public , C extends PrimitiveConfig, P extends DistributedPrimitive> B primitiveBuilder( String name, - PrimitiveType primitiveType) { + PrimitiveType primitiveType) { return primitives.primitiveBuilder(name, primitiveType); } @@ -255,7 +357,17 @@ public WorkQueue getWorkQueue(String name) { } @Override - public , P extends DistributedPrimitive> P getPrimitive(String name, PrimitiveType primitiveType, C primitiveConfig) { + public

P getPrimitive(String name, String primitiveType) { + return primitives.getPrimitive(name, primitiveType); + } + + @Override + public

P getPrimitive(String name, String primitiveType, PrimitiveConfig primitiveConfig) { + return primitives.getPrimitive(name, primitiveType, primitiveConfig); + } + + @Override + public , P extends DistributedPrimitive> P getPrimitive(String name, PrimitiveType primitiveType, C primitiveConfig) { return primitives.getPrimitive(name, primitiveType, primitiveConfig); } @@ -346,51 +458,47 @@ public String toString() { } /** - * Loads a configuration from the given file. + * Builds the core partition group. */ - private static AtomixConfig loadConfig(String config) { - File configFile = new File(config); - if (configFile.exists()) { - return Configs.load(configFile, AtomixConfig.class, Thread.currentThread().getContextClassLoader()); - } else { - return Configs.load(config, AtomixConfig.class, Thread.currentThread().getContextClassLoader()); + @SuppressWarnings("unchecked") + private static ManagedPartitionGroup buildSystemPartitionGroup(AtomixConfig config) { + PartitionGroupConfig partitionGroupConfig = config.getManagementGroup(); + if (partitionGroupConfig == null) { + return null; } - } - - /** - * Loads a configuration from the given file. - */ - private static AtomixConfig loadConfig(File config) { - return Configs.load(config, AtomixConfig.class, Thread.currentThread().getContextClassLoader()); - } - /** - * Builds the core partition group. - */ - private static ManagedPartitionGroup buildSystemPartitionGroup(AtomixConfig config, ClassLoader classLoader) { - return config.getManagementGroup() != null ? PartitionGroups.createGroup(config.getManagementGroup(), classLoader) : null; + PartitionGroupType partitionGroupType = config.getRegistry().getPartitionGroupTypes().get(partitionGroupConfig.getType()); + if (partitionGroupType == null) { + throw new ConfigurationException("Unknown partition group type " + partitionGroupConfig.getType()); + } + return partitionGroupType.newGroup(partitionGroupConfig); } /** * Builds a partition service. */ + @SuppressWarnings("unchecked") private static ManagedPartitionService buildPartitionService( AtomixConfig config, ClusterMembershipService clusterMembershipService, ClusterCommunicationService messagingService, - ClassLoader classLoader, - PrimitiveTypeRegistry primitiveTypeRegistry) { + RegistryService registryService) { List partitionGroups = new ArrayList<>(); for (PartitionGroupConfig partitionGroupConfig : config.getPartitionGroups().values()) { - partitionGroups.add(PartitionGroups.createGroup(partitionGroupConfig, classLoader)); + PartitionGroupType partitionGroupType = config.getRegistry().getPartitionGroupTypes().get(partitionGroupConfig.getType()); + if (partitionGroupType == null) { + throw new ConfigurationException("Unknown partition group type " + partitionGroupConfig.getType()); + } + partitionGroups.add(partitionGroupType.newGroup(partitionGroupConfig)); } + return new DefaultPartitionService( clusterMembershipService, messagingService, - classLoader, - primitiveTypeRegistry, - buildSystemPartitionGroup(config, classLoader), - partitionGroups); + registryService.primitiveTypes(), + buildSystemPartitionGroup(config), + partitionGroups, + registryService.partitionGroupTypes()); } /** @@ -537,7 +645,7 @@ public Builder withPrimitiveTypes(PrimitiveType... primitiveTypes) { * @throws NullPointerException if the primitive types is {@code null} */ public Builder withPrimitiveTypes(Collection primitiveTypes) { - primitiveTypes.forEach(type -> config.addType(type.getClass())); + primitiveTypes.forEach(type -> config.getRegistry().addPrimitiveType(type)); return this; } @@ -549,7 +657,7 @@ public Builder withPrimitiveTypes(Collection primitiveTypes) { * @throws NullPointerException if the primitive type is {@code null} */ public Builder addPrimitiveType(PrimitiveType primitiveType) { - config.addType(primitiveType.getClass()); + config.getRegistry().addPrimitiveType(primitiveType); return this; } diff --git a/core/src/main/java/io/atomix/core/AtomixConfig.java b/core/src/main/java/io/atomix/core/AtomixConfig.java index da99f6f9d5..e741391fac 100644 --- a/core/src/main/java/io/atomix/core/AtomixConfig.java +++ b/core/src/main/java/io/atomix/core/AtomixConfig.java @@ -17,18 +17,15 @@ import io.atomix.cluster.ClusterConfig; import io.atomix.core.profile.Profile; -import io.atomix.core.profile.Profiles; +import io.atomix.core.registry.RegistryConfig; import io.atomix.primitive.PrimitiveConfig; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.partition.PartitionGroupConfig; import io.atomix.utils.config.Config; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; @@ -42,9 +39,9 @@ public class AtomixConfig implements Config { private boolean enableShutdownHook; private PartitionGroupConfig managementGroup; private Map partitionGroups = new HashMap<>(); - private Collection> types = new ArrayList<>(); private Map primitives = new HashMap<>(); private List profiles = new ArrayList<>(); + private RegistryConfig registry = new RegistryConfig(); /** * Returns the cluster configuration. @@ -139,37 +136,6 @@ public AtomixConfig addPartitionGroup(PartitionGroupConfig partitionGroup) { return this; } - /** - * Returns the primitive types. - * - * @return the primitive types - */ - public Collection> getPrimitiveTypes() { - return types; - } - - /** - * Sets the primitive types. - * - * @param types the primitive types - * @return the primitive type configuration - */ - public AtomixConfig setPrimitiveTypes(Collection> types) { - this.types = types; - return this; - } - - /** - * Adds a primitive type. - * - * @param type the type class - * @return the primitive type configuration - */ - public AtomixConfig addType(Class type) { - types.add(type); - return this; - } - /** * Returns the primitive configurations. * @@ -229,10 +195,8 @@ public List getProfiles() { * @param profiles the profiles * @return the Atomix configuration */ - public AtomixConfig setProfiles(List profiles) { - this.profiles = profiles.stream() - .map(name -> Profiles.getNamedProfile(name)) - .collect(Collectors.toList()); + public AtomixConfig setProfiles(List profiles) { + this.profiles = profiles; return this; } @@ -246,4 +210,24 @@ public AtomixConfig addProfile(Profile profile) { profiles.add(checkNotNull(profile, "profile cannot be null")); return this; } + + /** + * Returns the registry. + * + * @return the registry + */ + public RegistryConfig getRegistry() { + return registry; + } + + /** + * Sets the registry. + * + * @param registry the registry + * @return the Atomix configuration + */ + public AtomixConfig setRegistry(RegistryConfig registry) { + this.registry = registry; + return this; + } } diff --git a/core/src/main/java/io/atomix/core/PrimitiveTypes.java b/core/src/main/java/io/atomix/core/PrimitiveTypes.java new file mode 100644 index 0000000000..beeec07871 --- /dev/null +++ b/core/src/main/java/io/atomix/core/PrimitiveTypes.java @@ -0,0 +1,196 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.core; + +import io.atomix.core.counter.AtomicCounter; +import io.atomix.core.counter.AtomicCounterBuilder; +import io.atomix.core.counter.AtomicCounterConfig; +import io.atomix.core.election.LeaderElection; +import io.atomix.core.election.LeaderElectionBuilder; +import io.atomix.core.election.LeaderElectionConfig; +import io.atomix.core.election.LeaderElector; +import io.atomix.core.election.LeaderElectorBuilder; +import io.atomix.core.election.LeaderElectorConfig; +import io.atomix.core.generator.AtomicIdGenerator; +import io.atomix.core.generator.AtomicIdGeneratorBuilder; +import io.atomix.core.generator.AtomicIdGeneratorConfig; +import io.atomix.core.lock.DistributedLock; +import io.atomix.core.lock.DistributedLockBuilder; +import io.atomix.core.lock.DistributedLockConfig; +import io.atomix.core.map.AtomicCounterMap; +import io.atomix.core.map.AtomicCounterMapBuilder; +import io.atomix.core.map.AtomicCounterMapConfig; +import io.atomix.core.map.ConsistentMap; +import io.atomix.core.map.ConsistentMapBuilder; +import io.atomix.core.map.ConsistentMapConfig; +import io.atomix.core.map.ConsistentTreeMap; +import io.atomix.core.map.ConsistentTreeMapBuilder; +import io.atomix.core.map.ConsistentTreeMapConfig; +import io.atomix.core.multimap.ConsistentMultimap; +import io.atomix.core.multimap.ConsistentMultimapBuilder; +import io.atomix.core.multimap.ConsistentMultimapConfig; +import io.atomix.core.queue.WorkQueue; +import io.atomix.core.queue.WorkQueueBuilder; +import io.atomix.core.queue.WorkQueueConfig; +import io.atomix.core.registry.RegistryConfig; +import io.atomix.core.semaphore.DistributedSemaphore; +import io.atomix.core.semaphore.DistributedSemaphoreBuilder; +import io.atomix.core.semaphore.DistributedSemaphoreConfig; +import io.atomix.core.set.DistributedSet; +import io.atomix.core.set.DistributedSetBuilder; +import io.atomix.core.set.DistributedSetConfig; +import io.atomix.core.tree.DocumentTree; +import io.atomix.core.tree.DocumentTreeBuilder; +import io.atomix.core.tree.DocumentTreeConfig; +import io.atomix.core.utils.config.PartitionGroupConfigMapper; +import io.atomix.core.utils.config.PrimitiveConfigMapper; +import io.atomix.core.utils.config.PrimitiveProtocolConfigMapper; +import io.atomix.core.utils.config.ProfileMapper; +import io.atomix.core.value.AtomicValue; +import io.atomix.core.value.AtomicValueBuilder; +import io.atomix.core.value.AtomicValueConfig; +import io.atomix.primitive.DistributedPrimitive; +import io.atomix.primitive.PrimitiveType; +import io.atomix.utils.config.ConfigMapper; + +/** + * Atomix core primitive types. + */ +@SuppressWarnings("unchecked") +public final class PrimitiveTypes { + private static final PrimitiveType, ConsistentMapConfig, ConsistentMap> CONSISTENT_MAP; + private static final PrimitiveType, DocumentTreeConfig, DocumentTree> DOCUMENT_TREE; + private static final PrimitiveType, ConsistentTreeMapConfig, ConsistentTreeMap> CONSISTENT_TREE_MAP; + private static final PrimitiveType, ConsistentMultimapConfig, ConsistentMultimap> CONSISTENT_MULTIMAP; + private static final PrimitiveType, AtomicCounterMapConfig, AtomicCounterMap> ATOMIC_COUNTER_MAP; + private static final PrimitiveType, DistributedSetConfig, DistributedSet> SET; + private static final PrimitiveType ATOMIC_COUNTER; + private static final PrimitiveType ATOMIC_ID_GENERATOR; + private static final PrimitiveType, AtomicValueConfig, AtomicValue> ATOMIC_VALUE; + private static final PrimitiveType, LeaderElectionConfig, LeaderElection> LEADER_ELECTION; + private static final PrimitiveType, LeaderElectorConfig, LeaderElector> LEADER_ELECTOR; + private static final PrimitiveType LOCK; + private static final PrimitiveType SEMAPHORE; + private static final PrimitiveType, WorkQueueConfig, WorkQueue> WORK_QUEUE; + + public static final PrimitiveType TRANSACTION = PrimitiveType.builder("transaction").build(); + + private static PrimitiveType findPrimitiveType(Class primitiveClass, RegistryConfig registry) { + return registry.getPrimitiveTypes().values() + .stream() + .filter(type -> primitiveClass == type.primitiveClass()) + .findFirst() + .orElse(null); + } + + static { + ConfigMapper mapper = new ConfigMapper( + PrimitiveTypes.class.getClassLoader(), + new PartitionGroupConfigMapper(), + new PrimitiveConfigMapper(), + new PrimitiveProtocolConfigMapper(), + new ProfileMapper()); + AtomixConfig defaultConfig = mapper.loadResources(AtomixConfig.class, Atomix.DEFAULT_RESOURCES); + RegistryConfig registry = defaultConfig.getRegistry(); + CONSISTENT_MAP = findPrimitiveType(ConsistentMap.class, registry); + DOCUMENT_TREE = findPrimitiveType(DocumentTree.class, registry); + CONSISTENT_TREE_MAP = findPrimitiveType(ConsistentTreeMap.class, registry); + CONSISTENT_MULTIMAP = findPrimitiveType(ConsistentMultimap.class, registry); + ATOMIC_COUNTER_MAP = findPrimitiveType(AtomicCounterMap.class, registry); + SET = findPrimitiveType(DistributedSet.class, registry); + ATOMIC_COUNTER = findPrimitiveType(AtomicCounter.class, registry); + ATOMIC_ID_GENERATOR = findPrimitiveType(AtomicIdGenerator.class, registry); + ATOMIC_VALUE = findPrimitiveType(AtomicValue.class, registry); + LEADER_ELECTION = findPrimitiveType(LeaderElection.class, registry); + LEADER_ELECTOR = findPrimitiveType(LeaderElector.class, registry); + LOCK = findPrimitiveType(DistributedLock.class, registry); + SEMAPHORE = findPrimitiveType(DistributedSemaphore.class, registry); + WORK_QUEUE = findPrimitiveType(WorkQueue.class, registry); + } + + @SuppressWarnings("unchecked") + public static PrimitiveType, ConsistentMapConfig, ConsistentMap> consistentMap() { + return (PrimitiveType) CONSISTENT_MAP; + } + + @SuppressWarnings("unchecked") + public static PrimitiveType, DocumentTreeConfig, DocumentTree> documentTree() { + return (PrimitiveType) DOCUMENT_TREE; + } + + @SuppressWarnings("unchecked") + public static PrimitiveType, ConsistentTreeMapConfig, ConsistentTreeMap> consistentTreeMap() { + return (PrimitiveType) CONSISTENT_TREE_MAP; + } + + @SuppressWarnings("unchecked") + public static PrimitiveType, ConsistentMultimapConfig, ConsistentMultimap> consistentMultimap() { + return (PrimitiveType) CONSISTENT_MULTIMAP; + } + + @SuppressWarnings("unchecked") + public static PrimitiveType, AtomicCounterMapConfig, AtomicCounterMap> atomicCounterMap() { + return (PrimitiveType) ATOMIC_COUNTER_MAP; + } + + @SuppressWarnings("unchecked") + public static PrimitiveType atomicCounter() { + return ATOMIC_COUNTER; + } + + @SuppressWarnings("unchecked") + public static PrimitiveType, DistributedSetConfig, DistributedSet> set() { + return (PrimitiveType) SET; + } + + @SuppressWarnings("unchecked") + public static PrimitiveType atomicIdGenerator() { + return ATOMIC_ID_GENERATOR; + } + + @SuppressWarnings("unchecked") + public static PrimitiveType, AtomicValueConfig, AtomicValue> atomicValue() { + return (PrimitiveType) ATOMIC_VALUE; + } + + @SuppressWarnings("unchecked") + public static PrimitiveType, LeaderElectionConfig, LeaderElection> leaderElection() { + return (PrimitiveType) LEADER_ELECTION; + } + + @SuppressWarnings("unchecked") + public static PrimitiveType, LeaderElectorConfig, LeaderElector> leaderElector() { + return (PrimitiveType) LEADER_ELECTOR; + } + + @SuppressWarnings("unchecked") + public static PrimitiveType lock() { + return LOCK; + } + + @SuppressWarnings("unchecked") + public static PrimitiveType semaphore() { + return SEMAPHORE; + } + + @SuppressWarnings("unchecked") + public static PrimitiveType, WorkQueueConfig, WorkQueue> workQueue() { + return (PrimitiveType) WORK_QUEUE; + } + + private PrimitiveTypes() { + } +} diff --git a/core/src/main/java/io/atomix/core/PrimitivesService.java b/core/src/main/java/io/atomix/core/PrimitivesService.java index 738c6024d2..2e56dfb167 100644 --- a/core/src/main/java/io/atomix/core/PrimitivesService.java +++ b/core/src/main/java/io/atomix/core/PrimitivesService.java @@ -17,47 +17,33 @@ import io.atomix.core.counter.AtomicCounter; import io.atomix.core.counter.AtomicCounterBuilder; -import io.atomix.core.counter.AtomicCounterType; import io.atomix.core.election.LeaderElection; import io.atomix.core.election.LeaderElectionBuilder; -import io.atomix.core.election.LeaderElectionType; import io.atomix.core.election.LeaderElector; import io.atomix.core.election.LeaderElectorBuilder; -import io.atomix.core.election.LeaderElectorType; import io.atomix.core.generator.AtomicIdGenerator; import io.atomix.core.generator.AtomicIdGeneratorBuilder; -import io.atomix.core.generator.AtomicIdGeneratorType; import io.atomix.core.lock.DistributedLock; import io.atomix.core.lock.DistributedLockBuilder; -import io.atomix.core.lock.DistributedLockType; import io.atomix.core.map.AtomicCounterMap; import io.atomix.core.map.AtomicCounterMapBuilder; -import io.atomix.core.map.AtomicCounterMapType; import io.atomix.core.map.ConsistentMap; import io.atomix.core.map.ConsistentMapBuilder; -import io.atomix.core.map.ConsistentMapType; import io.atomix.core.map.ConsistentTreeMap; import io.atomix.core.map.ConsistentTreeMapBuilder; -import io.atomix.core.map.ConsistentTreeMapType; import io.atomix.core.multimap.ConsistentMultimap; import io.atomix.core.multimap.ConsistentMultimapBuilder; -import io.atomix.core.multimap.ConsistentMultimapType; import io.atomix.core.queue.WorkQueue; import io.atomix.core.queue.WorkQueueBuilder; -import io.atomix.core.queue.WorkQueueType; import io.atomix.core.semaphore.DistributedSemaphore; import io.atomix.core.semaphore.DistributedSemaphoreBuilder; -import io.atomix.core.semaphore.DistributedSemaphoreType; import io.atomix.core.set.DistributedSet; import io.atomix.core.set.DistributedSetBuilder; -import io.atomix.core.set.DistributedSetType; import io.atomix.core.transaction.TransactionBuilder; import io.atomix.core.tree.DocumentTree; import io.atomix.core.tree.DocumentTreeBuilder; -import io.atomix.core.tree.DocumentTreeType; import io.atomix.core.value.AtomicValue; import io.atomix.core.value.AtomicValueBuilder; -import io.atomix.core.value.AtomicValueType; import io.atomix.primitive.DistributedPrimitive; import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveConfig; @@ -81,7 +67,7 @@ public interface PrimitivesService { * @return builder for a consistent map */ default ConsistentMapBuilder consistentMapBuilder(String name) { - return primitiveBuilder(name, ConsistentMapType.instance()); + return primitiveBuilder(name, PrimitiveTypes.consistentMap()); } /** @@ -94,7 +80,7 @@ default ConsistentMapBuilder consistentMapBuilder(String name) { * @return builder for a consistent map */ default ConsistentMapBuilder consistentMapBuilder(String name, PrimitiveProtocol protocol) { - return primitiveBuilder(name, ConsistentMapType.instance(), protocol); + return primitiveBuilder(name, PrimitiveTypes.consistentMap(), protocol); } /** @@ -105,7 +91,7 @@ default ConsistentMapBuilder consistentMapBuilder(String name, Prim * @return builder for a consistent map */ default DocumentTreeBuilder documentTreeBuilder(String name) { - return primitiveBuilder(name, DocumentTreeType.instance()); + return primitiveBuilder(name, PrimitiveTypes.documentTree()); } /** @@ -117,7 +103,7 @@ default DocumentTreeBuilder documentTreeBuilder(String name) { * @return builder for a consistent map */ default DocumentTreeBuilder documentTreeBuilder(String name, PrimitiveProtocol protocol) { - return primitiveBuilder(name, DocumentTreeType.instance(), protocol); + return primitiveBuilder(name, PrimitiveTypes.documentTree(), protocol); } /** @@ -128,7 +114,7 @@ default DocumentTreeBuilder documentTreeBuilder(String name, PrimitivePro * @return builder for a async consistent tree map */ default ConsistentTreeMapBuilder consistentTreeMapBuilder(String name) { - return primitiveBuilder(name, ConsistentTreeMapType.instance()); + return primitiveBuilder(name, PrimitiveTypes.consistentTreeMap()); } /** @@ -140,7 +126,7 @@ default ConsistentTreeMapBuilder consistentTreeMapBuilder(String name) { * @return builder for a async consistent tree map */ default ConsistentTreeMapBuilder consistentTreeMapBuilder(String name, PrimitiveProtocol protocol) { - return primitiveBuilder(name, ConsistentTreeMapType.instance(), protocol); + return primitiveBuilder(name, PrimitiveTypes.consistentTreeMap(), protocol); } /** @@ -152,7 +138,7 @@ default ConsistentTreeMapBuilder consistentTreeMapBuilder(String name, Pr * @return builder for a set based async consistent multimap */ default ConsistentMultimapBuilder consistentMultimapBuilder(String name) { - return primitiveBuilder(name, ConsistentMultimapType.instance()); + return primitiveBuilder(name, PrimitiveTypes.consistentMultimap()); } /** @@ -165,7 +151,7 @@ default ConsistentMultimapBuilder consistentMultimapBuilder(String * @return builder for a set based async consistent multimap */ default ConsistentMultimapBuilder consistentMultimapBuilder(String name, PrimitiveProtocol protocol) { - return primitiveBuilder(name, ConsistentMultimapType.instance(), protocol); + return primitiveBuilder(name, PrimitiveTypes.consistentMultimap(), protocol); } /** @@ -176,7 +162,7 @@ default ConsistentMultimapBuilder consistentMultimapBuilder(String * @return builder for an atomic counter map */ default AtomicCounterMapBuilder atomicCounterMapBuilder(String name) { - return primitiveBuilder(name, AtomicCounterMapType.instance()); + return primitiveBuilder(name, PrimitiveTypes.atomicCounterMap()); } /** @@ -188,7 +174,7 @@ default AtomicCounterMapBuilder atomicCounterMapBuilder(String name) { * @return builder for an atomic counter map */ default AtomicCounterMapBuilder atomicCounterMapBuilder(String name, PrimitiveProtocol protocol) { - return primitiveBuilder(name, AtomicCounterMapType.instance(), protocol); + return primitiveBuilder(name, PrimitiveTypes.atomicCounterMap(), protocol); } /** @@ -199,7 +185,7 @@ default AtomicCounterMapBuilder atomicCounterMapBuilder(String name, Prim * @return builder for an distributed set */ default DistributedSetBuilder setBuilder(String name) { - return primitiveBuilder(name, DistributedSetType.instance()); + return primitiveBuilder(name, PrimitiveTypes.set()); } /** @@ -211,7 +197,7 @@ default DistributedSetBuilder setBuilder(String name) { * @return builder for an distributed set */ default DistributedSetBuilder setBuilder(String name, PrimitiveProtocol protocol) { - return primitiveBuilder(name, DistributedSetType.instance(), protocol); + return primitiveBuilder(name, PrimitiveTypes.set(), protocol); } /** @@ -221,7 +207,7 @@ default DistributedSetBuilder setBuilder(String name, PrimitiveProtocol p * @return atomic counter builder */ default AtomicCounterBuilder atomicCounterBuilder(String name) { - return primitiveBuilder(name, AtomicCounterType.instance()); + return primitiveBuilder(name, PrimitiveTypes.atomicCounter()); } /** @@ -232,7 +218,7 @@ default AtomicCounterBuilder atomicCounterBuilder(String name) { * @return atomic counter builder */ default AtomicCounterBuilder atomicCounterBuilder(String name, PrimitiveProtocol protocol) { - return primitiveBuilder(name, AtomicCounterType.instance(), protocol); + return primitiveBuilder(name, PrimitiveTypes.atomicCounter(), protocol); } /** @@ -242,7 +228,7 @@ default AtomicCounterBuilder atomicCounterBuilder(String name, PrimitiveProtocol * @return atomic ID generator builder */ default AtomicIdGeneratorBuilder atomicIdGeneratorBuilder(String name) { - return primitiveBuilder(name, AtomicIdGeneratorType.instance()); + return primitiveBuilder(name, PrimitiveTypes.atomicIdGenerator()); } /** @@ -253,7 +239,7 @@ default AtomicIdGeneratorBuilder atomicIdGeneratorBuilder(String name) { * @return atomic ID generator builder */ default AtomicIdGeneratorBuilder atomicIdGeneratorBuilder(String name, PrimitiveProtocol protocol) { - return primitiveBuilder(name, AtomicIdGeneratorType.instance(), protocol); + return primitiveBuilder(name, PrimitiveTypes.atomicIdGenerator(), protocol); } /** @@ -264,7 +250,7 @@ default AtomicIdGeneratorBuilder atomicIdGeneratorBuilder(String name, Primitive * @return atomic value builder */ default AtomicValueBuilder atomicValueBuilder(String name) { - return primitiveBuilder(name, AtomicValueType.instance()); + return primitiveBuilder(name, PrimitiveTypes.atomicValue()); } /** @@ -276,7 +262,7 @@ default AtomicValueBuilder atomicValueBuilder(String name) { * @return atomic value builder */ default AtomicValueBuilder atomicValueBuilder(String name, PrimitiveProtocol protocol) { - return primitiveBuilder(name, AtomicValueType.instance(), protocol); + return primitiveBuilder(name, PrimitiveTypes.atomicValue(), protocol); } /** @@ -286,7 +272,7 @@ default AtomicValueBuilder atomicValueBuilder(String name, PrimitiveProto * @return leader election builder */ default LeaderElectionBuilder leaderElectionBuilder(String name) { - return primitiveBuilder(name, LeaderElectionType.instance()); + return primitiveBuilder(name, PrimitiveTypes.leaderElection()); } /** @@ -297,7 +283,7 @@ default LeaderElectionBuilder leaderElectionBuilder(String name) { * @return leader election builder */ default LeaderElectionBuilder leaderElectionBuilder(String name, PrimitiveProtocol protocol) { - return primitiveBuilder(name, LeaderElectionType.instance(), protocol); + return primitiveBuilder(name, PrimitiveTypes.leaderElection(), protocol); } /** @@ -307,7 +293,7 @@ default LeaderElectionBuilder leaderElectionBuilder(String name, Primitiv * @return leader elector builder */ default LeaderElectorBuilder leaderElectorBuilder(String name) { - return primitiveBuilder(name, LeaderElectorType.instance()); + return primitiveBuilder(name, PrimitiveTypes.leaderElector()); } /** @@ -318,7 +304,7 @@ default LeaderElectorBuilder leaderElectorBuilder(String name) { * @return leader elector builder */ default LeaderElectorBuilder leaderElectorBuilder(String name, PrimitiveProtocol protocol) { - return primitiveBuilder(name, LeaderElectorType.instance(), protocol); + return primitiveBuilder(name, PrimitiveTypes.leaderElector(), protocol); } /** @@ -328,7 +314,7 @@ default LeaderElectorBuilder leaderElectorBuilder(String name, PrimitiveP * @return distributed lock builder */ default DistributedLockBuilder lockBuilder(String name) { - return primitiveBuilder(name, DistributedLockType.instance()); + return primitiveBuilder(name, PrimitiveTypes.lock()); } /** @@ -339,18 +325,18 @@ default DistributedLockBuilder lockBuilder(String name) { * @return distributed lock builder */ default DistributedLockBuilder lockBuilder(String name, PrimitiveProtocol protocol) { - return primitiveBuilder(name, DistributedLockType.instance(), protocol); + return primitiveBuilder(name, PrimitiveTypes.lock(), protocol); } /** * Creates a new DistributedSemaphoreBuilder. * - * @param name the primitive name + * @param name the primitive name * @param protocol the primitive protocol * @return distributed semaphore builder */ default DistributedSemaphoreBuilder semaphoreBuilder(String name, PrimitiveProtocol protocol) { - return primitiveBuilder(name, DistributedSemaphoreType.instance(), protocol); + return primitiveBuilder(name, PrimitiveTypes.semaphore(), protocol); } /** @@ -360,7 +346,7 @@ default DistributedSemaphoreBuilder semaphoreBuilder(String name, PrimitiveProto * @return distributed semaphore builder */ default DistributedSemaphoreBuilder semaphoreBuilder(String name) { - return primitiveBuilder(name, DistributedSemaphoreType.instance()); + return primitiveBuilder(name, PrimitiveTypes.semaphore()); } /** @@ -371,7 +357,7 @@ default DistributedSemaphoreBuilder semaphoreBuilder(String name) { * @return work queue builder */ default WorkQueueBuilder workQueueBuilder(String name) { - return primitiveBuilder(name, WorkQueueType.instance()); + return primitiveBuilder(name, PrimitiveTypes.workQueue()); } /** @@ -383,7 +369,7 @@ default WorkQueueBuilder workQueueBuilder(String name) { * @return work queue builder */ default WorkQueueBuilder workQueueBuilder(String name, PrimitiveProtocol protocol) { - return primitiveBuilder(name, WorkQueueType.instance(), protocol); + return primitiveBuilder(name, PrimitiveTypes.workQueue(), protocol); } /** @@ -534,6 +520,30 @@ default TransactionBuilder transactionBuilder() { */

P getPrimitive(String name); + /** + * Returns a registered primitive. + * + * @param name the primitive name + * @param primitiveType the primitive type + * @param

the primitive type + * @return the primitive instance + */ +

P getPrimitive(String name, String primitiveType); + + /** + * Returns a cached primitive. + * + * @param name the primitive name + * @param primitiveType the primitive type + * @param primitiveConfig the primitive configuration + * @param

the primitive type + * @return the primitive instance + */ +

P getPrimitive( + String name, + String primitiveType, + PrimitiveConfig primitiveConfig); + /** * Returns a cached primitive. * @@ -546,7 +556,7 @@ default TransactionBuilder transactionBuilder() { */ , P extends DistributedPrimitive> P getPrimitive( String name, - PrimitiveType primitiveType, + PrimitiveType primitiveType, C primitiveConfig); /** @@ -560,7 +570,7 @@ , P extends DistributedPrimitive> P getPrimitive( */ , C extends PrimitiveConfig, P extends DistributedPrimitive> B primitiveBuilder( String name, - PrimitiveType primitiveType); + PrimitiveType primitiveType); /** * Returns a primitive builder of the given type. @@ -574,7 +584,7 @@ , C extends PrimitiveConfig, P */ default , C extends PrimitiveConfig, P extends DistributedPrimitive> B primitiveBuilder( String name, - PrimitiveType primitiveType, + PrimitiveType primitiveType, PrimitiveProtocol protocol) { return primitiveBuilder(name, primitiveType).withProtocol(protocol); } diff --git a/core/src/main/java/io/atomix/core/counter/AsyncAtomicCounter.java b/core/src/main/java/io/atomix/core/counter/AsyncAtomicCounter.java index 34bf90158c..307f4ba0d4 100644 --- a/core/src/main/java/io/atomix/core/counter/AsyncAtomicCounter.java +++ b/core/src/main/java/io/atomix/core/counter/AsyncAtomicCounter.java @@ -17,7 +17,6 @@ import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; -import io.atomix.primitive.PrimitiveType; import java.time.Duration; import java.util.concurrent.CompletableFuture; @@ -27,11 +26,6 @@ */ public interface AsyncAtomicCounter extends AsyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return AtomicCounterType.instance(); - } - /** * Atomically increment by one and return the updated value. * diff --git a/core/src/main/java/io/atomix/core/counter/AtomicCounter.java b/core/src/main/java/io/atomix/core/counter/AtomicCounter.java index 29e1704333..9133873b5c 100644 --- a/core/src/main/java/io/atomix/core/counter/AtomicCounter.java +++ b/core/src/main/java/io/atomix/core/counter/AtomicCounter.java @@ -15,7 +15,6 @@ */ package io.atomix.core.counter; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.SyncPrimitive; /** @@ -23,11 +22,6 @@ */ public interface AtomicCounter extends SyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return AtomicCounterType.instance(); - } - /** * Atomically increment by one and return the updated value. * diff --git a/core/src/main/java/io/atomix/core/counter/AtomicCounterBuilder.java b/core/src/main/java/io/atomix/core/counter/AtomicCounterBuilder.java index 57f5fb1178..92183c9971 100644 --- a/core/src/main/java/io/atomix/core/counter/AtomicCounterBuilder.java +++ b/core/src/main/java/io/atomix/core/counter/AtomicCounterBuilder.java @@ -17,13 +17,14 @@ import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; /** * Builder for AtomicCounter. */ public abstract class AtomicCounterBuilder extends DistributedPrimitiveBuilder { - public AtomicCounterBuilder(String name, AtomicCounterConfig config, PrimitiveManagementService managementService) { - super(AtomicCounterType.instance(), name, config, managementService); + public AtomicCounterBuilder(PrimitiveType type, String name, AtomicCounterConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } } \ No newline at end of file diff --git a/core/src/main/java/io/atomix/core/counter/AtomicCounterConfig.java b/core/src/main/java/io/atomix/core/counter/AtomicCounterConfig.java index f7b623e82a..d5c11cbacb 100644 --- a/core/src/main/java/io/atomix/core/counter/AtomicCounterConfig.java +++ b/core/src/main/java/io/atomix/core/counter/AtomicCounterConfig.java @@ -15,13 +15,15 @@ */ package io.atomix.core.counter; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** * Atomic counter configuration. */ public class AtomicCounterConfig extends PrimitiveConfig { - public AtomicCounterConfig() { - super(AtomicCounterType.instance()); + @Override + public String getType() { + return PrimitiveTypes.atomicCounter().name(); } } diff --git a/core/src/main/java/io/atomix/core/counter/AtomicCounterType.java b/core/src/main/java/io/atomix/core/counter/AtomicCounterType.java deleted file mode 100644 index fdf3d6645d..0000000000 --- a/core/src/main/java/io/atomix/core/counter/AtomicCounterType.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.core.counter; - -import io.atomix.core.counter.impl.AtomicCounterProxyBuilder; -import io.atomix.core.counter.impl.AtomicCounterResource; -import io.atomix.core.counter.impl.AtomicCounterService; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.resource.PrimitiveResource; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Atomic counter primitive type. - */ -public class AtomicCounterType implements PrimitiveType { - private static final String NAME = "counter"; - - /** - * Returns a new atomic counter type. - * - * @return a new atomic counter type - */ - public static AtomicCounterType instance() { - return new AtomicCounterType(); - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new AtomicCounterService(config); - } - - @Override - public PrimitiveResource newResource(AtomicCounter primitive) { - return new AtomicCounterResource(primitive.async()); - } - - @Override - public AtomicCounterBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new AtomicCounterConfig(), managementService); - } - - @Override - public AtomicCounterBuilder newPrimitiveBuilder(String name, AtomicCounterConfig config, PrimitiveManagementService managementService) { - return new AtomicCounterProxyBuilder(name, config, managementService); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/counter/impl/AtomicCounterProxyBuilder.java b/core/src/main/java/io/atomix/core/counter/impl/AtomicCounterProxyBuilder.java index 33e6bf9040..3952ac9a03 100644 --- a/core/src/main/java/io/atomix/core/counter/impl/AtomicCounterProxyBuilder.java +++ b/core/src/main/java/io/atomix/core/counter/impl/AtomicCounterProxyBuilder.java @@ -19,6 +19,7 @@ import io.atomix.core.counter.AtomicCounterBuilder; import io.atomix.core.counter.AtomicCounterConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; @@ -28,8 +29,8 @@ * Atomic counter proxy builder. */ public class AtomicCounterProxyBuilder extends AtomicCounterBuilder { - public AtomicCounterProxyBuilder(String name, AtomicCounterConfig config, PrimitiveManagementService managementService) { - super(name, config, managementService); + public AtomicCounterProxyBuilder(PrimitiveType type, String name, AtomicCounterConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/election/AsyncLeaderElection.java b/core/src/main/java/io/atomix/core/election/AsyncLeaderElection.java index 1ad278cd35..0de587ebe4 100644 --- a/core/src/main/java/io/atomix/core/election/AsyncLeaderElection.java +++ b/core/src/main/java/io/atomix/core/election/AsyncLeaderElection.java @@ -17,7 +17,6 @@ import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; -import io.atomix.primitive.PrimitiveType; import java.time.Duration; import java.util.concurrent.CompletableFuture; @@ -43,11 +42,6 @@ */ public interface AsyncLeaderElection extends AsyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return LeaderElectionType.instance(); - } - /** * Attempts to become leader for a topic. * diff --git a/core/src/main/java/io/atomix/core/election/AsyncLeaderElector.java b/core/src/main/java/io/atomix/core/election/AsyncLeaderElector.java index d6fd382e88..fc8f41f9ce 100644 --- a/core/src/main/java/io/atomix/core/election/AsyncLeaderElector.java +++ b/core/src/main/java/io/atomix/core/election/AsyncLeaderElector.java @@ -17,7 +17,6 @@ import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; -import io.atomix.primitive.PrimitiveType; import java.time.Duration; import java.util.Map; @@ -35,11 +34,6 @@ */ public interface AsyncLeaderElector extends AsyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return LeaderElectorType.instance(); - } - /** * Attempts to become leader for a topic. * diff --git a/core/src/main/java/io/atomix/core/election/LeaderElection.java b/core/src/main/java/io/atomix/core/election/LeaderElection.java index 9a364c1464..1f65931d8f 100644 --- a/core/src/main/java/io/atomix/core/election/LeaderElection.java +++ b/core/src/main/java/io/atomix/core/election/LeaderElection.java @@ -15,7 +15,6 @@ */ package io.atomix.core.election; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.SyncPrimitive; /** @@ -24,11 +23,6 @@ */ public interface LeaderElection extends SyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return LeaderElectionType.instance(); - } - /** * Attempts to become leader for a topic. * diff --git a/core/src/main/java/io/atomix/core/election/LeaderElectionBuilder.java b/core/src/main/java/io/atomix/core/election/LeaderElectionBuilder.java index ef000b04ec..a601663172 100644 --- a/core/src/main/java/io/atomix/core/election/LeaderElectionBuilder.java +++ b/core/src/main/java/io/atomix/core/election/LeaderElectionBuilder.java @@ -18,6 +18,7 @@ import io.atomix.cluster.MemberId; import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.utils.serializer.KryoNamespace; import io.atomix.utils.serializer.KryoNamespaces; import io.atomix.utils.serializer.Serializer; @@ -29,8 +30,8 @@ public abstract class LeaderElectionBuilder extends DistributedPrimitiveBuilder, LeaderElectionConfig, LeaderElection> { - public LeaderElectionBuilder(String name, LeaderElectionConfig config, PrimitiveManagementService managementService) { - super(LeaderElectionType.instance(), name, config, managementService); + public LeaderElectionBuilder(PrimitiveType type, String name, LeaderElectionConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/election/LeaderElectionConfig.java b/core/src/main/java/io/atomix/core/election/LeaderElectionConfig.java index 29e036528f..f7045c08bc 100644 --- a/core/src/main/java/io/atomix/core/election/LeaderElectionConfig.java +++ b/core/src/main/java/io/atomix/core/election/LeaderElectionConfig.java @@ -15,13 +15,15 @@ */ package io.atomix.core.election; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** * Leader election configuration. */ public class LeaderElectionConfig extends PrimitiveConfig { - public LeaderElectionConfig() { - super(LeaderElectionType.instance()); + @Override + public String getType() { + return PrimitiveTypes.leaderElection().name(); } } diff --git a/core/src/main/java/io/atomix/core/election/LeaderElectionType.java b/core/src/main/java/io/atomix/core/election/LeaderElectionType.java deleted file mode 100644 index b22cc00eea..0000000000 --- a/core/src/main/java/io/atomix/core/election/LeaderElectionType.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.core.election; - -import io.atomix.core.election.impl.LeaderElectionProxyBuilder; -import io.atomix.core.election.impl.LeaderElectionResource; -import io.atomix.core.election.impl.LeaderElectionService; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.resource.PrimitiveResource; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Leader elector primitive type. - */ -public class LeaderElectionType implements PrimitiveType, LeaderElectionConfig, LeaderElection, ServiceConfig> { - private static final String NAME = "leader-election"; - - /** - * Returns a new leader elector type. - * - * @param the election candidate type - * @return a new leader elector type - */ - public static LeaderElectionType instance() { - return new LeaderElectionType<>(); - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new LeaderElectionService(config); - } - - @Override - @SuppressWarnings("unchecked") - public PrimitiveResource newResource(LeaderElection primitive) { - return new LeaderElectionResource((AsyncLeaderElection) primitive.async()); - } - - @Override - public LeaderElectionBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new LeaderElectionConfig(), managementService); - } - - @Override - public LeaderElectionBuilder newPrimitiveBuilder(String name, LeaderElectionConfig config, PrimitiveManagementService managementService) { - return new LeaderElectionProxyBuilder<>(name, config, managementService); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/election/LeaderElector.java b/core/src/main/java/io/atomix/core/election/LeaderElector.java index f1fd721f27..225870219b 100644 --- a/core/src/main/java/io/atomix/core/election/LeaderElector.java +++ b/core/src/main/java/io/atomix/core/election/LeaderElector.java @@ -15,7 +15,6 @@ */ package io.atomix.core.election; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.SyncPrimitive; import java.util.Map; @@ -26,11 +25,6 @@ */ public interface LeaderElector extends SyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return LeaderElectorType.instance(); - } - /** * Attempts to become leader for a topic. * diff --git a/core/src/main/java/io/atomix/core/election/LeaderElectorBuilder.java b/core/src/main/java/io/atomix/core/election/LeaderElectorBuilder.java index 5ba401990d..f38a3a8f90 100644 --- a/core/src/main/java/io/atomix/core/election/LeaderElectorBuilder.java +++ b/core/src/main/java/io/atomix/core/election/LeaderElectorBuilder.java @@ -18,6 +18,7 @@ import io.atomix.cluster.MemberId; import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.utils.serializer.KryoNamespace; import io.atomix.utils.serializer.KryoNamespaces; import io.atomix.utils.serializer.Serializer; @@ -28,8 +29,8 @@ */ public abstract class LeaderElectorBuilder extends DistributedPrimitiveBuilder, LeaderElectorConfig, LeaderElector> { - public LeaderElectorBuilder(String name, LeaderElectorConfig config, PrimitiveManagementService managementService) { - super(LeaderElectorType.instance(), name, config, managementService); + public LeaderElectorBuilder(PrimitiveType type, String name, LeaderElectorConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/election/LeaderElectorConfig.java b/core/src/main/java/io/atomix/core/election/LeaderElectorConfig.java index 1909b1cc32..ae0173cbb4 100644 --- a/core/src/main/java/io/atomix/core/election/LeaderElectorConfig.java +++ b/core/src/main/java/io/atomix/core/election/LeaderElectorConfig.java @@ -15,13 +15,15 @@ */ package io.atomix.core.election; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** * Leader elector configuration. */ public class LeaderElectorConfig extends PrimitiveConfig { - public LeaderElectorConfig() { - super(LeaderElectorType.instance()); + @Override + public String getType() { + return PrimitiveTypes.leaderElector().name(); } } diff --git a/core/src/main/java/io/atomix/core/election/LeaderElectorType.java b/core/src/main/java/io/atomix/core/election/LeaderElectorType.java deleted file mode 100644 index e62476ce80..0000000000 --- a/core/src/main/java/io/atomix/core/election/LeaderElectorType.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.core.election; - -import io.atomix.core.election.impl.LeaderElectorProxyBuilder; -import io.atomix.core.election.impl.LeaderElectorService; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Leader elector primitive type. - */ -public class LeaderElectorType implements PrimitiveType, LeaderElectorConfig, LeaderElector, ServiceConfig> { - private static final String NAME = "leader-elector"; - - /** - * Returns a new leader elector type. - * - * @param the election candidate type - * @return a new leader elector type - */ - public static LeaderElectorType instance() { - return new LeaderElectorType<>(); - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new LeaderElectorService(config); - } - - @Override - public LeaderElectorBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new LeaderElectorConfig(), managementService); - } - - @Override - public LeaderElectorBuilder newPrimitiveBuilder(String name, LeaderElectorConfig config, PrimitiveManagementService managementService) { - return new LeaderElectorProxyBuilder<>(name, config, managementService); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/election/impl/LeaderElectionProxyBuilder.java b/core/src/main/java/io/atomix/core/election/impl/LeaderElectionProxyBuilder.java index 06ac1e34ee..b512115136 100644 --- a/core/src/main/java/io/atomix/core/election/impl/LeaderElectionProxyBuilder.java +++ b/core/src/main/java/io/atomix/core/election/impl/LeaderElectionProxyBuilder.java @@ -19,6 +19,7 @@ import io.atomix.core.election.LeaderElectionBuilder; import io.atomix.core.election.LeaderElectionConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; import io.atomix.utils.serializer.Serializer; @@ -29,8 +30,8 @@ * Default implementation of {@code LeaderElectorBuilder}. */ public class LeaderElectionProxyBuilder extends LeaderElectionBuilder { - public LeaderElectionProxyBuilder(String name, LeaderElectionConfig config, PrimitiveManagementService managementService) { - super(name, config, managementService); + public LeaderElectionProxyBuilder(PrimitiveType type, String name, LeaderElectionConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/election/impl/LeaderElectorProxyBuilder.java b/core/src/main/java/io/atomix/core/election/impl/LeaderElectorProxyBuilder.java index 24cd5c172f..6c00b83da8 100644 --- a/core/src/main/java/io/atomix/core/election/impl/LeaderElectorProxyBuilder.java +++ b/core/src/main/java/io/atomix/core/election/impl/LeaderElectorProxyBuilder.java @@ -19,6 +19,7 @@ import io.atomix.core.election.LeaderElectorBuilder; import io.atomix.core.election.LeaderElectorConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; import io.atomix.utils.serializer.Serializer; @@ -29,8 +30,8 @@ * Default implementation of {@code LeaderElectorBuilder}. */ public class LeaderElectorProxyBuilder extends LeaderElectorBuilder { - public LeaderElectorProxyBuilder(String name, LeaderElectorConfig config, PrimitiveManagementService managementService) { - super(name, config, managementService); + public LeaderElectorProxyBuilder(PrimitiveType type, String name, LeaderElectorConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/election/impl/TranscodingAsyncLeaderElection.java b/core/src/main/java/io/atomix/core/election/impl/TranscodingAsyncLeaderElection.java index e012346668..864de4e2c8 100644 --- a/core/src/main/java/io/atomix/core/election/impl/TranscodingAsyncLeaderElection.java +++ b/core/src/main/java/io/atomix/core/election/impl/TranscodingAsyncLeaderElection.java @@ -16,12 +16,12 @@ package io.atomix.core.election.impl; import com.google.common.collect.Maps; - import io.atomix.core.election.AsyncLeaderElection; import io.atomix.core.election.LeaderElection; import io.atomix.core.election.Leadership; import io.atomix.core.election.LeadershipEvent; import io.atomix.core.election.LeadershipEventListener; +import io.atomix.primitive.PrimitiveType; import java.time.Duration; import java.util.Map; @@ -51,6 +51,11 @@ public String name() { return backingElection.name(); } + @Override + public PrimitiveType primitiveType() { + return backingElection.primitiveType(); + } + @Override public CompletableFuture> run(V1 identifier) { return backingElection.run(valueEncoder.apply(identifier)).thenApply(l -> l.map(valueDecoder)); diff --git a/core/src/main/java/io/atomix/core/election/impl/TranscodingAsyncLeaderElector.java b/core/src/main/java/io/atomix/core/election/impl/TranscodingAsyncLeaderElector.java index 4fe5d7d6c5..c5ec6b7954 100644 --- a/core/src/main/java/io/atomix/core/election/impl/TranscodingAsyncLeaderElector.java +++ b/core/src/main/java/io/atomix/core/election/impl/TranscodingAsyncLeaderElector.java @@ -16,12 +16,12 @@ package io.atomix.core.election.impl; import com.google.common.collect.Maps; - import io.atomix.core.election.AsyncLeaderElector; import io.atomix.core.election.LeaderElector; import io.atomix.core.election.Leadership; import io.atomix.core.election.LeadershipEvent; import io.atomix.core.election.LeadershipEventListener; +import io.atomix.primitive.PrimitiveType; import java.time.Duration; import java.util.Map; @@ -51,6 +51,11 @@ public String name() { return backingElector.name(); } + @Override + public PrimitiveType primitiveType() { + return backingElector.primitiveType(); + } + @Override public CompletableFuture> run(String topic, V1 identifier) { return backingElector.run(topic, valueEncoder.apply(identifier)) diff --git a/core/src/main/java/io/atomix/core/generator/AsyncAtomicIdGenerator.java b/core/src/main/java/io/atomix/core/generator/AsyncAtomicIdGenerator.java index f9b99aec3f..f100c22d07 100644 --- a/core/src/main/java/io/atomix/core/generator/AsyncAtomicIdGenerator.java +++ b/core/src/main/java/io/atomix/core/generator/AsyncAtomicIdGenerator.java @@ -17,7 +17,6 @@ import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; -import io.atomix.primitive.PrimitiveType; import java.time.Duration; import java.util.concurrent.CompletableFuture; @@ -27,11 +26,6 @@ */ public interface AsyncAtomicIdGenerator extends AsyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return AtomicIdGeneratorType.instance(); - } - /** * Returns the next globally unique numeric ID. * diff --git a/core/src/main/java/io/atomix/core/generator/AtomicIdGenerator.java b/core/src/main/java/io/atomix/core/generator/AtomicIdGenerator.java index 17bba3b2b9..19034ef69d 100644 --- a/core/src/main/java/io/atomix/core/generator/AtomicIdGenerator.java +++ b/core/src/main/java/io/atomix/core/generator/AtomicIdGenerator.java @@ -15,7 +15,6 @@ */ package io.atomix.core.generator; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.SyncPrimitive; /** @@ -23,11 +22,6 @@ */ public interface AtomicIdGenerator extends SyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return AtomicIdGeneratorType.instance(); - } - /** * Gets the next globally unique numeric identifier. * diff --git a/core/src/main/java/io/atomix/core/generator/AtomicIdGeneratorBuilder.java b/core/src/main/java/io/atomix/core/generator/AtomicIdGeneratorBuilder.java index 7d9f5a320f..61b28a4fea 100644 --- a/core/src/main/java/io/atomix/core/generator/AtomicIdGeneratorBuilder.java +++ b/core/src/main/java/io/atomix/core/generator/AtomicIdGeneratorBuilder.java @@ -17,13 +17,14 @@ import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; /** * Builder for AtomicIdGenerator. */ public abstract class AtomicIdGeneratorBuilder extends DistributedPrimitiveBuilder { - protected AtomicIdGeneratorBuilder(String name, AtomicIdGeneratorConfig config, PrimitiveManagementService managementService) { - super(AtomicIdGeneratorType.instance(), name, config, managementService); + protected AtomicIdGeneratorBuilder(PrimitiveType type, String name, AtomicIdGeneratorConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } } \ No newline at end of file diff --git a/core/src/main/java/io/atomix/core/generator/AtomicIdGeneratorConfig.java b/core/src/main/java/io/atomix/core/generator/AtomicIdGeneratorConfig.java index 0c76eb4df0..e1147c8796 100644 --- a/core/src/main/java/io/atomix/core/generator/AtomicIdGeneratorConfig.java +++ b/core/src/main/java/io/atomix/core/generator/AtomicIdGeneratorConfig.java @@ -15,13 +15,15 @@ */ package io.atomix.core.generator; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** * ID generator configuration. */ public class AtomicIdGeneratorConfig extends PrimitiveConfig { - public AtomicIdGeneratorConfig() { - super(AtomicIdGeneratorType.instance()); + @Override + public String getType() { + return PrimitiveTypes.atomicIdGenerator().name(); } } diff --git a/core/src/main/java/io/atomix/core/generator/AtomicIdGeneratorType.java b/core/src/main/java/io/atomix/core/generator/AtomicIdGeneratorType.java deleted file mode 100644 index bba94a65ad..0000000000 --- a/core/src/main/java/io/atomix/core/generator/AtomicIdGeneratorType.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.core.generator; - -import io.atomix.core.counter.impl.AtomicCounterService; -import io.atomix.core.generator.impl.AtomicIdGeneratorResource; -import io.atomix.core.generator.impl.DelegatingAtomicIdGeneratorBuilder; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.resource.PrimitiveResource; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Atomic ID generator primitive type. - */ -public class AtomicIdGeneratorType implements PrimitiveType { - private static final String NAME = "id-generator"; - - /** - * Returns a new atomic ID generator type. - * - * @return a new atomic ID generator type - */ - public static AtomicIdGeneratorType instance() { - return new AtomicIdGeneratorType(); - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new AtomicCounterService(config); - } - - @Override - public PrimitiveResource newResource(AtomicIdGenerator primitive) { - return new AtomicIdGeneratorResource(primitive.async()); - } - - @Override - public AtomicIdGeneratorBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new AtomicIdGeneratorConfig(), managementService); - } - - @Override - public AtomicIdGeneratorBuilder newPrimitiveBuilder(String name, AtomicIdGeneratorConfig config, PrimitiveManagementService managementService) { - return new DelegatingAtomicIdGeneratorBuilder(name, config, managementService); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/generator/impl/DelegatingAtomicIdGenerator.java b/core/src/main/java/io/atomix/core/generator/impl/DelegatingAtomicIdGenerator.java index ca92da4349..cd3a1d8edb 100644 --- a/core/src/main/java/io/atomix/core/generator/impl/DelegatingAtomicIdGenerator.java +++ b/core/src/main/java/io/atomix/core/generator/impl/DelegatingAtomicIdGenerator.java @@ -18,6 +18,7 @@ import io.atomix.core.counter.AsyncAtomicCounter; import io.atomix.core.generator.AsyncAtomicIdGenerator; import io.atomix.core.generator.AtomicIdGenerator; +import io.atomix.primitive.PrimitiveType; import java.time.Duration; import java.util.concurrent.CompletableFuture; @@ -50,6 +51,11 @@ public String name() { return counter.name(); } + @Override + public PrimitiveType primitiveType() { + return counter.primitiveType(); + } + @Override public synchronized CompletableFuture nextId() { long nextDelta = delta.incrementAndGet(); diff --git a/core/src/main/java/io/atomix/core/generator/impl/DelegatingAtomicIdGeneratorBuilder.java b/core/src/main/java/io/atomix/core/generator/impl/DelegatingAtomicIdGeneratorBuilder.java index 4a968df3a5..3e856bee9c 100644 --- a/core/src/main/java/io/atomix/core/generator/impl/DelegatingAtomicIdGeneratorBuilder.java +++ b/core/src/main/java/io/atomix/core/generator/impl/DelegatingAtomicIdGeneratorBuilder.java @@ -20,6 +20,7 @@ import io.atomix.core.generator.AtomicIdGeneratorBuilder; import io.atomix.core.generator.AtomicIdGeneratorConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; @@ -29,8 +30,8 @@ * Default implementation of AtomicIdGeneratorBuilder. */ public class DelegatingAtomicIdGeneratorBuilder extends AtomicIdGeneratorBuilder { - public DelegatingAtomicIdGeneratorBuilder(String name, AtomicIdGeneratorConfig config, PrimitiveManagementService managementService) { - super(name, config, managementService); + public DelegatingAtomicIdGeneratorBuilder(PrimitiveType type, String name, AtomicIdGeneratorConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/impl/CorePrimitiveManagementService.java b/core/src/main/java/io/atomix/core/impl/CorePrimitiveManagementService.java index b9a0d78b73..0921060747 100644 --- a/core/src/main/java/io/atomix/core/impl/CorePrimitiveManagementService.java +++ b/core/src/main/java/io/atomix/core/impl/CorePrimitiveManagementService.java @@ -16,11 +16,13 @@ package io.atomix.core.impl; import io.atomix.cluster.ClusterMembershipService; -import io.atomix.cluster.messaging.ClusterEventingService; import io.atomix.cluster.messaging.ClusterCommunicationService; +import io.atomix.cluster.messaging.ClusterEventingService; import io.atomix.primitive.PrimitiveManagementService; import io.atomix.primitive.PrimitiveRegistry; +import io.atomix.primitive.PrimitiveTypeRegistry; import io.atomix.primitive.partition.PartitionService; +import io.atomix.primitive.protocol.PrimitiveProtocolTypeRegistry; import java.util.concurrent.ScheduledExecutorService; @@ -34,7 +36,8 @@ public class CorePrimitiveManagementService implements PrimitiveManagementServic private final ClusterEventingService eventService; private final PartitionService partitionService; private final PrimitiveRegistry primitiveRegistry; - private final ClassLoader classLoader; + private final PrimitiveTypeRegistry primitiveTypeRegistry; + private final PrimitiveProtocolTypeRegistry protocolTypeRegistry; public CorePrimitiveManagementService( ScheduledExecutorService executorService, @@ -43,14 +46,16 @@ public CorePrimitiveManagementService( ClusterEventingService eventService, PartitionService partitionService, PrimitiveRegistry primitiveRegistry, - ClassLoader classLoader) { + PrimitiveTypeRegistry primitiveTypeRegistry, + PrimitiveProtocolTypeRegistry protocolTypeRegistry) { this.executorService = executorService; this.membershipService = membershipService; this.communicationService = communicationService; this.eventService = eventService; this.partitionService = partitionService; this.primitiveRegistry = primitiveRegistry; - this.classLoader = classLoader; + this.primitiveTypeRegistry = primitiveTypeRegistry; + this.protocolTypeRegistry = protocolTypeRegistry; } @Override @@ -84,7 +89,12 @@ public PrimitiveRegistry getPrimitiveRegistry() { } @Override - public ClassLoader getClassLoader() { - return classLoader; + public PrimitiveTypeRegistry getPrimitiveTypeRegistry() { + return primitiveTypeRegistry; + } + + @Override + public PrimitiveProtocolTypeRegistry getProtocolTypeRegistry() { + return protocolTypeRegistry; } } diff --git a/core/src/main/java/io/atomix/core/impl/CorePrimitiveRegistry.java b/core/src/main/java/io/atomix/core/impl/CorePrimitiveRegistry.java index c8bd521d15..0b6132e8d3 100644 --- a/core/src/main/java/io/atomix/core/impl/CorePrimitiveRegistry.java +++ b/core/src/main/java/io/atomix/core/impl/CorePrimitiveRegistry.java @@ -15,8 +15,8 @@ */ package io.atomix.core.impl; +import io.atomix.core.PrimitiveTypes; import io.atomix.core.map.AsyncConsistentMap; -import io.atomix.core.map.ConsistentMapType; import io.atomix.core.map.impl.ConsistentMapProxy; import io.atomix.core.map.impl.TranscodingAsyncConsistentMap; import io.atomix.primitive.DistributedPrimitive; @@ -25,7 +25,7 @@ import io.atomix.primitive.PrimitiveInfo; import io.atomix.primitive.PrimitiveRegistry; import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.PrimitiveTypes; +import io.atomix.primitive.PrimitiveTypeRegistry; import io.atomix.primitive.partition.PartitionService; import io.atomix.primitive.protocol.PrimitiveProtocol; import io.atomix.primitive.proxy.PrimitiveProxy; @@ -50,23 +50,23 @@ public class CorePrimitiveRegistry implements ManagedPrimitiveRegistry { private static final Serializer SERIALIZER = Serializer.using(KryoNamespaces.BASIC); private final PartitionService partitionService; - private final ClassLoader classLoader; + private final PrimitiveTypeRegistry primitiveTypeRegistry; private final AtomicBoolean started = new AtomicBoolean(); private AsyncConsistentMap primitives; - public CorePrimitiveRegistry(PartitionService partitionService, ClassLoader classLoader) { + public CorePrimitiveRegistry(PartitionService partitionService, PrimitiveTypeRegistry primitiveTypeRegistry) { this.partitionService = checkNotNull(partitionService); - this.classLoader = checkNotNull(classLoader); + this.primitiveTypeRegistry = checkNotNull(primitiveTypeRegistry); } @Override public CompletableFuture createPrimitive(String name, PrimitiveType type) { PrimitiveInfo info = new PrimitiveInfo(name, type); CompletableFuture future = new CompletableFuture<>(); - primitives.putIfAbsent(name, type.id()).whenComplete((result, error) -> { + primitives.putIfAbsent(name, type.name()).whenComplete((result, error) -> { if (error != null) { future.completeExceptionally(error); - } else if (result == null || result.value().equals(type.id())) { + } else if (result == null || result.value().equals(type.name())) { future.complete(info); } else { future.completeExceptionally(new PrimitiveException("A different primitive with the same name already exists")); @@ -81,7 +81,7 @@ public Collection getPrimitives() { return primitives.entrySet() .get(DistributedPrimitive.DEFAULT_OPERATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS) .stream() - .map(entry -> new PrimitiveInfo(entry.getKey(), PrimitiveTypes.getPrimitiveType(entry.getValue().value(), classLoader))) + .map(entry -> new PrimitiveInfo(entry.getKey(), primitiveTypeRegistry.getPrimitiveType(entry.getValue().value()))) .collect(Collectors.toList()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -105,7 +105,7 @@ public Collection getPrimitives(PrimitiveType primitiveType) { public PrimitiveInfo getPrimitive(String name) { try { return primitives.get(name) - .thenApply(value -> value == null ? null : value.map(type -> new PrimitiveInfo(name, PrimitiveTypes.getPrimitiveType(type, classLoader))).value()) + .thenApply(value -> value == null ? null : value.map(type -> new PrimitiveInfo(name, primitiveTypeRegistry.getPrimitiveType(type))).value()) .get(DistributedPrimitive.DEFAULT_OPERATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -123,7 +123,7 @@ public CompletableFuture start() { PrimitiveProtocol protocol = partitionService.getSystemPartitionGroup().newProtocol(); PrimitiveProxy proxy = protocol.newProxy( "primitives", - ConsistentMapType.instance(), + primitiveTypeRegistry.getPrimitiveType(PrimitiveTypes.consistentMap().name()), new ServiceConfig(), partitionService); return proxy.connect() diff --git a/core/src/main/java/io/atomix/core/impl/CorePrimitivesService.java b/core/src/main/java/io/atomix/core/impl/CorePrimitivesService.java index e9089109cf..cd1f2d0e58 100644 --- a/core/src/main/java/io/atomix/core/impl/CorePrimitivesService.java +++ b/core/src/main/java/io/atomix/core/impl/CorePrimitivesService.java @@ -18,43 +18,31 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import io.atomix.cluster.ClusterMembershipService; -import io.atomix.cluster.messaging.ClusterEventingService; import io.atomix.cluster.messaging.ClusterCommunicationService; +import io.atomix.cluster.messaging.ClusterEventingService; import io.atomix.core.AtomixConfig; import io.atomix.core.ManagedPrimitivesService; +import io.atomix.core.PrimitiveTypes; import io.atomix.core.PrimitivesService; import io.atomix.core.counter.AtomicCounter; -import io.atomix.core.counter.AtomicCounterType; import io.atomix.core.election.LeaderElection; -import io.atomix.core.election.LeaderElectionType; import io.atomix.core.election.LeaderElector; -import io.atomix.core.election.LeaderElectorType; import io.atomix.core.generator.AtomicIdGenerator; -import io.atomix.core.generator.AtomicIdGeneratorType; import io.atomix.core.lock.DistributedLock; -import io.atomix.core.lock.DistributedLockType; import io.atomix.core.map.AtomicCounterMap; -import io.atomix.core.map.AtomicCounterMapType; import io.atomix.core.map.ConsistentMap; -import io.atomix.core.map.ConsistentMapType; import io.atomix.core.map.ConsistentTreeMap; -import io.atomix.core.map.ConsistentTreeMapType; import io.atomix.core.multimap.ConsistentMultimap; -import io.atomix.core.multimap.ConsistentMultimapType; import io.atomix.core.queue.WorkQueue; -import io.atomix.core.queue.WorkQueueType; +import io.atomix.core.registry.RegistryService; import io.atomix.core.semaphore.DistributedSemaphore; -import io.atomix.core.semaphore.DistributedSemaphoreType; import io.atomix.core.set.DistributedSet; -import io.atomix.core.set.DistributedSetType; import io.atomix.core.transaction.ManagedTransactionService; import io.atomix.core.transaction.TransactionBuilder; import io.atomix.core.transaction.TransactionConfig; import io.atomix.core.transaction.impl.DefaultTransactionBuilder; import io.atomix.core.tree.DocumentTree; -import io.atomix.core.tree.DocumentTreeType; import io.atomix.core.value.AtomicValue; -import io.atomix.core.value.AtomicValueType; import io.atomix.primitive.DistributedPrimitive; import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.ManagedPrimitiveRegistry; @@ -97,9 +85,9 @@ public CorePrimitivesService( ClusterCommunicationService communicationService, ClusterEventingService eventService, PartitionService partitionService, - AtomixConfig config, - ClassLoader classLoader) { - this.primitiveRegistry = new CorePrimitiveRegistry(partitionService, classLoader); + RegistryService registryService, + AtomixConfig config) { + this.primitiveRegistry = new CorePrimitiveRegistry(partitionService, registryService.primitiveTypes()); this.managementService = new CorePrimitiveManagementService( executorService, membershipService, @@ -107,7 +95,8 @@ public CorePrimitivesService( eventService, partitionService, primitiveRegistry, - classLoader); + registryService.primitiveTypes(), + registryService.protocolTypes()); this.transactionService = new CoreTransactionService(managementService); this.config = checkNotNull(config); } @@ -119,78 +108,78 @@ public TransactionBuilder transactionBuilder(String name) { @Override public ConsistentMap getConsistentMap(String name) { - return getPrimitive(name, ConsistentMapType.instance(), config.getPrimitive(name)); + return getPrimitive(name, PrimitiveTypes.consistentMap(), config.getPrimitive(name)); } @Override public DocumentTree getDocumentTree(String name) { - return getPrimitive(name, DocumentTreeType.instance(), config.getPrimitive(name)); + return getPrimitive(name, PrimitiveTypes.documentTree(), config.getPrimitive(name)); } @Override public ConsistentTreeMap getTreeMap(String name) { - return getPrimitive(name, ConsistentTreeMapType.instance(), config.getPrimitive(name)); + return getPrimitive(name, PrimitiveTypes.consistentTreeMap(), config.getPrimitive(name)); } @Override public ConsistentMultimap getConsistentMultimap(String name) { - return getPrimitive(name, ConsistentMultimapType.instance(), config.getPrimitive(name)); + return getPrimitive(name, PrimitiveTypes.consistentMultimap(), config.getPrimitive(name)); } @Override public AtomicCounterMap getAtomicCounterMap(String name) { - return getPrimitive(name, AtomicCounterMapType.instance(), config.getPrimitive(name)); + return getPrimitive(name, PrimitiveTypes.atomicCounterMap(), config.getPrimitive(name)); } @Override public DistributedSet getSet(String name) { - return getPrimitive(name, DistributedSetType.instance(), config.getPrimitive(name)); + return getPrimitive(name, PrimitiveTypes.set(), config.getPrimitive(name)); } @Override public AtomicCounter getAtomicCounter(String name) { - return getPrimitive(name, AtomicCounterType.instance(), config.getPrimitive(name)); + return getPrimitive(name, PrimitiveTypes.atomicCounter(), config.getPrimitive(name)); } @Override public AtomicIdGenerator getAtomicIdGenerator(String name) { - return getPrimitive(name, AtomicIdGeneratorType.instance(), config.getPrimitive(name)); + return getPrimitive(name, PrimitiveTypes.atomicIdGenerator(), config.getPrimitive(name)); } @Override public AtomicValue getAtomicValue(String name) { - return getPrimitive(name, AtomicValueType.instance(), config.getPrimitive(name)); + return getPrimitive(name, PrimitiveTypes.atomicValue(), config.getPrimitive(name)); } @Override public LeaderElection getLeaderElection(String name) { - return getPrimitive(name, LeaderElectionType.instance(), config.getPrimitive(name)); + return getPrimitive(name, PrimitiveTypes.leaderElection(), config.getPrimitive(name)); } @Override public LeaderElector getLeaderElector(String name) { - return getPrimitive(name, LeaderElectorType.instance(), config.getPrimitive(name)); + return getPrimitive(name, PrimitiveTypes.leaderElector(), config.getPrimitive(name)); } @Override public DistributedLock getLock(String name) { - return getPrimitive(name, DistributedLockType.instance(), config.getPrimitive(name)); + return getPrimitive(name, PrimitiveTypes.lock(), config.getPrimitive(name)); } @Override public DistributedSemaphore getSemaphore(String name) { - return getPrimitive(name, DistributedSemaphoreType.instance(), config.getPrimitive(name)); + return getPrimitive(name, PrimitiveTypes.semaphore(), config.getPrimitive(name)); } @Override public WorkQueue getWorkQueue(String name) { - return getPrimitive(name, WorkQueueType.instance(), config.getPrimitive(name)); + return getPrimitive(name, PrimitiveTypes.workQueue(), config.getPrimitive(name)); } @Override public , C extends PrimitiveConfig, P extends DistributedPrimitive> B primitiveBuilder( - String name, PrimitiveType primitiveType) { - return primitiveType.newPrimitiveBuilder(name, managementService); + String name, PrimitiveType primitiveType) { + return primitiveType.newBuilder(name, managementService); } @Override @@ -205,25 +194,39 @@ public

P getPrimitive(String name) { PrimitiveConfig primitiveConfig = config.getPrimitive(name); if (primitiveConfig == null) { - primitiveConfig = (PrimitiveConfig) info.type().primitiveConfigClass().newInstance(); + primitiveConfig = info.type().newConfig(); } - return info.type().newPrimitiveBuilder(name, primitiveConfig, managementService).build(); + return info.type().newBuilder(name, primitiveConfig, managementService).build(); }); } catch (ExecutionException e) { throw new AtomixRuntimeException(e); } } + @Override + @SuppressWarnings("unchecked") + public

P getPrimitive(String name, String primitiveType) { + PrimitiveType type = managementService.getPrimitiveTypeRegistry().getPrimitiveType(primitiveType); + return (P) getPrimitive(name, type, type.newConfig()); + } + + @Override + @SuppressWarnings("unchecked") + public

P getPrimitive(String name, String primitiveType, PrimitiveConfig primitiveConfig) { + PrimitiveType type = managementService.getPrimitiveTypeRegistry().getPrimitiveType(primitiveType); + return (P) getPrimitive(name, type, primitiveConfig); + } + @Override @SuppressWarnings("unchecked") public , P extends DistributedPrimitive> P getPrimitive( - String name, PrimitiveType primitiveType, C primitiveConfig) { + String name, PrimitiveType primitiveType, C primitiveConfig) { try { return (P) cache.get(name, () -> { if (primitiveConfig == null) { - return primitiveType.newPrimitiveBuilder(name, managementService).build(); + return primitiveType.newBuilder(name, managementService).build(); } - return primitiveType.newPrimitiveBuilder(name, primitiveConfig, managementService).build(); + return primitiveType.newBuilder(name, primitiveConfig, managementService).build(); }); } catch (ExecutionException e) { throw new AtomixRuntimeException(e); diff --git a/core/src/main/java/io/atomix/core/impl/CoreTransactionService.java b/core/src/main/java/io/atomix/core/impl/CoreTransactionService.java index d56ad9dda5..be70548db1 100644 --- a/core/src/main/java/io/atomix/core/impl/CoreTransactionService.java +++ b/core/src/main/java/io/atomix/core/impl/CoreTransactionService.java @@ -15,8 +15,9 @@ */ package io.atomix.core.impl; +import io.atomix.core.PrimitiveTypes; import io.atomix.core.map.AsyncConsistentMap; -import io.atomix.core.map.ConsistentMapType; +import io.atomix.core.map.ConsistentMapBuilder; import io.atomix.core.transaction.ManagedTransactionService; import io.atomix.core.transaction.TransactionId; import io.atomix.core.transaction.TransactionService; @@ -99,10 +100,12 @@ public CompletableFuture complete(TransactionId transactionId) { } @Override + @SuppressWarnings("unchecked") public CompletableFuture start() { - return ConsistentMapType.instance() - .newPrimitiveBuilder("atomix-transactions", managementService) - .withProtocol(managementService.getPartitionService().getSystemPartitionGroup().newProtocol()) + ConsistentMapBuilder builder = (ConsistentMapBuilder) managementService.getPrimitiveTypeRegistry() + .getPrimitiveType(PrimitiveTypes.consistentMap().name()) + .newBuilder("atomix-transactions", managementService); + return builder.withProtocol(managementService.getPartitionService().getSystemPartitionGroup().newProtocol()) .withSerializer(SERIALIZER) .buildAsync() .thenApply(transactions -> { diff --git a/core/src/main/java/io/atomix/core/lock/AsyncDistributedLock.java b/core/src/main/java/io/atomix/core/lock/AsyncDistributedLock.java index 0b48be77a1..1f0183722c 100644 --- a/core/src/main/java/io/atomix/core/lock/AsyncDistributedLock.java +++ b/core/src/main/java/io/atomix/core/lock/AsyncDistributedLock.java @@ -17,7 +17,6 @@ import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; -import io.atomix.primitive.PrimitiveType; import io.atomix.utils.time.Version; import java.time.Duration; @@ -29,11 +28,6 @@ */ public interface AsyncDistributedLock extends AsyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return DistributedLockType.instance(); - } - /** * Acquires the lock, blocking until it's available. * diff --git a/core/src/main/java/io/atomix/core/lock/DistributedLock.java b/core/src/main/java/io/atomix/core/lock/DistributedLock.java index ae02f4e5b7..db3040a671 100644 --- a/core/src/main/java/io/atomix/core/lock/DistributedLock.java +++ b/core/src/main/java/io/atomix/core/lock/DistributedLock.java @@ -15,7 +15,6 @@ */ package io.atomix.core.lock; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.SyncPrimitive; import io.atomix.utils.time.Version; @@ -27,11 +26,6 @@ */ public interface DistributedLock extends SyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return DistributedLockType.instance(); - } - /** * Acquires the lock, blocking until it's available. * diff --git a/core/src/main/java/io/atomix/core/lock/DistributedLockBuilder.java b/core/src/main/java/io/atomix/core/lock/DistributedLockBuilder.java index 948b663762..09575ba7d0 100644 --- a/core/src/main/java/io/atomix/core/lock/DistributedLockBuilder.java +++ b/core/src/main/java/io/atomix/core/lock/DistributedLockBuilder.java @@ -17,13 +17,14 @@ import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; /** * Builder for AtomicIdGenerator. */ public abstract class DistributedLockBuilder extends DistributedPrimitiveBuilder { - public DistributedLockBuilder(String name, DistributedLockConfig config, PrimitiveManagementService managementService) { - super(DistributedLockType.instance(), name, config, managementService); + public DistributedLockBuilder(PrimitiveType type, String name, DistributedLockConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } } \ No newline at end of file diff --git a/core/src/main/java/io/atomix/core/lock/DistributedLockConfig.java b/core/src/main/java/io/atomix/core/lock/DistributedLockConfig.java index ba984235bc..28a82d4418 100644 --- a/core/src/main/java/io/atomix/core/lock/DistributedLockConfig.java +++ b/core/src/main/java/io/atomix/core/lock/DistributedLockConfig.java @@ -15,13 +15,15 @@ */ package io.atomix.core.lock; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** * Distributed lock configuration. */ public class DistributedLockConfig extends PrimitiveConfig { - public DistributedLockConfig() { - super(DistributedLockType.instance()); + @Override + public String getType() { + return PrimitiveTypes.lock().name(); } } diff --git a/core/src/main/java/io/atomix/core/lock/DistributedLockType.java b/core/src/main/java/io/atomix/core/lock/DistributedLockType.java deleted file mode 100644 index 4bd7523541..0000000000 --- a/core/src/main/java/io/atomix/core/lock/DistributedLockType.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.core.lock; - -import io.atomix.core.lock.impl.DefaultDistributedLockService; -import io.atomix.core.lock.impl.DistributedLockProxyBuilder; -import io.atomix.core.lock.impl.DistributedLockResource; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.resource.PrimitiveResource; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Distributed lock primitive type. - */ -public class DistributedLockType implements PrimitiveType { - private static final String NAME = "lock"; - - /** - * Returns a new distributed lock type. - * - * @return a new distributed lock type - */ - public static DistributedLockType instance() { - return new DistributedLockType(); - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new DefaultDistributedLockService(config); - } - - @Override - @SuppressWarnings("unchecked") - public PrimitiveResource newResource(DistributedLock primitive) { - return new DistributedLockResource(primitive.async()); - } - - @Override - public DistributedLockBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new DistributedLockConfig(), managementService); - } - - @Override - public DistributedLockBuilder newPrimitiveBuilder(String name, DistributedLockConfig config, PrimitiveManagementService managementService) { - return new DistributedLockProxyBuilder(name, config, managementService); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/lock/impl/DefaultDistributedLockService.java b/core/src/main/java/io/atomix/core/lock/impl/DefaultDistributedLockService.java index 8399b45c4c..444be328b2 100644 --- a/core/src/main/java/io/atomix/core/lock/impl/DefaultDistributedLockService.java +++ b/core/src/main/java/io/atomix/core/lock/impl/DefaultDistributedLockService.java @@ -15,7 +15,6 @@ */ package io.atomix.core.lock.impl; -import io.atomix.core.lock.DistributedLockType; import io.atomix.primitive.service.AbstractPrimitiveService; import io.atomix.primitive.service.BackupInput; import io.atomix.primitive.service.BackupOutput; @@ -23,8 +22,6 @@ import io.atomix.primitive.session.PrimitiveSession; import io.atomix.primitive.session.SessionId; import io.atomix.utils.concurrent.Scheduled; -import io.atomix.utils.serializer.KryoNamespace; -import io.atomix.utils.serializer.Serializer; import java.time.Duration; import java.util.ArrayDeque; @@ -38,12 +35,6 @@ * Raft atomic value service. */ public class DefaultDistributedLockService extends AbstractPrimitiveService implements DistributedLockService { - private static final Serializer SERIALIZER = Serializer.using(KryoNamespace.builder() - .register((KryoNamespace) DistributedLockType.instance().namespace()) - .register(LockHolder.class) - .register(SessionId.class) - .build()); - private LockHolder lock; private Queue queue = new ArrayDeque<>(); private final Map timers = new HashMap<>(); @@ -52,11 +43,6 @@ public DefaultDistributedLockService(ServiceConfig config) { super(DistributedLockClient.class, config); } - @Override - public Serializer serializer() { - return SERIALIZER; - } - @Override public void backup(BackupOutput output) { output.writeObject(lock); diff --git a/core/src/main/java/io/atomix/core/lock/impl/DistributedLockProxyBuilder.java b/core/src/main/java/io/atomix/core/lock/impl/DistributedLockProxyBuilder.java index 1fc7aec14f..9faf2ca9ea 100644 --- a/core/src/main/java/io/atomix/core/lock/impl/DistributedLockProxyBuilder.java +++ b/core/src/main/java/io/atomix/core/lock/impl/DistributedLockProxyBuilder.java @@ -20,6 +20,7 @@ import io.atomix.core.lock.DistributedLockBuilder; import io.atomix.core.lock.DistributedLockConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; @@ -29,8 +30,8 @@ * Default distributed lock builder implementation. */ public class DistributedLockProxyBuilder extends DistributedLockBuilder { - public DistributedLockProxyBuilder(String name, DistributedLockConfig config, PrimitiveManagementService managementService) { - super(name, config, managementService); + public DistributedLockProxyBuilder(PrimitiveType type, String name, DistributedLockConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/map/AsyncAtomicCounterMap.java b/core/src/main/java/io/atomix/core/map/AsyncAtomicCounterMap.java index fdf3587ba1..6983174a4d 100644 --- a/core/src/main/java/io/atomix/core/map/AsyncAtomicCounterMap.java +++ b/core/src/main/java/io/atomix/core/map/AsyncAtomicCounterMap.java @@ -17,7 +17,6 @@ import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; -import io.atomix.primitive.PrimitiveType; import java.time.Duration; import java.util.concurrent.CompletableFuture; @@ -27,11 +26,6 @@ */ public interface AsyncAtomicCounterMap extends AsyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return AtomicCounterMapType.instance(); - } - /** * Increments by one the value currently associated with key, and returns the new value. * diff --git a/core/src/main/java/io/atomix/core/map/AsyncConsistentMap.java b/core/src/main/java/io/atomix/core/map/AsyncConsistentMap.java index 75e3a97177..9292cc9e72 100644 --- a/core/src/main/java/io/atomix/core/map/AsyncConsistentMap.java +++ b/core/src/main/java/io/atomix/core/map/AsyncConsistentMap.java @@ -21,7 +21,6 @@ import io.atomix.core.transaction.Transactional; import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; -import io.atomix.primitive.PrimitiveType; import io.atomix.utils.time.Versioned; import java.time.Duration; @@ -62,11 +61,6 @@ */ public interface AsyncConsistentMap extends AsyncPrimitive, Transactional> { - @Override - default PrimitiveType primitiveType() { - return ConsistentMapType.instance(); - } - @Override default CompletableFuture delete() { return clear(); diff --git a/core/src/main/java/io/atomix/core/map/AsyncConsistentTreeMap.java b/core/src/main/java/io/atomix/core/map/AsyncConsistentTreeMap.java index baf3304b15..5d383893fe 100644 --- a/core/src/main/java/io/atomix/core/map/AsyncConsistentTreeMap.java +++ b/core/src/main/java/io/atomix/core/map/AsyncConsistentTreeMap.java @@ -17,7 +17,6 @@ package io.atomix.core.map; import io.atomix.primitive.DistributedPrimitive; -import io.atomix.primitive.PrimitiveType; import io.atomix.utils.time.Versioned; import java.time.Duration; @@ -31,11 +30,6 @@ */ public interface AsyncConsistentTreeMap extends AsyncConsistentMap { - @Override - default PrimitiveType primitiveType() { - return ConsistentTreeMapType.instance(); - } - /** * Return the lowest key in the map. * diff --git a/core/src/main/java/io/atomix/core/map/AtomicCounterMap.java b/core/src/main/java/io/atomix/core/map/AtomicCounterMap.java index 87a4350b25..cf034eeee5 100644 --- a/core/src/main/java/io/atomix/core/map/AtomicCounterMap.java +++ b/core/src/main/java/io/atomix/core/map/AtomicCounterMap.java @@ -15,7 +15,6 @@ */ package io.atomix.core.map; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.SyncPrimitive; /** @@ -23,11 +22,6 @@ */ public interface AtomicCounterMap extends SyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return AtomicCounterMapType.instance(); - } - /** * Increments by one the value currently associated with key, and returns the new value. * diff --git a/core/src/main/java/io/atomix/core/map/AtomicCounterMapBuilder.java b/core/src/main/java/io/atomix/core/map/AtomicCounterMapBuilder.java index 304dc64629..97eda2e65b 100644 --- a/core/src/main/java/io/atomix/core/map/AtomicCounterMapBuilder.java +++ b/core/src/main/java/io/atomix/core/map/AtomicCounterMapBuilder.java @@ -17,13 +17,14 @@ import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; /** * Builder for AtomicCounterMap. */ public abstract class AtomicCounterMapBuilder extends DistributedPrimitiveBuilder, AtomicCounterMapConfig, AtomicCounterMap> { - public AtomicCounterMapBuilder(String name, AtomicCounterMapConfig config, PrimitiveManagementService managementService) { - super(AtomicCounterMapType.instance(), name, config, managementService); + public AtomicCounterMapBuilder(PrimitiveType type, String name, AtomicCounterMapConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } } diff --git a/core/src/main/java/io/atomix/core/map/AtomicCounterMapConfig.java b/core/src/main/java/io/atomix/core/map/AtomicCounterMapConfig.java index 62de73fc95..be60b074d7 100644 --- a/core/src/main/java/io/atomix/core/map/AtomicCounterMapConfig.java +++ b/core/src/main/java/io/atomix/core/map/AtomicCounterMapConfig.java @@ -15,13 +15,15 @@ */ package io.atomix.core.map; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** * Atomic counter map configuration. */ public class AtomicCounterMapConfig extends PrimitiveConfig { - public AtomicCounterMapConfig() { - super(AtomicCounterMapType.instance()); + @Override + public String getType() { + return PrimitiveTypes.atomicCounterMap().name(); } } diff --git a/core/src/main/java/io/atomix/core/map/AtomicCounterMapType.java b/core/src/main/java/io/atomix/core/map/AtomicCounterMapType.java deleted file mode 100644 index f9f554a119..0000000000 --- a/core/src/main/java/io/atomix/core/map/AtomicCounterMapType.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.core.map; - -import io.atomix.core.map.impl.AtomicCounterMapProxyBuilder; -import io.atomix.core.map.impl.AtomicCounterMapService; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Atomic counter map primitive type. - */ -public class AtomicCounterMapType implements PrimitiveType, AtomicCounterMapConfig, AtomicCounterMap, ServiceConfig> { - private static final String NAME = "counter-map"; - - /** - * Returns a new atomic counter map type. - * - * @param the key type - * @return a new atomic counter map type - */ - public static AtomicCounterMapType instance() { - return new AtomicCounterMapType<>(); - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new AtomicCounterMapService(config); - } - - @Override - public AtomicCounterMapBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new AtomicCounterMapConfig(), managementService); - } - - @Override - public AtomicCounterMapBuilder newPrimitiveBuilder(String name, AtomicCounterMapConfig config, PrimitiveManagementService managementService) { - return new AtomicCounterMapProxyBuilder<>(name, config, managementService); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/map/ConsistentMap.java b/core/src/main/java/io/atomix/core/map/ConsistentMap.java index 18790bebb9..e75e2d663c 100644 --- a/core/src/main/java/io/atomix/core/map/ConsistentMap.java +++ b/core/src/main/java/io/atomix/core/map/ConsistentMap.java @@ -17,7 +17,6 @@ package io.atomix.core.map; import com.google.common.util.concurrent.MoreExecutors; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.SyncPrimitive; import io.atomix.utils.time.Versioned; @@ -40,11 +39,6 @@ */ public interface ConsistentMap extends SyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return ConsistentMapType.instance(); - } - /** * Returns the number of entries in the map. * diff --git a/core/src/main/java/io/atomix/core/map/ConsistentMapBuilder.java b/core/src/main/java/io/atomix/core/map/ConsistentMapBuilder.java index 8917036a31..a7c4f2c600 100644 --- a/core/src/main/java/io/atomix/core/map/ConsistentMapBuilder.java +++ b/core/src/main/java/io/atomix/core/map/ConsistentMapBuilder.java @@ -17,6 +17,7 @@ import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; /** * Builder for {@link ConsistentMap} instances. @@ -27,8 +28,8 @@ public abstract class ConsistentMapBuilder extends DistributedPrimitiveBuilder, ConsistentMapConfig, ConsistentMap> { - public ConsistentMapBuilder(String name, ConsistentMapConfig config, PrimitiveManagementService managementService) { - super(ConsistentMapType.instance(), name, config, managementService); + public ConsistentMapBuilder(PrimitiveType type, String name, ConsistentMapConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } /** diff --git a/core/src/main/java/io/atomix/core/map/ConsistentMapConfig.java b/core/src/main/java/io/atomix/core/map/ConsistentMapConfig.java index 69b7f8a0c4..2779584845 100644 --- a/core/src/main/java/io/atomix/core/map/ConsistentMapConfig.java +++ b/core/src/main/java/io/atomix/core/map/ConsistentMapConfig.java @@ -15,6 +15,7 @@ */ package io.atomix.core.map; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** @@ -23,8 +24,9 @@ public class ConsistentMapConfig extends PrimitiveConfig { private boolean nullValues = false; - public ConsistentMapConfig() { - super(ConsistentMapType.instance()); + @Override + public String getType() { + return PrimitiveTypes.consistentMap().name(); } /** diff --git a/core/src/main/java/io/atomix/core/map/ConsistentMapType.java b/core/src/main/java/io/atomix/core/map/ConsistentMapType.java deleted file mode 100644 index da6f9ff2ad..0000000000 --- a/core/src/main/java/io/atomix/core/map/ConsistentMapType.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.core.map; - -import io.atomix.core.map.impl.ConsistentMapProxyBuilder; -import io.atomix.core.map.impl.ConsistentMapResource; -import io.atomix.core.map.impl.ConsistentMapService; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.resource.PrimitiveResource; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Consistent map primitive type. - */ -public class ConsistentMapType implements PrimitiveType, ConsistentMapConfig, ConsistentMap, ServiceConfig> { - private static final String NAME = "consistent-map"; - - /** - * Returns a new consistent map type. - * - * @param the key type - * @param the value type - * @return a new consistent map type - */ - public static ConsistentMapType instance() { - return new ConsistentMapType<>(); - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new ConsistentMapService(config); - } - - @Override - @SuppressWarnings("unchecked") - public PrimitiveResource newResource(ConsistentMap primitive) { - return new ConsistentMapResource((AsyncConsistentMap) primitive.async()); - } - - @Override - public ConsistentMapBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new ConsistentMapConfig(), managementService); - } - - @Override - public ConsistentMapBuilder newPrimitiveBuilder(String name, ConsistentMapConfig config, PrimitiveManagementService managementService) { - return new ConsistentMapProxyBuilder<>(name, config, managementService); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/map/ConsistentTreeMap.java b/core/src/main/java/io/atomix/core/map/ConsistentTreeMap.java index bab3115468..0b8f9befe4 100644 --- a/core/src/main/java/io/atomix/core/map/ConsistentTreeMap.java +++ b/core/src/main/java/io/atomix/core/map/ConsistentTreeMap.java @@ -16,7 +16,6 @@ package io.atomix.core.map; -import io.atomix.primitive.PrimitiveType; import io.atomix.utils.time.Versioned; import java.util.Map; @@ -28,11 +27,6 @@ */ public interface ConsistentTreeMap extends ConsistentMap { - @Override - default PrimitiveType primitiveType() { - return ConsistentTreeMapType.instance(); - } - /** * Returns the lowest key in the map. * diff --git a/core/src/main/java/io/atomix/core/map/ConsistentTreeMapBuilder.java b/core/src/main/java/io/atomix/core/map/ConsistentTreeMapBuilder.java index 9f4bdc22d6..d9a54b57d6 100644 --- a/core/src/main/java/io/atomix/core/map/ConsistentTreeMapBuilder.java +++ b/core/src/main/java/io/atomix/core/map/ConsistentTreeMapBuilder.java @@ -18,13 +18,14 @@ import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; /** * Builder for {@link ConsistentTreeMap}. */ public abstract class ConsistentTreeMapBuilder extends DistributedPrimitiveBuilder, ConsistentTreeMapConfig, ConsistentTreeMap> { - public ConsistentTreeMapBuilder(String name, ConsistentTreeMapConfig config, PrimitiveManagementService managementService) { - super(ConsistentTreeMapType.instance(), name, config, managementService); + public ConsistentTreeMapBuilder(PrimitiveType type, String name, ConsistentTreeMapConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } } diff --git a/core/src/main/java/io/atomix/core/map/ConsistentTreeMapConfig.java b/core/src/main/java/io/atomix/core/map/ConsistentTreeMapConfig.java index ed8156dcaf..f0f4c49447 100644 --- a/core/src/main/java/io/atomix/core/map/ConsistentTreeMapConfig.java +++ b/core/src/main/java/io/atomix/core/map/ConsistentTreeMapConfig.java @@ -15,13 +15,15 @@ */ package io.atomix.core.map; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** * Consistent tree-map configuration. */ public class ConsistentTreeMapConfig extends PrimitiveConfig { - public ConsistentTreeMapConfig() { - super(ConsistentTreeMapType.instance()); + @Override + public String getType() { + return PrimitiveTypes.consistentTreeMap().name(); } } diff --git a/core/src/main/java/io/atomix/core/map/ConsistentTreeMapType.java b/core/src/main/java/io/atomix/core/map/ConsistentTreeMapType.java deleted file mode 100644 index 999981e669..0000000000 --- a/core/src/main/java/io/atomix/core/map/ConsistentTreeMapType.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.core.map; - -import io.atomix.core.map.impl.ConsistentTreeMapProxyBuilder; -import io.atomix.core.map.impl.ConsistentTreeMapService; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Consistent tree map primitive type. - */ -public class ConsistentTreeMapType - implements PrimitiveType, ConsistentTreeMapConfig, ConsistentTreeMap, ServiceConfig> { - private static final String NAME = "consistent-tree-map"; - - /** - * Returns a new consistent tree map type. - * - * @param the value type - * @return a new consistent tree map type - */ - public static ConsistentTreeMapType instance() { - return new ConsistentTreeMapType<>(); - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new ConsistentTreeMapService(config); - } - - @Override - public ConsistentTreeMapBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new ConsistentTreeMapConfig(), managementService); - } - - @Override - public ConsistentTreeMapBuilder newPrimitiveBuilder(String name, ConsistentTreeMapConfig config, PrimitiveManagementService managementService) { - return new ConsistentTreeMapProxyBuilder<>(name, config, managementService); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/map/impl/AtomicCounterMapProxyBuilder.java b/core/src/main/java/io/atomix/core/map/impl/AtomicCounterMapProxyBuilder.java index e39ebe2f78..3766f1a002 100644 --- a/core/src/main/java/io/atomix/core/map/impl/AtomicCounterMapProxyBuilder.java +++ b/core/src/main/java/io/atomix/core/map/impl/AtomicCounterMapProxyBuilder.java @@ -20,6 +20,7 @@ import io.atomix.core.map.AtomicCounterMapBuilder; import io.atomix.core.map.AtomicCounterMapConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; import io.atomix.utils.serializer.Serializer; @@ -30,8 +31,8 @@ * Default {@code AtomicCounterMapBuilder}. */ public class AtomicCounterMapProxyBuilder extends AtomicCounterMapBuilder { - public AtomicCounterMapProxyBuilder(String name, AtomicCounterMapConfig config, PrimitiveManagementService managementService) { - super(name, config, managementService); + public AtomicCounterMapProxyBuilder(PrimitiveType type, String name, AtomicCounterMapConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/map/impl/ConsistentMapProxyBuilder.java b/core/src/main/java/io/atomix/core/map/impl/ConsistentMapProxyBuilder.java index cdaf3c1696..70b59ee3d9 100644 --- a/core/src/main/java/io/atomix/core/map/impl/ConsistentMapProxyBuilder.java +++ b/core/src/main/java/io/atomix/core/map/impl/ConsistentMapProxyBuilder.java @@ -21,6 +21,7 @@ import io.atomix.core.map.ConsistentMapBuilder; import io.atomix.core.map.ConsistentMapConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; import io.atomix.utils.serializer.Serializer; @@ -34,8 +35,8 @@ * @param type for map value */ public class ConsistentMapProxyBuilder extends ConsistentMapBuilder { - public ConsistentMapProxyBuilder(String name, ConsistentMapConfig config, PrimitiveManagementService managementService) { - super(name, config, managementService); + public ConsistentMapProxyBuilder(PrimitiveType type, String name, ConsistentMapConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/map/impl/ConsistentTreeMapProxyBuilder.java b/core/src/main/java/io/atomix/core/map/impl/ConsistentTreeMapProxyBuilder.java index 486f2a8c90..32ef41dc6e 100644 --- a/core/src/main/java/io/atomix/core/map/impl/ConsistentTreeMapProxyBuilder.java +++ b/core/src/main/java/io/atomix/core/map/impl/ConsistentTreeMapProxyBuilder.java @@ -20,6 +20,7 @@ import io.atomix.core.map.ConsistentTreeMapBuilder; import io.atomix.core.map.ConsistentTreeMapConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; import io.atomix.utils.serializer.Serializer; @@ -32,8 +33,8 @@ * @param type for map value */ public class ConsistentTreeMapProxyBuilder extends ConsistentTreeMapBuilder { - public ConsistentTreeMapProxyBuilder(String name, ConsistentTreeMapConfig config, PrimitiveManagementService managementService) { - super(name, config, managementService); + public ConsistentTreeMapProxyBuilder(PrimitiveType type, String name, ConsistentTreeMapConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/map/impl/DelegatingAsyncConsistentMap.java b/core/src/main/java/io/atomix/core/map/impl/DelegatingAsyncConsistentMap.java index 53f31fca21..ca9ca11639 100644 --- a/core/src/main/java/io/atomix/core/map/impl/DelegatingAsyncConsistentMap.java +++ b/core/src/main/java/io/atomix/core/map/impl/DelegatingAsyncConsistentMap.java @@ -23,7 +23,7 @@ import io.atomix.core.map.MapEventListener; import io.atomix.core.transaction.TransactionId; import io.atomix.core.transaction.TransactionLog; -import io.atomix.primitive.impl.DelegatingAsyncPrimitive; +import io.atomix.primitive.DelegatingAsyncPrimitive; import io.atomix.utils.time.Versioned; import java.time.Duration; diff --git a/core/src/main/java/io/atomix/core/map/impl/DelegatingAsyncConsistentTreeMap.java b/core/src/main/java/io/atomix/core/map/impl/DelegatingAsyncConsistentTreeMap.java index 0889c1e747..43cddaca04 100644 --- a/core/src/main/java/io/atomix/core/map/impl/DelegatingAsyncConsistentTreeMap.java +++ b/core/src/main/java/io/atomix/core/map/impl/DelegatingAsyncConsistentTreeMap.java @@ -21,7 +21,7 @@ import io.atomix.core.map.MapEventListener; import io.atomix.core.transaction.TransactionId; import io.atomix.core.transaction.TransactionLog; -import io.atomix.primitive.impl.DelegatingAsyncPrimitive; +import io.atomix.primitive.DelegatingAsyncPrimitive; import io.atomix.utils.time.Versioned; import java.time.Duration; diff --git a/core/src/main/java/io/atomix/core/map/impl/TranscodingAsyncAtomicCounterMap.java b/core/src/main/java/io/atomix/core/map/impl/TranscodingAsyncAtomicCounterMap.java index 003767a26e..db5034a511 100644 --- a/core/src/main/java/io/atomix/core/map/impl/TranscodingAsyncAtomicCounterMap.java +++ b/core/src/main/java/io/atomix/core/map/impl/TranscodingAsyncAtomicCounterMap.java @@ -17,6 +17,7 @@ import io.atomix.core.map.AsyncAtomicCounterMap; import io.atomix.core.map.AtomicCounterMap; +import io.atomix.primitive.PrimitiveType; import io.atomix.utils.concurrent.Futures; import java.time.Duration; @@ -43,6 +44,11 @@ public String name() { return backingMap.name(); } + @Override + public PrimitiveType primitiveType() { + return backingMap.primitiveType(); + } + @Override public CompletableFuture incrementAndGet(K1 key) { try { diff --git a/core/src/main/java/io/atomix/core/map/impl/TranscodingAsyncConsistentMap.java b/core/src/main/java/io/atomix/core/map/impl/TranscodingAsyncConsistentMap.java index fcf0e75afe..eb5b9d2092 100644 --- a/core/src/main/java/io/atomix/core/map/impl/TranscodingAsyncConsistentMap.java +++ b/core/src/main/java/io/atomix/core/map/impl/TranscodingAsyncConsistentMap.java @@ -18,13 +18,13 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; - import io.atomix.core.map.AsyncConsistentMap; import io.atomix.core.map.ConsistentMap; import io.atomix.core.map.MapEvent; import io.atomix.core.map.MapEventListener; import io.atomix.core.transaction.TransactionId; import io.atomix.core.transaction.TransactionLog; +import io.atomix.primitive.PrimitiveType; import io.atomix.utils.concurrent.Futures; import io.atomix.utils.time.Versioned; @@ -80,6 +80,11 @@ public String name() { return backingMap.name(); } + @Override + public PrimitiveType primitiveType() { + return backingMap.primitiveType(); + } + @Override public CompletableFuture size() { return backingMap.size(); diff --git a/core/src/main/java/io/atomix/core/map/impl/TranscodingAsyncConsistentTreeMap.java b/core/src/main/java/io/atomix/core/map/impl/TranscodingAsyncConsistentTreeMap.java index 3ce45070a9..e6b6abd217 100644 --- a/core/src/main/java/io/atomix/core/map/impl/TranscodingAsyncConsistentTreeMap.java +++ b/core/src/main/java/io/atomix/core/map/impl/TranscodingAsyncConsistentTreeMap.java @@ -23,6 +23,7 @@ import io.atomix.core.map.MapEventListener; import io.atomix.core.transaction.TransactionId; import io.atomix.core.transaction.TransactionLog; +import io.atomix.primitive.PrimitiveType; import io.atomix.utils.concurrent.Futures; import io.atomix.utils.time.Versioned; @@ -64,6 +65,11 @@ public TranscodingAsyncConsistentTreeMap( this.versionedValueTransform = v -> v == null ? null : v.map(valueDecoder); } + @Override + public PrimitiveType primitiveType() { + return backingMap.primitiveType(); + } + @Override public CompletableFuture firstKey() { return backingMap.firstKey(); diff --git a/core/src/main/java/io/atomix/core/multimap/AsyncConsistentMultimap.java b/core/src/main/java/io/atomix/core/multimap/AsyncConsistentMultimap.java index b4e8b33911..3062456401 100644 --- a/core/src/main/java/io/atomix/core/multimap/AsyncConsistentMultimap.java +++ b/core/src/main/java/io/atomix/core/multimap/AsyncConsistentMultimap.java @@ -20,7 +20,6 @@ import com.google.common.util.concurrent.MoreExecutors; import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; -import io.atomix.primitive.PrimitiveType; import io.atomix.utils.time.Versioned; import java.time.Duration; @@ -40,11 +39,6 @@ */ public interface AsyncConsistentMultimap extends AsyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return ConsistentMultimapType.instance(); - } - @Override default CompletableFuture delete() { return clear(); diff --git a/core/src/main/java/io/atomix/core/multimap/ConsistentMultimap.java b/core/src/main/java/io/atomix/core/multimap/ConsistentMultimap.java index 5dd84cc1f2..cb8619b762 100644 --- a/core/src/main/java/io/atomix/core/multimap/ConsistentMultimap.java +++ b/core/src/main/java/io/atomix/core/multimap/ConsistentMultimap.java @@ -18,7 +18,6 @@ import com.google.common.collect.Multiset; import com.google.common.util.concurrent.MoreExecutors; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.SyncPrimitive; import io.atomix.utils.time.Versioned; @@ -34,11 +33,6 @@ */ public interface ConsistentMultimap extends SyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return ConsistentMultimapType.instance(); - } - /** * Returns the number of key-value pairs in this multimap. * diff --git a/core/src/main/java/io/atomix/core/multimap/ConsistentMultimapBuilder.java b/core/src/main/java/io/atomix/core/multimap/ConsistentMultimapBuilder.java index 161c6ea8ed..1fe5f5712c 100644 --- a/core/src/main/java/io/atomix/core/multimap/ConsistentMultimapBuilder.java +++ b/core/src/main/java/io/atomix/core/multimap/ConsistentMultimapBuilder.java @@ -18,13 +18,14 @@ import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; /** * A builder class for {@code AsyncConsistentMultimap}. */ public abstract class ConsistentMultimapBuilder extends DistributedPrimitiveBuilder, ConsistentMultimapConfig, ConsistentMultimap> { - public ConsistentMultimapBuilder(String name, ConsistentMultimapConfig config, PrimitiveManagementService managementService) { - super(ConsistentMultimapType.instance(), name, config, managementService); + public ConsistentMultimapBuilder(PrimitiveType type, String name, ConsistentMultimapConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } } diff --git a/core/src/main/java/io/atomix/core/multimap/ConsistentMultimapConfig.java b/core/src/main/java/io/atomix/core/multimap/ConsistentMultimapConfig.java index 3ee1f775e6..3ded97004a 100644 --- a/core/src/main/java/io/atomix/core/multimap/ConsistentMultimapConfig.java +++ b/core/src/main/java/io/atomix/core/multimap/ConsistentMultimapConfig.java @@ -15,13 +15,15 @@ */ package io.atomix.core.multimap; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** * Consistent multimap configuration. */ public class ConsistentMultimapConfig extends PrimitiveConfig { - public ConsistentMultimapConfig() { - super(ConsistentMultimapType.instance()); + @Override + public String getType() { + return PrimitiveTypes.consistentMultimap().name(); } } diff --git a/core/src/main/java/io/atomix/core/multimap/ConsistentMultimapType.java b/core/src/main/java/io/atomix/core/multimap/ConsistentMultimapType.java deleted file mode 100644 index 83c4d4bbea..0000000000 --- a/core/src/main/java/io/atomix/core/multimap/ConsistentMultimapType.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.core.multimap; - -import io.atomix.core.multimap.impl.ConsistentMultimapProxyBuilder; -import io.atomix.core.multimap.impl.ConsistentSetMultimapService; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Consistent multimap primitive type. - */ -public class ConsistentMultimapType implements PrimitiveType, ConsistentMultimapConfig, ConsistentMultimap, ServiceConfig> { - private static final String NAME = "consistent-multimap"; - - /** - * Returns a new consistent multimap type. - * - * @param the key type - * @param the value type - * @return a new consistent multimap type - */ - public static ConsistentMultimapType instance() { - return new ConsistentMultimapType<>(); - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new ConsistentSetMultimapService(config); - } - - @Override - public ConsistentMultimapBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new ConsistentMultimapConfig(), managementService); - } - - @Override - public ConsistentMultimapBuilder newPrimitiveBuilder(String name, ConsistentMultimapConfig config, PrimitiveManagementService managementService) { - return new ConsistentMultimapProxyBuilder<>(name, config, managementService); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/multimap/impl/ConsistentMultimapProxyBuilder.java b/core/src/main/java/io/atomix/core/multimap/impl/ConsistentMultimapProxyBuilder.java index 22419a96ac..37b47dcc0c 100644 --- a/core/src/main/java/io/atomix/core/multimap/impl/ConsistentMultimapProxyBuilder.java +++ b/core/src/main/java/io/atomix/core/multimap/impl/ConsistentMultimapProxyBuilder.java @@ -22,6 +22,7 @@ import io.atomix.core.multimap.ConsistentMultimapBuilder; import io.atomix.core.multimap.ConsistentMultimapConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; import io.atomix.utils.serializer.Serializer; @@ -32,8 +33,8 @@ * Default {@link AsyncConsistentMultimap} builder. */ public class ConsistentMultimapProxyBuilder extends ConsistentMultimapBuilder { - public ConsistentMultimapProxyBuilder(String name, ConsistentMultimapConfig config, PrimitiveManagementService managementService) { - super(name, config, managementService); + public ConsistentMultimapProxyBuilder(PrimitiveType type, String name, ConsistentMultimapConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/multimap/impl/DelegatingAsyncConsistentMultimap.java b/core/src/main/java/io/atomix/core/multimap/impl/DelegatingAsyncConsistentMultimap.java index a57785fc50..feb1ec96e4 100644 --- a/core/src/main/java/io/atomix/core/multimap/impl/DelegatingAsyncConsistentMultimap.java +++ b/core/src/main/java/io/atomix/core/multimap/impl/DelegatingAsyncConsistentMultimap.java @@ -21,7 +21,7 @@ import io.atomix.core.multimap.AsyncConsistentMultimap; import io.atomix.core.multimap.ConsistentMultimap; import io.atomix.core.multimap.MultimapEventListener; -import io.atomix.primitive.impl.DelegatingAsyncPrimitive; +import io.atomix.primitive.DelegatingAsyncPrimitive; import io.atomix.utils.time.Versioned; import java.time.Duration; diff --git a/core/src/main/java/io/atomix/core/multimap/impl/TranscodingAsyncConsistentMultimap.java b/core/src/main/java/io/atomix/core/multimap/impl/TranscodingAsyncConsistentMultimap.java index 5ae4bcdc4a..0d0ad3285e 100644 --- a/core/src/main/java/io/atomix/core/multimap/impl/TranscodingAsyncConsistentMultimap.java +++ b/core/src/main/java/io/atomix/core/multimap/impl/TranscodingAsyncConsistentMultimap.java @@ -19,11 +19,11 @@ import com.google.common.collect.ImmutableMultiset; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; - import io.atomix.core.multimap.AsyncConsistentMultimap; import io.atomix.core.multimap.ConsistentMultimap; import io.atomix.core.multimap.MultimapEvent; import io.atomix.core.multimap.MultimapEventListener; +import io.atomix.primitive.PrimitiveType; import io.atomix.utils.concurrent.Futures; import io.atomix.utils.time.Versioned; @@ -93,6 +93,11 @@ public TranscodingAsyncConsistentMultimap( v.stream().map(valueEncoder).collect(Collectors.toSet()); } + @Override + public PrimitiveType primitiveType() { + return backingMap.primitiveType(); + } + @Override public CompletableFuture size() { return backingMap.size(); diff --git a/core/src/main/java/io/atomix/core/profile/ClientProfile.java b/core/src/main/java/io/atomix/core/profile/ClientProfile.java index 8e0879b52a..29477788fc 100644 --- a/core/src/main/java/io/atomix/core/profile/ClientProfile.java +++ b/core/src/main/java/io/atomix/core/profile/ClientProfile.java @@ -20,14 +20,7 @@ /** * Client profile. */ -public class ClientProfile implements NamedProfile { - private static final String NAME = "client"; - - @Override - public String name() { - return NAME; - } - +public class ClientProfile implements Profile { @Override public void configure(AtomixConfig config) { // Do nothing! This profile is just for code readability. diff --git a/core/src/main/java/io/atomix/core/profile/ConsensusProfile.java b/core/src/main/java/io/atomix/core/profile/ConsensusProfile.java index 490af690db..552f174c89 100644 --- a/core/src/main/java/io/atomix/core/profile/ConsensusProfile.java +++ b/core/src/main/java/io/atomix/core/profile/ConsensusProfile.java @@ -24,20 +24,13 @@ /** * Consensus profile. */ -public class ConsensusProfile implements NamedProfile { - private static final String NAME = "consensus"; - +public class ConsensusProfile implements Profile { private static final String DATA_PATH = ".data"; private static final String SYSTEM_GROUP_NAME = "system"; private static final String GROUP_NAME = "raft"; private static final int PARTITION_SIZE = 3; private static final int NUM_PARTITIONS = 7; - @Override - public String name() { - return NAME; - } - @Override public void configure(AtomixConfig config) { config.setManagementGroup(new RaftPartitionGroupConfig() diff --git a/core/src/main/java/io/atomix/core/profile/DataGridProfile.java b/core/src/main/java/io/atomix/core/profile/DataGridProfile.java index bda515f23d..930561f292 100644 --- a/core/src/main/java/io/atomix/core/profile/DataGridProfile.java +++ b/core/src/main/java/io/atomix/core/profile/DataGridProfile.java @@ -22,18 +22,11 @@ /** * In-memory data grid profile. */ -public class DataGridProfile implements NamedProfile { - private static final String NAME = "data-grid"; - +public class DataGridProfile implements Profile { private static final String SYSTEM_GROUP_NAME = "system"; private static final String GROUP_NAME = "data"; private static final int NUM_PARTITIONS = 71; - @Override - public String name() { - return NAME; - } - @Override public void configure(AtomixConfig config) { if (config.getManagementGroup() == null) { diff --git a/core/src/main/java/io/atomix/core/profile/Profile.java b/core/src/main/java/io/atomix/core/profile/Profile.java index 605a5d95d5..22ec6167b2 100644 --- a/core/src/main/java/io/atomix/core/profile/Profile.java +++ b/core/src/main/java/io/atomix/core/profile/Profile.java @@ -25,18 +25,18 @@ public interface Profile { /** * The consensus profile configures an Atomix instance with a Raft system partition and a multi-Raft data partition group. */ - ConsensusProfile CONSENSUS = new ConsensusProfile(); + Profile CONSENSUS = new ConsensusProfile(); /** * The data grid profile configures an Atomix instance with a primary-backup system partition if no system partition * is configured, and a primary-backup data partition group. */ - DataGridProfile DATA_GRID = new DataGridProfile(); + Profile DATA_GRID = new DataGridProfile(); /** * The client profile does not change the configuration of a node. It is intended only for code clarity. */ - ClientProfile CLIENT = new ClientProfile(); + Profile CLIENT = new ClientProfile(); /** * Configures the Atomix instance. diff --git a/core/src/main/java/io/atomix/core/profile/ProfileType.java b/core/src/main/java/io/atomix/core/profile/ProfileType.java new file mode 100644 index 0000000000..88abf53b6d --- /dev/null +++ b/core/src/main/java/io/atomix/core/profile/ProfileType.java @@ -0,0 +1,64 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.core.profile; + +import io.atomix.utils.AbstractNamed; +import io.atomix.utils.Type; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Profile type configuration. + */ +public class ProfileType extends AbstractNamed implements Type { + private Class profileClass; + + public ProfileType() { + } + + public ProfileType(String name, Class profileClass) { + super(name); + this.profileClass = profileClass; + } + + /** + * Returns the profile class. + * + * @return the profile class + */ + public Class profileClass() { + return profileClass; + } + + @Override + public int hashCode() { + return Objects.hash(name()); + } + + @Override + public boolean equals(Object object) { + return object instanceof ProfileType && Objects.equals(((ProfileType) object).name(), name()); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("name", name()) + .toString(); + } +} diff --git a/core/src/main/java/io/atomix/core/profile/Profiles.java b/core/src/main/java/io/atomix/core/profile/Profiles.java deleted file mode 100644 index 199e9e7d13..0000000000 --- a/core/src/main/java/io/atomix/core/profile/Profiles.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2018-present Open Networking Foundation - * - * 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.atomix.core.profile; - -import io.atomix.utils.Services; -import io.atomix.utils.config.ConfigurationException; - -/** - * Atomix profiles. - */ -public final class Profiles { - - /** - * Returns the Atomix profile for the given name - * - * @param profileName the name for which to return the Atomix profile - * @return the Atomix profile for the given name - */ - public static NamedProfile getNamedProfile(String profileName) { - for (NamedProfile type : Services.loadAll(NamedProfile.class, Thread.currentThread().getContextClassLoader())) { - if (type.name().replace("_", "-").equalsIgnoreCase(profileName.replace("_", "-"))) { - return type; - } - } - throw new ConfigurationException("Unknown Atomix profile: " + profileName); - } - - private Profiles() { - } -} diff --git a/core/src/main/java/io/atomix/core/queue/AsyncWorkQueue.java b/core/src/main/java/io/atomix/core/queue/AsyncWorkQueue.java index cba74cc41d..894342aa31 100644 --- a/core/src/main/java/io/atomix/core/queue/AsyncWorkQueue.java +++ b/core/src/main/java/io/atomix/core/queue/AsyncWorkQueue.java @@ -18,7 +18,6 @@ import com.google.common.collect.ImmutableList; import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; -import io.atomix.primitive.PrimitiveType; import java.time.Duration; import java.util.Arrays; @@ -45,11 +44,6 @@ */ public interface AsyncWorkQueue extends AsyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return WorkQueueType.instance(); - } - /** * Adds a collection of tasks to the work queue. * diff --git a/core/src/main/java/io/atomix/core/queue/WorkQueue.java b/core/src/main/java/io/atomix/core/queue/WorkQueue.java index 3babf2ea56..35190e9f85 100644 --- a/core/src/main/java/io/atomix/core/queue/WorkQueue.java +++ b/core/src/main/java/io/atomix/core/queue/WorkQueue.java @@ -16,7 +16,6 @@ package io.atomix.core.queue; import com.google.common.collect.ImmutableList; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.SyncPrimitive; import java.util.Arrays; @@ -42,11 +41,6 @@ */ public interface WorkQueue extends SyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return WorkQueueType.instance(); - } - /** * Adds a collection of tasks to the work queue. * diff --git a/core/src/main/java/io/atomix/core/queue/WorkQueueBuilder.java b/core/src/main/java/io/atomix/core/queue/WorkQueueBuilder.java index 343a71130b..6c32b8e706 100644 --- a/core/src/main/java/io/atomix/core/queue/WorkQueueBuilder.java +++ b/core/src/main/java/io/atomix/core/queue/WorkQueueBuilder.java @@ -17,12 +17,13 @@ import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; /** * Work queue builder. */ public abstract class WorkQueueBuilder extends DistributedPrimitiveBuilder, WorkQueueConfig, WorkQueue> { - public WorkQueueBuilder(String name, WorkQueueConfig config, PrimitiveManagementService managementService) { - super(WorkQueueType.instance(), name, config, managementService); + public WorkQueueBuilder(PrimitiveType type, String name, WorkQueueConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } } diff --git a/core/src/main/java/io/atomix/core/queue/WorkQueueConfig.java b/core/src/main/java/io/atomix/core/queue/WorkQueueConfig.java index 5d79b419be..69e79233e9 100644 --- a/core/src/main/java/io/atomix/core/queue/WorkQueueConfig.java +++ b/core/src/main/java/io/atomix/core/queue/WorkQueueConfig.java @@ -15,13 +15,15 @@ */ package io.atomix.core.queue; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** * Work queue configuration. */ public class WorkQueueConfig extends PrimitiveConfig { - public WorkQueueConfig() { - super(WorkQueueType.instance()); + @Override + public String getType() { + return PrimitiveTypes.workQueue().name(); } } diff --git a/core/src/main/java/io/atomix/core/queue/WorkQueueType.java b/core/src/main/java/io/atomix/core/queue/WorkQueueType.java deleted file mode 100644 index c4b3f08f2c..0000000000 --- a/core/src/main/java/io/atomix/core/queue/WorkQueueType.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.core.queue; - -import io.atomix.core.queue.impl.WorkQueueProxyBuilder; -import io.atomix.core.queue.impl.WorkQueueResource; -import io.atomix.core.queue.impl.WorkQueueService; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.resource.PrimitiveResource; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Work queue primitive type. - */ -public class WorkQueueType implements PrimitiveType, WorkQueueConfig, WorkQueue, ServiceConfig> { - private static final String NAME = "work-queue"; - - /** - * Returns a new work queue type instance. - * - * @param the element type - * @return a new work queue type - */ - public static WorkQueueType instance() { - return new WorkQueueType<>(); - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new WorkQueueService(config); - } - - @Override - @SuppressWarnings("unchecked") - public PrimitiveResource newResource(WorkQueue primitive) { - return new WorkQueueResource((AsyncWorkQueue) primitive.async()); - } - - @Override - public WorkQueueBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new WorkQueueConfig(), managementService); - } - - @Override - public WorkQueueBuilder newPrimitiveBuilder(String name, WorkQueueConfig config, PrimitiveManagementService managementService) { - return new WorkQueueProxyBuilder<>(name, config, managementService); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/queue/impl/TranscodingAsyncWorkQueue.java b/core/src/main/java/io/atomix/core/queue/impl/TranscodingAsyncWorkQueue.java index 2ed6d4b40b..1bee2f5e27 100644 --- a/core/src/main/java/io/atomix/core/queue/impl/TranscodingAsyncWorkQueue.java +++ b/core/src/main/java/io/atomix/core/queue/impl/TranscodingAsyncWorkQueue.java @@ -15,6 +15,12 @@ */ package io.atomix.core.queue.impl; +import io.atomix.core.queue.AsyncWorkQueue; +import io.atomix.core.queue.Task; +import io.atomix.core.queue.WorkQueue; +import io.atomix.core.queue.WorkQueueStats; +import io.atomix.primitive.PrimitiveType; + import java.time.Duration; import java.util.Collection; import java.util.concurrent.CompletableFuture; @@ -23,11 +29,6 @@ import java.util.function.Function; import java.util.stream.Collectors; -import io.atomix.core.queue.AsyncWorkQueue; -import io.atomix.core.queue.Task; -import io.atomix.core.queue.WorkQueue; -import io.atomix.core.queue.WorkQueueStats; - import static com.google.common.base.MoreObjects.toStringHelper; /** @@ -50,6 +51,11 @@ public String name() { return backingQueue.name(); } + @Override + public PrimitiveType primitiveType() { + return backingQueue.primitiveType(); + } + @Override public CompletableFuture addMultiple(Collection items) { return backingQueue.addMultiple(items.stream().map(valueEncoder).collect(Collectors.toList())); diff --git a/core/src/main/java/io/atomix/core/queue/impl/WorkQueueProxyBuilder.java b/core/src/main/java/io/atomix/core/queue/impl/WorkQueueProxyBuilder.java index 78fb0cf797..5ebb2e2cbc 100644 --- a/core/src/main/java/io/atomix/core/queue/impl/WorkQueueProxyBuilder.java +++ b/core/src/main/java/io/atomix/core/queue/impl/WorkQueueProxyBuilder.java @@ -19,6 +19,7 @@ import io.atomix.core.queue.WorkQueueBuilder; import io.atomix.core.queue.WorkQueueConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; import io.atomix.utils.serializer.Serializer; @@ -29,8 +30,8 @@ * Default work queue builder implementation. */ public class WorkQueueProxyBuilder extends WorkQueueBuilder { - public WorkQueueProxyBuilder(String name, WorkQueueConfig config, PrimitiveManagementService managementService) { - super(name, config, managementService); + public WorkQueueProxyBuilder(PrimitiveType type, String name, WorkQueueConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/registry/RegistryConfig.java b/core/src/main/java/io/atomix/core/registry/RegistryConfig.java new file mode 100644 index 0000000000..22d10764b2 --- /dev/null +++ b/core/src/main/java/io/atomix/core/registry/RegistryConfig.java @@ -0,0 +1,158 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.core.registry; + +import io.atomix.core.profile.ProfileType; +import io.atomix.primitive.PrimitiveType; +import io.atomix.primitive.partition.PartitionGroupType; +import io.atomix.primitive.protocol.PrimitiveProtocolType; + +import java.util.HashMap; +import java.util.Map; + +/** + * Atomix object registry. + */ +public class RegistryConfig { + private Map primitiveTypes = new HashMap<>(); + private Map partitionGroupTypes = new HashMap<>(); + private Map protocolTypes = new HashMap<>(); + private Map profileTypes = new HashMap<>(); + + /** + * Returns the primitive types. + * + * @return the primitive types + */ + public Map getPrimitiveTypes() { + return primitiveTypes; + } + + /** + * Sets the primitive types. + * + * @param primitives the primitive types + * @return the registry + */ + public RegistryConfig setPrimitiveTypes(Map primitives) { + this.primitiveTypes = primitives; + return this; + } + + /** + * Adds a primitive to the registry. + * + * @param primitive the primitive to add + * @return the registry + */ + public RegistryConfig addPrimitiveType(PrimitiveType primitive) { + primitiveTypes.put(primitive.name(), primitive); + return this; + } + + /** + * Returns the partition groups. + * + * @return the partition groups + */ + public Map getPartitionGroupTypes() { + return partitionGroupTypes; + } + + /** + * Sets the partition group types. + * + * @param partitionGroups the partition group types + * @return the registry + */ + public RegistryConfig setPartitionGroupTypes(Map partitionGroups) { + this.partitionGroupTypes = partitionGroups; + return this; + } + + /** + * Adds a partition group to the registry. + * + * @param partitionGroup the group to add + * @return the registry + */ + public RegistryConfig addPartitionGroupType(PartitionGroupType partitionGroup) { + partitionGroupTypes.put(partitionGroup.name(), partitionGroup); + return this; + } + + /** + * Returns the primitive protocols. + * + * @return the primitive protocols + */ + public Map getProtocolTypes() { + return protocolTypes; + } + + /** + * Sets the protocol types. + * + * @param protocols the protocol types + * @return the registry + */ + public RegistryConfig setProtocolTypes(Map protocols) { + this.protocolTypes = protocols; + return this; + } + + /** + * Adds a protocol type to the registry. + * + * @param protocol the protocol to add + * @return the registry + */ + public RegistryConfig addProtocolType(PrimitiveProtocolType protocol) { + protocolTypes.put(protocol.name(), protocol); + return this; + } + + /** + * Returns the profile types. + * + * @return the profile types + */ + public Map getProfileTypes() { + return profileTypes; + } + + /** + * Sets the profile types. + * + * @param profiles the profile types + * @return the registry + */ + public RegistryConfig setProfileTypes(Map profiles) { + this.profileTypes = profiles; + return this; + } + + /** + * Adds a profile type to the registry. + * + * @param profile the profile to add + * @return the registry + */ + public RegistryConfig addProfileType(ProfileType profile) { + profileTypes.put(profile.name(), profile); + return this; + } +} diff --git a/core/src/main/java/io/atomix/core/registry/RegistryService.java b/core/src/main/java/io/atomix/core/registry/RegistryService.java new file mode 100644 index 0000000000..d691e41762 --- /dev/null +++ b/core/src/main/java/io/atomix/core/registry/RegistryService.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.core.registry; + +import io.atomix.primitive.PrimitiveTypeRegistry; +import io.atomix.primitive.partition.PartitionGroupTypeRegistry; +import io.atomix.primitive.protocol.PrimitiveProtocolTypeRegistry; + +/** + * Atomix registry. + */ +public interface RegistryService { + + /** + * Returns the partition group types. + * + * @return the partition group types + */ + PartitionGroupTypeRegistry partitionGroupTypes(); + + /** + * Returns the primitive types. + * + * @return the primitive types + */ + PrimitiveTypeRegistry primitiveTypes(); + + /** + * Returns the primitive protocol types. + * + * @return the primitive protocol types + */ + PrimitiveProtocolTypeRegistry protocolTypes(); + +} diff --git a/core/src/main/java/io/atomix/core/registry/impl/DefaultRegistryService.java b/core/src/main/java/io/atomix/core/registry/impl/DefaultRegistryService.java new file mode 100644 index 0000000000..3bc9a18eac --- /dev/null +++ b/core/src/main/java/io/atomix/core/registry/impl/DefaultRegistryService.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.core.registry.impl; + +import io.atomix.core.registry.RegistryConfig; +import io.atomix.core.registry.RegistryService; +import io.atomix.primitive.PrimitiveTypeRegistry; +import io.atomix.primitive.impl.DefaultPrimitiveTypeRegistry; +import io.atomix.primitive.partition.PartitionGroupTypeRegistry; +import io.atomix.primitive.partition.impl.DefaultPartitionGroupTypeRegistry; +import io.atomix.primitive.protocol.PrimitiveProtocolTypeRegistry; +import io.atomix.primitive.protocol.impl.DefaultPrimitiveProtocolTypeRegistry; + +/** + * Default registry service. + */ +public class DefaultRegistryService implements RegistryService { + private final PartitionGroupTypeRegistry partitionGroupTypes; + private final PrimitiveTypeRegistry primitiveTypes; + private final PrimitiveProtocolTypeRegistry protocolTypes; + + public DefaultRegistryService(RegistryConfig config) { + this.partitionGroupTypes = new DefaultPartitionGroupTypeRegistry(config.getPartitionGroupTypes().values()); + this.primitiveTypes = new DefaultPrimitiveTypeRegistry(config.getPrimitiveTypes().values()); + this.protocolTypes = new DefaultPrimitiveProtocolTypeRegistry(config.getProtocolTypes().values()); + } + + @Override + public PartitionGroupTypeRegistry partitionGroupTypes() { + return partitionGroupTypes; + } + + @Override + public PrimitiveTypeRegistry primitiveTypes() { + return primitiveTypes; + } + + @Override + public PrimitiveProtocolTypeRegistry protocolTypes() { + return protocolTypes; + } +} diff --git a/core/src/main/java/io/atomix/core/registry/impl/ImmutableRegistryService.java b/core/src/main/java/io/atomix/core/registry/impl/ImmutableRegistryService.java new file mode 100644 index 0000000000..fd23f0bd9e --- /dev/null +++ b/core/src/main/java/io/atomix/core/registry/impl/ImmutableRegistryService.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.core.registry.impl; + +import io.atomix.core.registry.RegistryService; +import io.atomix.primitive.PrimitiveTypeRegistry; +import io.atomix.primitive.impl.ImmutablePrimitiveTypeRegistry; +import io.atomix.primitive.partition.PartitionGroupTypeRegistry; +import io.atomix.primitive.partition.impl.ImmutablePartitionGroupTypeRegistry; +import io.atomix.primitive.protocol.PrimitiveProtocolTypeRegistry; +import io.atomix.primitive.protocol.impl.ImmutablePrimitiveProtocolTypeRegistry; + +/** + * Immutable registry service. + */ +public class ImmutableRegistryService implements RegistryService { + private final PartitionGroupTypeRegistry partitionGroupTypes; + private final PrimitiveTypeRegistry primitiveTypes; + private final PrimitiveProtocolTypeRegistry protocolTypes; + + public ImmutableRegistryService(RegistryService registry) { + this.partitionGroupTypes = new ImmutablePartitionGroupTypeRegistry(registry.partitionGroupTypes()); + this.primitiveTypes = new ImmutablePrimitiveTypeRegistry(registry.primitiveTypes()); + this.protocolTypes = new ImmutablePrimitiveProtocolTypeRegistry(registry.protocolTypes()); + } + + @Override + public PartitionGroupTypeRegistry partitionGroupTypes() { + return partitionGroupTypes; + } + + @Override + public PrimitiveTypeRegistry primitiveTypes() { + return primitiveTypes; + } + + @Override + public PrimitiveProtocolTypeRegistry protocolTypes() { + return protocolTypes; + } +} diff --git a/core/src/main/java/io/atomix/core/semaphore/AsyncDistributedSemaphore.java b/core/src/main/java/io/atomix/core/semaphore/AsyncDistributedSemaphore.java index 540c646588..dd9f39ff91 100644 --- a/core/src/main/java/io/atomix/core/semaphore/AsyncDistributedSemaphore.java +++ b/core/src/main/java/io/atomix/core/semaphore/AsyncDistributedSemaphore.java @@ -17,7 +17,6 @@ import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; -import io.atomix.primitive.PrimitiveType; import io.atomix.utils.time.Version; import io.atomix.utils.time.Versioned; @@ -30,10 +29,6 @@ * Distributed implementation of {@link java.util.concurrent.Semaphore}. */ public interface AsyncDistributedSemaphore extends AsyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return DistributedSemaphoreType.instance(); - } /** * Acquires a permit from this semaphore. diff --git a/core/src/main/java/io/atomix/core/semaphore/DistributedSemaphoreBuilder.java b/core/src/main/java/io/atomix/core/semaphore/DistributedSemaphoreBuilder.java index 487dcae669..1279cbea00 100644 --- a/core/src/main/java/io/atomix/core/semaphore/DistributedSemaphoreBuilder.java +++ b/core/src/main/java/io/atomix/core/semaphore/DistributedSemaphoreBuilder.java @@ -17,11 +17,12 @@ import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; public abstract class DistributedSemaphoreBuilder extends DistributedPrimitiveBuilder { - public DistributedSemaphoreBuilder(String name, DistributedSemaphoreConfig config, PrimitiveManagementService managementService) { - super(DistributedSemaphoreType.instance(), name, config, managementService); + public DistributedSemaphoreBuilder(PrimitiveType type, String name, DistributedSemaphoreConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } public DistributedSemaphoreBuilder withInitialCapacity(int permits) { diff --git a/core/src/main/java/io/atomix/core/semaphore/DistributedSemaphoreConfig.java b/core/src/main/java/io/atomix/core/semaphore/DistributedSemaphoreConfig.java index 59efac42bf..8fa67c2ac5 100644 --- a/core/src/main/java/io/atomix/core/semaphore/DistributedSemaphoreConfig.java +++ b/core/src/main/java/io/atomix/core/semaphore/DistributedSemaphoreConfig.java @@ -15,18 +15,20 @@ */ package io.atomix.core.semaphore; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** * Semaphore configuration. */ public class DistributedSemaphoreConfig extends PrimitiveConfig { - protected DistributedSemaphoreConfig() { - super(DistributedSemaphoreType.instance()); - } - private int initialCapacity; + @Override + public String getType() { + return PrimitiveTypes.semaphore().name(); + } + /** * Initialize this semaphore with the given permit count. * Only the first initialization will be accepted. diff --git a/core/src/main/java/io/atomix/core/semaphore/DistributedSemaphoreType.java b/core/src/main/java/io/atomix/core/semaphore/DistributedSemaphoreType.java deleted file mode 100644 index 13d5dca386..0000000000 --- a/core/src/main/java/io/atomix/core/semaphore/DistributedSemaphoreType.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018-present Open Networking Foundation - * - * 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.atomix.core.semaphore; - -import io.atomix.core.semaphore.impl.DistributedSemaphoreProxyBuilder; -import io.atomix.core.semaphore.impl.DistributedSemaphoreService; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.resource.PrimitiveResource; -import io.atomix.primitive.service.PrimitiveService; - -import static com.google.common.base.MoreObjects.toStringHelper; - -public class DistributedSemaphoreType implements PrimitiveType { - private static final String NAME = "semaphore"; - - public static DistributedSemaphoreType instance() { - return new DistributedSemaphoreType(); - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(DistributedSemaphoreServiceConfig config) { - return new DistributedSemaphoreService(config); - } - - @Override - public DistributedSemaphoreBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new DistributedSemaphoreConfig(), managementService); - } - - @Override - public DistributedSemaphoreBuilder newPrimitiveBuilder(String name, DistributedSemaphoreConfig config, PrimitiveManagementService managementService) { - return new DistributedSemaphoreProxyBuilder(name, config, managementService); - } - - @Override - public PrimitiveResource newResource(DistributedSemaphore primitive) { - throw new UnsupportedOperationException("Not implemented yet"); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/semaphore/impl/DistributedSemaphoreProxyBuilder.java b/core/src/main/java/io/atomix/core/semaphore/impl/DistributedSemaphoreProxyBuilder.java index 1d1cdc3b03..ffe57c0693 100644 --- a/core/src/main/java/io/atomix/core/semaphore/impl/DistributedSemaphoreProxyBuilder.java +++ b/core/src/main/java/io/atomix/core/semaphore/impl/DistributedSemaphoreProxyBuilder.java @@ -21,30 +21,30 @@ import io.atomix.core.semaphore.DistributedSemaphoreConfig; import io.atomix.core.semaphore.DistributedSemaphoreServiceConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.proxy.PrimitiveProxy; import java.util.concurrent.CompletableFuture; - public class DistributedSemaphoreProxyBuilder extends DistributedSemaphoreBuilder { - public DistributedSemaphoreProxyBuilder(String name, DistributedSemaphoreConfig config, PrimitiveManagementService managementService) { - super(name, config, managementService); + public DistributedSemaphoreProxyBuilder(PrimitiveType type, String name, DistributedSemaphoreConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @SuppressWarnings("unchecked") @Override public CompletableFuture buildAsync() { PrimitiveProxy proxy = protocol().newProxy( - name(), - primitiveType(), - new DistributedSemaphoreServiceConfig().setInitialCapacity(config.initialCapacity()), - managementService.getPartitionService()); + name(), + primitiveType(), + new DistributedSemaphoreServiceConfig().setInitialCapacity(config.initialCapacity()), + managementService.getPartitionService()); return new DistributedSemaphoreProxy( - proxy, - managementService.getPrimitiveRegistry(), - managementService.getExecutorService()) - .connect() - .thenApply(AsyncDistributedSemaphore::sync); + proxy, + managementService.getPrimitiveRegistry(), + managementService.getExecutorService()) + .connect() + .thenApply(AsyncDistributedSemaphore::sync); } } diff --git a/core/src/main/java/io/atomix/core/set/AsyncDistributedSet.java b/core/src/main/java/io/atomix/core/set/AsyncDistributedSet.java index 10f227e74a..346219d8dd 100644 --- a/core/src/main/java/io/atomix/core/set/AsyncDistributedSet.java +++ b/core/src/main/java/io/atomix/core/set/AsyncDistributedSet.java @@ -18,7 +18,6 @@ import io.atomix.core.set.impl.BlockingDistributedSet; import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; -import io.atomix.primitive.PrimitiveType; import java.time.Duration; import java.util.Collection; @@ -36,11 +35,6 @@ */ public interface AsyncDistributedSet extends AsyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return DistributedSetType.instance(); - } - /** * Registers the specified listener to be notified whenever * the set is updated. diff --git a/core/src/main/java/io/atomix/core/set/DistributedSet.java b/core/src/main/java/io/atomix/core/set/DistributedSet.java index aaf1cb3152..b49422de11 100644 --- a/core/src/main/java/io/atomix/core/set/DistributedSet.java +++ b/core/src/main/java/io/atomix/core/set/DistributedSet.java @@ -15,7 +15,6 @@ */ package io.atomix.core.set; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.SyncPrimitive; import java.util.Set; @@ -26,10 +25,6 @@ * @param set entry type */ public interface DistributedSet extends Set, SyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return DistributedSetType.instance(); - } /** * Registers the specified listener to be notified whenever diff --git a/core/src/main/java/io/atomix/core/set/DistributedSetBuilder.java b/core/src/main/java/io/atomix/core/set/DistributedSetBuilder.java index 2a5dcb1ead..c63ea95091 100644 --- a/core/src/main/java/io/atomix/core/set/DistributedSetBuilder.java +++ b/core/src/main/java/io/atomix/core/set/DistributedSetBuilder.java @@ -17,6 +17,7 @@ import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; /** * Builder for distributed set. @@ -24,7 +25,7 @@ * @param type set elements. */ public abstract class DistributedSetBuilder extends DistributedPrimitiveBuilder, DistributedSetConfig, DistributedSet> { - public DistributedSetBuilder(String name, DistributedSetConfig config, PrimitiveManagementService managementService) { - super(DistributedSetType.instance(), name, config, managementService); + public DistributedSetBuilder(PrimitiveType type, String name, DistributedSetConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } } diff --git a/core/src/main/java/io/atomix/core/set/DistributedSetConfig.java b/core/src/main/java/io/atomix/core/set/DistributedSetConfig.java index dffe524111..00300ce044 100644 --- a/core/src/main/java/io/atomix/core/set/DistributedSetConfig.java +++ b/core/src/main/java/io/atomix/core/set/DistributedSetConfig.java @@ -15,13 +15,15 @@ */ package io.atomix.core.set; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** * Distributed set configuration. */ public class DistributedSetConfig extends PrimitiveConfig { - public DistributedSetConfig() { - super(DistributedSetType.instance()); + @Override + public String getType() { + return PrimitiveTypes.set().name(); } } diff --git a/core/src/main/java/io/atomix/core/set/DistributedSetType.java b/core/src/main/java/io/atomix/core/set/DistributedSetType.java deleted file mode 100644 index b21728ae08..0000000000 --- a/core/src/main/java/io/atomix/core/set/DistributedSetType.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.core.set; - -import io.atomix.core.map.impl.ConsistentMapService; -import io.atomix.core.set.impl.DelegatingDistributedSetBuilder; -import io.atomix.core.set.impl.DistributedSetResource; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.resource.PrimitiveResource; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Distributed set primitive type. - */ -public class DistributedSetType implements PrimitiveType, DistributedSetConfig, DistributedSet, ServiceConfig> { - private static final String NAME = "set"; - - /** - * Returns a new distributed set type. - * - * @param the set element type - * @return a new distributed set type - */ - public static DistributedSetType instance() { - return new DistributedSetType<>(); - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new ConsistentMapService(config); - } - - @Override - @SuppressWarnings("unchecked") - public PrimitiveResource newResource(DistributedSet primitive) { - return new DistributedSetResource((AsyncDistributedSet) primitive.async()); - } - - @Override - public DistributedSetBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new DistributedSetConfig(), managementService); - } - - @Override - public DistributedSetBuilder newPrimitiveBuilder(String name, DistributedSetConfig config, PrimitiveManagementService managementService) { - return new DelegatingDistributedSetBuilder<>(name, config, managementService); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/set/impl/DelegatingAsyncDistributedSet.java b/core/src/main/java/io/atomix/core/set/impl/DelegatingAsyncDistributedSet.java index a72829c0fa..6d3c15ef4f 100644 --- a/core/src/main/java/io/atomix/core/set/impl/DelegatingAsyncDistributedSet.java +++ b/core/src/main/java/io/atomix/core/set/impl/DelegatingAsyncDistributedSet.java @@ -26,7 +26,7 @@ import io.atomix.core.set.DistributedSet; import io.atomix.core.set.SetEvent; import io.atomix.core.set.SetEventListener; -import io.atomix.primitive.impl.DelegatingAsyncPrimitive; +import io.atomix.primitive.DelegatingAsyncPrimitive; import io.atomix.utils.concurrent.Futures; import java.time.Duration; diff --git a/core/src/main/java/io/atomix/core/set/impl/DelegatingDistributedSetBuilder.java b/core/src/main/java/io/atomix/core/set/impl/DelegatingDistributedSetBuilder.java index 12995c4c34..ad2db0ed0a 100644 --- a/core/src/main/java/io/atomix/core/set/impl/DelegatingDistributedSetBuilder.java +++ b/core/src/main/java/io/atomix/core/set/impl/DelegatingDistributedSetBuilder.java @@ -25,6 +25,7 @@ import io.atomix.core.set.DistributedSetBuilder; import io.atomix.core.set.DistributedSetConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; import io.atomix.utils.serializer.Serializer; @@ -37,8 +38,8 @@ * @param type for set elements */ public class DelegatingDistributedSetBuilder extends DistributedSetBuilder { - public DelegatingDistributedSetBuilder(String name, DistributedSetConfig config, PrimitiveManagementService managementService) { - super(name, config, managementService); + public DelegatingDistributedSetBuilder(PrimitiveType type, String name, DistributedSetConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/transaction/AsyncTransaction.java b/core/src/main/java/io/atomix/core/transaction/AsyncTransaction.java index 9482739d6c..9e7948b8bd 100644 --- a/core/src/main/java/io/atomix/core/transaction/AsyncTransaction.java +++ b/core/src/main/java/io/atomix/core/transaction/AsyncTransaction.java @@ -18,7 +18,6 @@ import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; import io.atomix.primitive.protocol.PrimitiveProtocol; -import io.atomix.primitive.PrimitiveType; import java.time.Duration; import java.util.concurrent.CompletableFuture; @@ -28,11 +27,6 @@ */ public interface AsyncTransaction extends AsyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return TransactionType.instance(); - } - /** * Returns the transaction identifier. * diff --git a/core/src/main/java/io/atomix/core/transaction/AsyncTransactionalMap.java b/core/src/main/java/io/atomix/core/transaction/AsyncTransactionalMap.java index dc7687336d..c026796d4a 100644 --- a/core/src/main/java/io/atomix/core/transaction/AsyncTransactionalMap.java +++ b/core/src/main/java/io/atomix/core/transaction/AsyncTransactionalMap.java @@ -15,7 +15,6 @@ */ package io.atomix.core.transaction; -import io.atomix.core.map.ConsistentMapType; import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; @@ -26,10 +25,6 @@ * Asynchronous transactional map. */ public interface AsyncTransactionalMap extends AsyncPrimitive { - @Override - default ConsistentMapType primitiveType() { - return ConsistentMapType.instance(); - } /** * Returns the value to which the specified key is mapped, or null if this diff --git a/core/src/main/java/io/atomix/core/transaction/AsyncTransactionalSet.java b/core/src/main/java/io/atomix/core/transaction/AsyncTransactionalSet.java index f99f88a826..23631de4c2 100644 --- a/core/src/main/java/io/atomix/core/transaction/AsyncTransactionalSet.java +++ b/core/src/main/java/io/atomix/core/transaction/AsyncTransactionalSet.java @@ -15,7 +15,6 @@ */ package io.atomix.core.transaction; -import io.atomix.core.set.DistributedSetType; import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; @@ -27,11 +26,6 @@ */ public interface AsyncTransactionalSet extends AsyncPrimitive { - @Override - default DistributedSetType primitiveType() { - return DistributedSetType.instance(); - } - /** * Adds the specified element to this set if it is not already present * (optional operation). More formally, adds the specified element diff --git a/core/src/main/java/io/atomix/core/transaction/Transaction.java b/core/src/main/java/io/atomix/core/transaction/Transaction.java index 20fb20b53c..f8fdba919c 100644 --- a/core/src/main/java/io/atomix/core/transaction/Transaction.java +++ b/core/src/main/java/io/atomix/core/transaction/Transaction.java @@ -15,20 +15,14 @@ */ package io.atomix.core.transaction; -import io.atomix.primitive.protocol.PrimitiveProtocol; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.SyncPrimitive; +import io.atomix.primitive.protocol.PrimitiveProtocol; /** * Transaction primitive. */ public interface Transaction extends SyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return TransactionType.instance(); - } - /** * Returns the transaction identifier. * diff --git a/core/src/main/java/io/atomix/core/transaction/TransactionBuilder.java b/core/src/main/java/io/atomix/core/transaction/TransactionBuilder.java index 1ac2cca3be..ef2dba5fa0 100644 --- a/core/src/main/java/io/atomix/core/transaction/TransactionBuilder.java +++ b/core/src/main/java/io/atomix/core/transaction/TransactionBuilder.java @@ -17,13 +17,14 @@ import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; /** * Transaction builder. */ public abstract class TransactionBuilder extends DistributedPrimitiveBuilder { - protected TransactionBuilder(String name, TransactionConfig config, PrimitiveManagementService managementService) { - super(TransactionType.instance(), name, config, managementService); + protected TransactionBuilder(PrimitiveType type, String name, TransactionConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } /** diff --git a/core/src/main/java/io/atomix/core/transaction/TransactionConfig.java b/core/src/main/java/io/atomix/core/transaction/TransactionConfig.java index 8d318df8d8..ff5526b6a6 100644 --- a/core/src/main/java/io/atomix/core/transaction/TransactionConfig.java +++ b/core/src/main/java/io/atomix/core/transaction/TransactionConfig.java @@ -15,6 +15,7 @@ */ package io.atomix.core.transaction; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; import static com.google.common.base.Preconditions.checkNotNull; @@ -25,8 +26,9 @@ public class TransactionConfig extends PrimitiveConfig { private Isolation isolation = Isolation.READ_COMMITTED; - public TransactionConfig() { - super(TransactionType.instance()); + @Override + public String getType() { + return PrimitiveTypes.TRANSACTION.name(); } /** diff --git a/core/src/main/java/io/atomix/core/transaction/TransactionType.java b/core/src/main/java/io/atomix/core/transaction/TransactionType.java deleted file mode 100644 index 4c566414d3..0000000000 --- a/core/src/main/java/io/atomix/core/transaction/TransactionType.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.core.transaction; - -import io.atomix.core.impl.CoreTransactionService; -import io.atomix.core.transaction.impl.DefaultTransactionBuilder; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Transaction primitive type. - */ -public class TransactionType implements PrimitiveType { - private static final String NAME = "transaction"; - private static final TransactionType INSTANCE = new TransactionType(); - - /** - * Returns a new consistent tree map type. - * - * @return a new consistent tree map type - */ - public static TransactionType instance() { - return INSTANCE; - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - throw new UnsupportedOperationException(); - } - - @Override - public TransactionBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new TransactionConfig(), managementService); - } - - @Override - public TransactionBuilder newPrimitiveBuilder(String name, TransactionConfig config, PrimitiveManagementService managementService) { - return new DefaultTransactionBuilder(name, config, managementService, new CoreTransactionService(managementService)); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/transaction/TransactionalMap.java b/core/src/main/java/io/atomix/core/transaction/TransactionalMap.java index 50cc0980bb..aeb6cbe3f2 100644 --- a/core/src/main/java/io/atomix/core/transaction/TransactionalMap.java +++ b/core/src/main/java/io/atomix/core/transaction/TransactionalMap.java @@ -15,17 +15,12 @@ */ package io.atomix.core.transaction; -import io.atomix.core.map.ConsistentMapType; import io.atomix.primitive.SyncPrimitive; /** * Transactional map. */ public interface TransactionalMap extends SyncPrimitive { - @Override - default ConsistentMapType primitiveType() { - return ConsistentMapType.instance(); - } /** * Returns the value to which the specified key is mapped, or null if this diff --git a/core/src/main/java/io/atomix/core/transaction/TransactionalMapBuilder.java b/core/src/main/java/io/atomix/core/transaction/TransactionalMapBuilder.java index 93d90e6677..ed9ba9cf07 100644 --- a/core/src/main/java/io/atomix/core/transaction/TransactionalMapBuilder.java +++ b/core/src/main/java/io/atomix/core/transaction/TransactionalMapBuilder.java @@ -15,16 +15,16 @@ */ package io.atomix.core.transaction; -import io.atomix.core.map.ConsistentMapType; import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; /** * Transactional map builder. */ public abstract class TransactionalMapBuilder extends DistributedPrimitiveBuilder, TransactionalMapConfig, TransactionalMap> { - protected TransactionalMapBuilder(String name, TransactionalMapConfig config, PrimitiveManagementService managementService) { - super(ConsistentMapType.instance(), name, config, managementService); + protected TransactionalMapBuilder(PrimitiveType type, String name, TransactionalMapConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } } diff --git a/core/src/main/java/io/atomix/core/transaction/TransactionalMapConfig.java b/core/src/main/java/io/atomix/core/transaction/TransactionalMapConfig.java index 2d2fc1c04b..6d90d48296 100644 --- a/core/src/main/java/io/atomix/core/transaction/TransactionalMapConfig.java +++ b/core/src/main/java/io/atomix/core/transaction/TransactionalMapConfig.java @@ -15,14 +15,15 @@ */ package io.atomix.core.transaction; -import io.atomix.core.map.ConsistentMapType; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** * Transactional map configuration. */ public class TransactionalMapConfig extends PrimitiveConfig { - public TransactionalMapConfig() { - super(ConsistentMapType.instance()); + @Override + public String getType() { + return PrimitiveTypes.consistentMap().name(); } } diff --git a/core/src/main/java/io/atomix/core/transaction/TransactionalSet.java b/core/src/main/java/io/atomix/core/transaction/TransactionalSet.java index 24b38760aa..5f62055317 100644 --- a/core/src/main/java/io/atomix/core/transaction/TransactionalSet.java +++ b/core/src/main/java/io/atomix/core/transaction/TransactionalSet.java @@ -15,7 +15,6 @@ */ package io.atomix.core.transaction; -import io.atomix.core.set.DistributedSetType; import io.atomix.primitive.SyncPrimitive; /** @@ -23,11 +22,6 @@ */ public interface TransactionalSet extends SyncPrimitive { - @Override - default DistributedSetType primitiveType() { - return DistributedSetType.instance(); - } - /** * Adds the specified element to this set if it is not already present * (optional operation). More formally, adds the specified element diff --git a/core/src/main/java/io/atomix/core/transaction/TransactionalSetBuilder.java b/core/src/main/java/io/atomix/core/transaction/TransactionalSetBuilder.java index 54a8310534..388376c271 100644 --- a/core/src/main/java/io/atomix/core/transaction/TransactionalSetBuilder.java +++ b/core/src/main/java/io/atomix/core/transaction/TransactionalSetBuilder.java @@ -15,16 +15,16 @@ */ package io.atomix.core.transaction; -import io.atomix.core.set.DistributedSetType; import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; /** * Transactional set builder. */ public abstract class TransactionalSetBuilder extends DistributedPrimitiveBuilder, TransactionalSetConfig, TransactionalSet> { - protected TransactionalSetBuilder(String name, TransactionalSetConfig config, PrimitiveManagementService managementService) { - super(DistributedSetType.instance(), name, config, managementService); + protected TransactionalSetBuilder(PrimitiveType type, String name, TransactionalSetConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } } diff --git a/core/src/main/java/io/atomix/core/transaction/TransactionalSetConfig.java b/core/src/main/java/io/atomix/core/transaction/TransactionalSetConfig.java index ae2b60b1fa..a3942352a2 100644 --- a/core/src/main/java/io/atomix/core/transaction/TransactionalSetConfig.java +++ b/core/src/main/java/io/atomix/core/transaction/TransactionalSetConfig.java @@ -15,14 +15,15 @@ */ package io.atomix.core.transaction; -import io.atomix.core.set.DistributedSetType; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** * Transactional set configuration. */ public class TransactionalSetConfig extends PrimitiveConfig { - public TransactionalSetConfig() { - super(DistributedSetType.instance()); + @Override + public String getType() { + return PrimitiveTypes.set().name(); } } diff --git a/core/src/main/java/io/atomix/core/transaction/impl/BlockingTransaction.java b/core/src/main/java/io/atomix/core/transaction/impl/BlockingTransaction.java index d1c02236fa..e8a3a95f1d 100644 --- a/core/src/main/java/io/atomix/core/transaction/impl/BlockingTransaction.java +++ b/core/src/main/java/io/atomix/core/transaction/impl/BlockingTransaction.java @@ -23,6 +23,7 @@ import io.atomix.core.transaction.TransactionalMapBuilder; import io.atomix.core.transaction.TransactionalSetBuilder; import io.atomix.primitive.PrimitiveException; +import io.atomix.primitive.PrimitiveType; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -48,6 +49,11 @@ public String name() { return asyncTransaction.name(); } + @Override + public PrimitiveType primitiveType() { + return asyncTransaction.primitiveType(); + } + @Override public TransactionId transactionId() { return asyncTransaction.transactionId(); diff --git a/core/src/main/java/io/atomix/core/transaction/impl/BlockingTransactionalMap.java b/core/src/main/java/io/atomix/core/transaction/impl/BlockingTransactionalMap.java index a5f6dd6ee5..e814b00b00 100644 --- a/core/src/main/java/io/atomix/core/transaction/impl/BlockingTransactionalMap.java +++ b/core/src/main/java/io/atomix/core/transaction/impl/BlockingTransactionalMap.java @@ -16,10 +16,10 @@ package io.atomix.core.transaction.impl; import com.google.common.base.Throwables; - import io.atomix.core.map.ConsistentMapException; import io.atomix.core.transaction.AsyncTransactionalMap; import io.atomix.core.transaction.TransactionalMap; +import io.atomix.primitive.PrimitiveType; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -43,6 +43,11 @@ public String name() { return asyncMap.name(); } + @Override + public PrimitiveType primitiveType() { + return asyncMap.primitiveType(); + } + @Override public V get(K key) { return complete(asyncMap.get(key)); diff --git a/core/src/main/java/io/atomix/core/transaction/impl/BlockingTransactionalSet.java b/core/src/main/java/io/atomix/core/transaction/impl/BlockingTransactionalSet.java index 9a7152a2e8..653cc89350 100644 --- a/core/src/main/java/io/atomix/core/transaction/impl/BlockingTransactionalSet.java +++ b/core/src/main/java/io/atomix/core/transaction/impl/BlockingTransactionalSet.java @@ -16,10 +16,10 @@ package io.atomix.core.transaction.impl; import com.google.common.base.Throwables; - import io.atomix.core.transaction.AsyncTransactionalSet; import io.atomix.core.transaction.TransactionalSet; import io.atomix.primitive.PrimitiveException; +import io.atomix.primitive.PrimitiveType; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -43,6 +43,11 @@ public String name() { return asyncSet.name(); } + @Override + public PrimitiveType primitiveType() { + return asyncSet.primitiveType(); + } + @Override public boolean add(E element) { return complete(asyncSet.add(element)); diff --git a/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransaction.java b/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransaction.java index 3ac0529822..52c9dd3302 100644 --- a/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransaction.java +++ b/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransaction.java @@ -16,7 +16,7 @@ package io.atomix.core.transaction.impl; import com.google.common.collect.Sets; - +import io.atomix.core.PrimitiveTypes; import io.atomix.core.transaction.AsyncTransaction; import io.atomix.core.transaction.CommitStatus; import io.atomix.core.transaction.Isolation; @@ -29,6 +29,7 @@ import io.atomix.core.transaction.TransactionalSetBuilder; import io.atomix.core.transaction.TransactionalSetConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.utils.concurrent.Futures; import java.time.Duration; @@ -62,6 +63,11 @@ public String name() { return null; } + @Override + public PrimitiveType primitiveType() { + return PrimitiveTypes.TRANSACTION; + } + @Override public TransactionId transactionId() { return transactionId; @@ -141,13 +147,13 @@ public CompletableFuture abort() { @Override public TransactionalMapBuilder mapBuilder(String name) { checkState(isOpen(), "transaction not open"); - return new DefaultTransactionalMapBuilder<>(name, new TransactionalMapConfig(), managementService, this); + return new DefaultTransactionalMapBuilder<>(PrimitiveTypes.consistentMap(), name, new TransactionalMapConfig(), managementService, this); } @Override public TransactionalSetBuilder setBuilder(String name) { checkState(isOpen(), "transaction not open"); - return new DefaultTransactionalSetBuilder<>(name, new TransactionalSetConfig(), managementService, this); + return new DefaultTransactionalSetBuilder<>(PrimitiveTypes.set(), name, new TransactionalSetConfig(), managementService, this); } @Override diff --git a/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionBuilder.java b/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionBuilder.java index 5f01b389f9..7f38545a65 100644 --- a/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionBuilder.java +++ b/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionBuilder.java @@ -15,6 +15,7 @@ */ package io.atomix.core.transaction.impl; +import io.atomix.core.PrimitiveTypes; import io.atomix.core.transaction.Transaction; import io.atomix.core.transaction.TransactionBuilder; import io.atomix.core.transaction.TransactionConfig; @@ -36,7 +37,7 @@ public DefaultTransactionBuilder( TransactionConfig config, PrimitiveManagementService managementService, TransactionService transactionService) { - super(name, config, managementService); + super(PrimitiveTypes.TRANSACTION, name, config, managementService); this.transactionService = checkNotNull(transactionService); } diff --git a/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionalMapBuilder.java b/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionalMapBuilder.java index 334e486bcb..2ee6bb864d 100644 --- a/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionalMapBuilder.java +++ b/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionalMapBuilder.java @@ -15,12 +15,13 @@ */ package io.atomix.core.transaction.impl; +import io.atomix.core.PrimitiveTypes; import io.atomix.core.map.ConsistentMapBuilder; -import io.atomix.core.map.ConsistentMapType; import io.atomix.core.transaction.TransactionalMap; import io.atomix.core.transaction.TransactionalMapBuilder; import io.atomix.core.transaction.TransactionalMapConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.protocol.PrimitiveProtocol; import java.util.concurrent.CompletableFuture; @@ -32,9 +33,9 @@ public class DefaultTransactionalMapBuilder extends TransactionalMapBuilde private final ConsistentMapBuilder mapBuilder; private final DefaultTransaction transaction; - public DefaultTransactionalMapBuilder(String name, TransactionalMapConfig config, PrimitiveManagementService managementService, DefaultTransaction transaction) { - super(name, config, managementService); - this.mapBuilder = ConsistentMapType.instance().newPrimitiveBuilder(name, managementService); + public DefaultTransactionalMapBuilder(PrimitiveType type, String name, TransactionalMapConfig config, PrimitiveManagementService managementService, DefaultTransaction transaction) { + super(type, name, config, managementService); + this.mapBuilder = PrimitiveTypes.consistentMap().newBuilder(name, managementService); this.transaction = transaction; } diff --git a/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionalSet.java b/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionalSet.java index 8c59e8c2eb..a30a953e13 100644 --- a/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionalSet.java +++ b/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionalSet.java @@ -15,12 +15,14 @@ */ package io.atomix.core.transaction.impl; -import java.time.Duration; -import java.util.concurrent.CompletableFuture; - +import io.atomix.core.PrimitiveTypes; import io.atomix.core.transaction.AsyncTransactionalMap; import io.atomix.core.transaction.AsyncTransactionalSet; import io.atomix.core.transaction.TransactionalSet; +import io.atomix.primitive.PrimitiveType; + +import java.time.Duration; +import java.util.concurrent.CompletableFuture; /** * Default transactional set. @@ -37,6 +39,11 @@ public String name() { return transactionalMap.name(); } + @Override + public PrimitiveType primitiveType() { + return PrimitiveTypes.set(); + } + @Override public CompletableFuture add(E element) { return transactionalMap.put(element, true); diff --git a/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionalSetBuilder.java b/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionalSetBuilder.java index 1781be826b..adc571961f 100644 --- a/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionalSetBuilder.java +++ b/core/src/main/java/io/atomix/core/transaction/impl/DefaultTransactionalSetBuilder.java @@ -20,6 +20,7 @@ import io.atomix.core.transaction.TransactionalSetBuilder; import io.atomix.core.transaction.TransactionalSetConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import java.util.concurrent.CompletableFuture; @@ -29,14 +30,14 @@ public class DefaultTransactionalSetBuilder extends TransactionalSetBuilder { private final DefaultTransaction transaction; - public DefaultTransactionalSetBuilder(String name, TransactionalSetConfig config, PrimitiveManagementService managementService, DefaultTransaction transaction) { - super(name, config, managementService); + public DefaultTransactionalSetBuilder(PrimitiveType type, String name, TransactionalSetConfig config, PrimitiveManagementService managementService, DefaultTransaction transaction) { + super(type, name, config, managementService); this.transaction = transaction; } @Override public CompletableFuture> buildAsync() { - return new DefaultTransactionalMapBuilder(name(), new TransactionalMapConfig(), managementService, transaction) + return new DefaultTransactionalMapBuilder(type, name(), new TransactionalMapConfig(), managementService, transaction) .buildAsync() .thenApply(map -> new DefaultTransactionalSet<>(map.async()).sync()); } diff --git a/core/src/main/java/io/atomix/core/transaction/impl/TransactionalMapParticipant.java b/core/src/main/java/io/atomix/core/transaction/impl/TransactionalMapParticipant.java index aa7b782e0f..7f1bf30473 100644 --- a/core/src/main/java/io/atomix/core/transaction/impl/TransactionalMapParticipant.java +++ b/core/src/main/java/io/atomix/core/transaction/impl/TransactionalMapParticipant.java @@ -21,6 +21,7 @@ import io.atomix.core.transaction.TransactionId; import io.atomix.core.transaction.TransactionParticipant; import io.atomix.core.transaction.TransactionalMap; +import io.atomix.primitive.PrimitiveType; import java.time.Duration; import java.util.concurrent.CompletableFuture; @@ -45,6 +46,11 @@ public String name() { return consistentMap.name(); } + @Override + public PrimitiveType primitiveType() { + return consistentMap.primitiveType(); + } + @Override public CompletableFuture prepare() { return consistentMap.prepare(log()); diff --git a/core/src/main/java/io/atomix/core/tree/AsyncDocumentTree.java b/core/src/main/java/io/atomix/core/tree/AsyncDocumentTree.java index e541145c5f..b86a411b4a 100644 --- a/core/src/main/java/io/atomix/core/tree/AsyncDocumentTree.java +++ b/core/src/main/java/io/atomix/core/tree/AsyncDocumentTree.java @@ -18,10 +18,8 @@ import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; -import io.atomix.primitive.PrimitiveType; import io.atomix.utils.time.Versioned; -import javax.annotation.concurrent.NotThreadSafe; import java.time.Duration; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -31,14 +29,8 @@ * * @param document tree value type */ -@NotThreadSafe public interface AsyncDocumentTree extends AsyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return DocumentTreeType.instance(); - } - /** * Returns the {@link DocumentPath path} to root of the tree. * diff --git a/core/src/main/java/io/atomix/core/tree/DocumentTree.java b/core/src/main/java/io/atomix/core/tree/DocumentTree.java index c72f639b42..a3df479147 100644 --- a/core/src/main/java/io/atomix/core/tree/DocumentTree.java +++ b/core/src/main/java/io/atomix/core/tree/DocumentTree.java @@ -16,11 +16,9 @@ package io.atomix.core.tree; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.SyncPrimitive; import io.atomix.utils.time.Versioned; -import javax.annotation.concurrent.NotThreadSafe; import java.util.Map; /** @@ -28,14 +26,8 @@ * * @param document tree value type */ -@NotThreadSafe public interface DocumentTree extends SyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return DocumentTreeType.instance(); - } - /** * Returns the {@link DocumentPath path} to root of the tree. * diff --git a/core/src/main/java/io/atomix/core/tree/DocumentTreeBuilder.java b/core/src/main/java/io/atomix/core/tree/DocumentTreeBuilder.java index 1f76a0f2e1..fa17e3f2cb 100644 --- a/core/src/main/java/io/atomix/core/tree/DocumentTreeBuilder.java +++ b/core/src/main/java/io/atomix/core/tree/DocumentTreeBuilder.java @@ -18,13 +18,14 @@ import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; /** * Builder for {@link DocumentTree}. */ public abstract class DocumentTreeBuilder extends DistributedPrimitiveBuilder, DocumentTreeConfig, DocumentTree> { - protected DocumentTreeBuilder(String name, DocumentTreeConfig config, PrimitiveManagementService managementService) { - super(DocumentTreeType.instance(), name, config, managementService); + protected DocumentTreeBuilder(PrimitiveType type, String name, DocumentTreeConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } } \ No newline at end of file diff --git a/core/src/main/java/io/atomix/core/tree/DocumentTreeConfig.java b/core/src/main/java/io/atomix/core/tree/DocumentTreeConfig.java index c257e1460d..f8177f5bb9 100644 --- a/core/src/main/java/io/atomix/core/tree/DocumentTreeConfig.java +++ b/core/src/main/java/io/atomix/core/tree/DocumentTreeConfig.java @@ -15,6 +15,7 @@ */ package io.atomix.core.tree; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.Ordering; import io.atomix.primitive.PrimitiveConfig; @@ -24,8 +25,9 @@ public class DocumentTreeConfig extends PrimitiveConfig { private Ordering ordering; - public DocumentTreeConfig() { - super(DocumentTreeType.instance()); + @Override + public String getType() { + return PrimitiveTypes.documentTree().name(); } /** diff --git a/core/src/main/java/io/atomix/core/tree/DocumentTreeType.java b/core/src/main/java/io/atomix/core/tree/DocumentTreeType.java deleted file mode 100644 index 2c960fcd84..0000000000 --- a/core/src/main/java/io/atomix/core/tree/DocumentTreeType.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.core.tree; - -import io.atomix.core.tree.impl.DocumentTreeProxyBuilder; -import io.atomix.core.tree.impl.DocumentTreeResource; -import io.atomix.core.tree.impl.DocumentTreeService; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.resource.PrimitiveResource; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Document tree primitive type. - */ -public class DocumentTreeType implements PrimitiveType, DocumentTreeConfig, DocumentTree, ServiceConfig> { - private static final String NAME = "document-tree"; - - /** - * Returns a new document tree type. - * - * @param the tree value type - * @return a new document tree type - */ - public static DocumentTreeType instance() { - return new DocumentTreeType<>(); - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new DocumentTreeService(config); - } - - @Override - @SuppressWarnings("unchecked") - public PrimitiveResource newResource(DocumentTree primitive) { - return new DocumentTreeResource((AsyncDocumentTree) primitive.async()); - } - - @Override - public DocumentTreeBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new DocumentTreeConfig(), managementService); - } - - @Override - public DocumentTreeBuilder newPrimitiveBuilder(String name, DocumentTreeConfig config, PrimitiveManagementService managementService) { - return new DocumentTreeProxyBuilder<>(name, config, managementService); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/tree/impl/DefaultDocumentTree.java b/core/src/main/java/io/atomix/core/tree/impl/DefaultDocumentTree.java index e33ec68d0c..5ab994fb39 100644 --- a/core/src/main/java/io/atomix/core/tree/impl/DefaultDocumentTree.java +++ b/core/src/main/java/io/atomix/core/tree/impl/DefaultDocumentTree.java @@ -19,7 +19,6 @@ import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.Maps; - import io.atomix.core.tree.AsyncDocumentTree; import io.atomix.core.tree.DocumentPath; import io.atomix.core.tree.DocumentTree; @@ -28,6 +27,7 @@ import io.atomix.core.tree.IllegalDocumentModificationException; import io.atomix.core.tree.NoSuchDocumentPathException; import io.atomix.primitive.Ordering; +import io.atomix.primitive.PrimitiveType; import io.atomix.utils.time.Versioned; import java.util.Iterator; @@ -67,6 +67,11 @@ public String name() { return null; } + @Override + public PrimitiveType primitiveType() { + return null; + } + @Override public DocumentPath root() { return ROOT_PATH; diff --git a/core/src/main/java/io/atomix/core/tree/impl/DelegatingAsyncDocumentTree.java b/core/src/main/java/io/atomix/core/tree/impl/DelegatingAsyncDocumentTree.java index bcdb0b0b73..3c64a8587a 100644 --- a/core/src/main/java/io/atomix/core/tree/impl/DelegatingAsyncDocumentTree.java +++ b/core/src/main/java/io/atomix/core/tree/impl/DelegatingAsyncDocumentTree.java @@ -21,7 +21,7 @@ import io.atomix.core.tree.DocumentPath; import io.atomix.core.tree.DocumentTree; import io.atomix.core.tree.DocumentTreeListener; -import io.atomix.primitive.impl.DelegatingAsyncPrimitive; +import io.atomix.primitive.DelegatingAsyncPrimitive; import io.atomix.utils.time.Versioned; import java.time.Duration; diff --git a/core/src/main/java/io/atomix/core/tree/impl/DocumentTreeProxyBuilder.java b/core/src/main/java/io/atomix/core/tree/impl/DocumentTreeProxyBuilder.java index f9931bac5b..481aadd91c 100644 --- a/core/src/main/java/io/atomix/core/tree/impl/DocumentTreeProxyBuilder.java +++ b/core/src/main/java/io/atomix/core/tree/impl/DocumentTreeProxyBuilder.java @@ -20,6 +20,7 @@ import io.atomix.core.tree.DocumentTreeBuilder; import io.atomix.core.tree.DocumentTreeConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; import io.atomix.utils.serializer.Serializer; @@ -32,8 +33,8 @@ * @param type for document tree value */ public class DocumentTreeProxyBuilder extends DocumentTreeBuilder { - public DocumentTreeProxyBuilder(String name, DocumentTreeConfig config, PrimitiveManagementService managementService) { - super(name, config, managementService); + public DocumentTreeProxyBuilder(PrimitiveType type, String name, DocumentTreeConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/tree/impl/TranscodingAsyncDocumentTree.java b/core/src/main/java/io/atomix/core/tree/impl/TranscodingAsyncDocumentTree.java index 59596ebdac..6de49e4c2c 100644 --- a/core/src/main/java/io/atomix/core/tree/impl/TranscodingAsyncDocumentTree.java +++ b/core/src/main/java/io/atomix/core/tree/impl/TranscodingAsyncDocumentTree.java @@ -16,12 +16,12 @@ package io.atomix.core.tree.impl; import com.google.common.collect.Maps; - import io.atomix.core.tree.AsyncDocumentTree; import io.atomix.core.tree.DocumentPath; import io.atomix.core.tree.DocumentTree; import io.atomix.core.tree.DocumentTreeEvent; import io.atomix.core.tree.DocumentTreeListener; +import io.atomix.primitive.PrimitiveType; import io.atomix.utils.time.Versioned; import java.time.Duration; @@ -52,6 +52,11 @@ public String name() { return backingTree.name(); } + @Override + public PrimitiveType primitiveType() { + return backingTree.primitiveType(); + } + @Override public DocumentPath root() { return backingTree.root(); diff --git a/core/src/main/java/io/atomix/core/utils/config/PartitionGroupConfigMapper.java b/core/src/main/java/io/atomix/core/utils/config/PartitionGroupConfigMapper.java new file mode 100644 index 0000000000..e97ba324f7 --- /dev/null +++ b/core/src/main/java/io/atomix/core/utils/config/PartitionGroupConfigMapper.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.core.utils.config; + +import io.atomix.primitive.partition.PartitionGroupConfig; +import io.atomix.primitive.partition.PartitionGroupType; +import io.atomix.utils.config.PolymorphicTypeMapper; + +/** + * Partition group mapper. + */ +public class PartitionGroupConfigMapper extends PolymorphicTypeMapper, PartitionGroupType> { + public PartitionGroupConfigMapper() { + super(PartitionGroupConfig.class, PartitionGroupType.class); + } + + @Override + public String getTypePath(String typeName) { + return String.format("registry.partitionGroupTypes.%s", typeName); + } + + @Override + @SuppressWarnings("unchecked") + public Class> getConcreteTypedClass(PartitionGroupType type) { + return (Class>) type.configClass(); + } +} diff --git a/core/src/main/java/io/atomix/core/utils/config/PrimitiveConfigMapper.java b/core/src/main/java/io/atomix/core/utils/config/PrimitiveConfigMapper.java new file mode 100644 index 0000000000..7a453e5bdc --- /dev/null +++ b/core/src/main/java/io/atomix/core/utils/config/PrimitiveConfigMapper.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.core.utils.config; + +import io.atomix.primitive.PrimitiveConfig; +import io.atomix.primitive.PrimitiveType; +import io.atomix.utils.config.PolymorphicTypeMapper; + +/** + * Primitive configuration mapper. + */ +public class PrimitiveConfigMapper extends PolymorphicTypeMapper, PrimitiveType> { + public PrimitiveConfigMapper() { + super(PrimitiveConfig.class, PrimitiveType.class); + } + + @Override + public String getTypePath(String typeName) { + return String.format("registry.primitiveTypes.%s", typeName); + } + + @Override + @SuppressWarnings("unchecked") + public Class> getConcreteTypedClass(PrimitiveType type) { + return type.configClass(); + } +} diff --git a/core/src/main/java/io/atomix/core/utils/config/PrimitiveProtocolConfigMapper.java b/core/src/main/java/io/atomix/core/utils/config/PrimitiveProtocolConfigMapper.java new file mode 100644 index 0000000000..4c849c4ed1 --- /dev/null +++ b/core/src/main/java/io/atomix/core/utils/config/PrimitiveProtocolConfigMapper.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.core.utils.config; + +import io.atomix.primitive.protocol.PrimitiveProtocolConfig; +import io.atomix.primitive.protocol.PrimitiveProtocolType; +import io.atomix.utils.config.PolymorphicTypeMapper; + +/** + * Primitive configuration mapper. + */ +public class PrimitiveProtocolConfigMapper extends PolymorphicTypeMapper, PrimitiveProtocolType> { + public PrimitiveProtocolConfigMapper() { + super(PrimitiveProtocolConfig.class, PrimitiveProtocolType.class); + } + + @Override + public String getTypePath(String typeName) { + return String.format("registry.protocolTypes.%s", typeName); + } + + @Override + @SuppressWarnings("unchecked") + public Class> getConcreteTypedClass(PrimitiveProtocolType type) { + return (Class>) type.configClass(); + } +} diff --git a/config/src/main/java/io/atomix/core/config/jackson/impl/ConfigPropertyNamingStrategy.java b/core/src/main/java/io/atomix/core/utils/config/ProfileMapper.java similarity index 51% rename from config/src/main/java/io/atomix/core/config/jackson/impl/ConfigPropertyNamingStrategy.java rename to core/src/main/java/io/atomix/core/utils/config/ProfileMapper.java index d63d71f7b5..646644894e 100644 --- a/config/src/main/java/io/atomix/core/config/jackson/impl/ConfigPropertyNamingStrategy.java +++ b/core/src/main/java/io/atomix/core/utils/config/ProfileMapper.java @@ -13,21 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.atomix.core.config.jackson.impl; +package io.atomix.core.utils.config; -import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import io.atomix.core.profile.Profile; +import io.atomix.core.profile.ProfileType; +import io.atomix.utils.config.PolymorphicTypeMapper; /** - * Property naming strategy that removes the "Config" suffix from properties. + * Profile configuration mapper. */ -public class ConfigPropertyNamingStrategy extends PropertyNamingStrategy.KebabCaseStrategy { - private static final String CONFIG_SUFFIX = "Config"; +public class ProfileMapper extends PolymorphicTypeMapper { + public ProfileMapper() { + super(Profile.class, ProfileType.class); + } + + @Override + public String getTypePath(String typeName) { + return String.format("registry.profileTypes.%s", typeName); + } @Override - public String translate(String input) { - if (input.endsWith(CONFIG_SUFFIX)) { - return super.translate(input.substring(0, input.length() - CONFIG_SUFFIX.length())); - } - return super.translate(input); + public Class getConcreteTypedClass(ProfileType type) { + return type.profileClass(); } -} \ No newline at end of file +} diff --git a/core/src/main/java/io/atomix/core/value/AsyncAtomicValue.java b/core/src/main/java/io/atomix/core/value/AsyncAtomicValue.java index f324d061b6..c11211b5d0 100644 --- a/core/src/main/java/io/atomix/core/value/AsyncAtomicValue.java +++ b/core/src/main/java/io/atomix/core/value/AsyncAtomicValue.java @@ -17,7 +17,6 @@ import io.atomix.primitive.AsyncPrimitive; import io.atomix.primitive.DistributedPrimitive; -import io.atomix.primitive.PrimitiveType; import java.time.Duration; import java.util.concurrent.CompletableFuture; @@ -34,11 +33,6 @@ */ public interface AsyncAtomicValue extends AsyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return AtomicValueType.instance(); - } - /** * Atomically sets the value to the given updated value if the current value is equal to the expected value. *

diff --git a/core/src/main/java/io/atomix/core/value/AtomicValue.java b/core/src/main/java/io/atomix/core/value/AtomicValue.java index f5e279a532..82b27458bc 100644 --- a/core/src/main/java/io/atomix/core/value/AtomicValue.java +++ b/core/src/main/java/io/atomix/core/value/AtomicValue.java @@ -15,7 +15,6 @@ */ package io.atomix.core.value; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.SyncPrimitive; /** @@ -24,10 +23,6 @@ * @param value type */ public interface AtomicValue extends SyncPrimitive { - @Override - default PrimitiveType primitiveType() { - return AtomicValueType.instance(); - } /** * Atomically sets the value to the given updated value if the current value is equal to the expected value. diff --git a/core/src/main/java/io/atomix/core/value/AtomicValueBuilder.java b/core/src/main/java/io/atomix/core/value/AtomicValueBuilder.java index 73606a5a09..f672533525 100644 --- a/core/src/main/java/io/atomix/core/value/AtomicValueBuilder.java +++ b/core/src/main/java/io/atomix/core/value/AtomicValueBuilder.java @@ -17,6 +17,7 @@ import io.atomix.primitive.DistributedPrimitiveBuilder; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; /** * Builder for constructing new AtomicValue instances. @@ -25,7 +26,7 @@ */ public abstract class AtomicValueBuilder extends DistributedPrimitiveBuilder, AtomicValueConfig, AtomicValue> { - public AtomicValueBuilder(String name, AtomicValueConfig config, PrimitiveManagementService managementService) { - super(AtomicValueType.instance(), name, config, managementService); + public AtomicValueBuilder(PrimitiveType type, String name, AtomicValueConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } } diff --git a/core/src/main/java/io/atomix/core/value/AtomicValueConfig.java b/core/src/main/java/io/atomix/core/value/AtomicValueConfig.java index 0984305504..4bee35a5a0 100644 --- a/core/src/main/java/io/atomix/core/value/AtomicValueConfig.java +++ b/core/src/main/java/io/atomix/core/value/AtomicValueConfig.java @@ -15,13 +15,15 @@ */ package io.atomix.core.value; +import io.atomix.core.PrimitiveTypes; import io.atomix.primitive.PrimitiveConfig; /** * Atomic value configuration. */ public class AtomicValueConfig extends PrimitiveConfig { - public AtomicValueConfig() { - super(AtomicValueType.instance()); + @Override + public String getType() { + return PrimitiveTypes.atomicValue().name(); } } diff --git a/core/src/main/java/io/atomix/core/value/AtomicValueType.java b/core/src/main/java/io/atomix/core/value/AtomicValueType.java deleted file mode 100644 index 256efb765f..0000000000 --- a/core/src/main/java/io/atomix/core/value/AtomicValueType.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.core.value; - -import io.atomix.core.value.impl.AtomicValueProxyBuilder; -import io.atomix.core.value.impl.AtomicValueResource; -import io.atomix.core.value.impl.AtomicValueService; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.resource.PrimitiveResource; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Atomic value primitive type. - */ -public class AtomicValueType implements PrimitiveType, AtomicValueConfig, AtomicValue, ServiceConfig> { - private static final String NAME = "value"; - - /** - * Returns a new value type. - * - * @param the value value type - * @return the value type - */ - public static AtomicValueType instance() { - return new AtomicValueType<>(); - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new AtomicValueService(config); - } - - @Override - @SuppressWarnings("unchecked") - public PrimitiveResource newResource(AtomicValue primitive) { - return new AtomicValueResource((AsyncAtomicValue) primitive.async()); - } - - @Override - public AtomicValueBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - return newPrimitiveBuilder(name, new AtomicValueConfig(), managementService); - } - - @Override - public AtomicValueBuilder newPrimitiveBuilder(String name, AtomicValueConfig config, PrimitiveManagementService managementService) { - return new AtomicValueProxyBuilder<>(name, config, managementService); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/core/src/main/java/io/atomix/core/value/impl/AtomicValueProxyBuilder.java b/core/src/main/java/io/atomix/core/value/impl/AtomicValueProxyBuilder.java index 79d0af9acd..fd66beeb81 100644 --- a/core/src/main/java/io/atomix/core/value/impl/AtomicValueProxyBuilder.java +++ b/core/src/main/java/io/atomix/core/value/impl/AtomicValueProxyBuilder.java @@ -19,6 +19,7 @@ import io.atomix.core.value.AtomicValueBuilder; import io.atomix.core.value.AtomicValueConfig; import io.atomix.primitive.PrimitiveManagementService; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; import io.atomix.utils.serializer.Serializer; @@ -31,8 +32,8 @@ * @param value type */ public class AtomicValueProxyBuilder extends AtomicValueBuilder { - public AtomicValueProxyBuilder(String name, AtomicValueConfig config, PrimitiveManagementService managementService) { - super(name, config, managementService); + public AtomicValueProxyBuilder(PrimitiveType type, String name, AtomicValueConfig config, PrimitiveManagementService managementService) { + super(type, name, config, managementService); } @Override diff --git a/core/src/main/java/io/atomix/core/value/impl/TranscodingAsyncAtomicValue.java b/core/src/main/java/io/atomix/core/value/impl/TranscodingAsyncAtomicValue.java index a48f891859..54ea44338f 100644 --- a/core/src/main/java/io/atomix/core/value/impl/TranscodingAsyncAtomicValue.java +++ b/core/src/main/java/io/atomix/core/value/impl/TranscodingAsyncAtomicValue.java @@ -16,11 +16,11 @@ package io.atomix.core.value.impl; import com.google.common.collect.Maps; - import io.atomix.core.value.AsyncAtomicValue; import io.atomix.core.value.AtomicValue; import io.atomix.core.value.AtomicValueEvent; import io.atomix.core.value.AtomicValueEventListener; +import io.atomix.primitive.PrimitiveType; import java.time.Duration; import java.util.Map; @@ -50,6 +50,11 @@ public String name() { return backingValue.name(); } + @Override + public PrimitiveType primitiveType() { + return backingValue.primitiveType(); + } + @Override public CompletableFuture compareAndSet(V1 expect, V1 update) { return backingValue.compareAndSet(valueEncoder.apply(expect), valueEncoder.apply(update)); diff --git a/core/src/main/resources/META-INF/services/io.atomix.core.profile.NamedProfile b/core/src/main/resources/META-INF/services/io.atomix.core.profile.NamedProfile deleted file mode 100644 index bf524b3c3c..0000000000 --- a/core/src/main/resources/META-INF/services/io.atomix.core.profile.NamedProfile +++ /dev/null @@ -1,18 +0,0 @@ -# -# Copyright 2018-present Open Networking Foundation -# -# 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. -# -io.atomix.core.profile.ClientProfile -io.atomix.core.profile.ConsensusProfile -io.atomix.core.profile.DataGridProfile \ No newline at end of file diff --git a/core/src/main/resources/META-INF/services/io.atomix.primitive.PrimitiveType b/core/src/main/resources/META-INF/services/io.atomix.primitive.PrimitiveType deleted file mode 100644 index 17f0b4b3c0..0000000000 --- a/core/src/main/resources/META-INF/services/io.atomix.primitive.PrimitiveType +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright 2018-present Open Networking Foundation -# -# 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. -# -io.atomix.core.counter.AtomicCounterType -io.atomix.core.election.LeaderElectionType -io.atomix.core.election.LeaderElectorType -io.atomix.core.generator.AtomicIdGeneratorType -io.atomix.core.lock.DistributedLockType -io.atomix.core.map.AtomicCounterMapType -io.atomix.core.map.ConsistentMapType -io.atomix.core.map.ConsistentTreeMapType -io.atomix.core.multimap.ConsistentMultimapType -io.atomix.core.queue.WorkQueueType -io.atomix.core.set.DistributedSetType -io.atomix.core.transaction.TransactionType -io.atomix.core.tree.DocumentTreeType -io.atomix.core.value.AtomicValueType -io.atomix.primitive.partition.impl.PrimaryElectorType -io.atomix.primitive.session.impl.SessionIdGeneratorType -io.atomix.core.semaphore.DistributedSemaphoreType diff --git a/core/src/main/resources/defaults.conf b/core/src/main/resources/defaults.conf new file mode 100644 index 0000000000..b51739d80f --- /dev/null +++ b/core/src/main/resources/defaults.conf @@ -0,0 +1,154 @@ +# Copyright 2018-present Open Networking Foundation +# +# 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. + +# The registry stores information about configuration types. +registry { + # primitiveTypes is an object describing primitive types. The key is the primitive type name by which the + # type can be loaded. The value is an object describing the various classes that operate the primitive. + primitiveTypes { + counter { + builderClass: io.atomix.core.counter.impl.AtomicCounterProxyBuilder + configClass: io.atomix.core.counter.AtomicCounterConfig + primitiveClass: io.atomix.core.counter.AtomicCounter + serviceClass: io.atomix.core.counter.impl.AtomicCounterService + resourceClass: io.atomix.core.counter.impl.AtomicCounterResource + } + election { + builderClass: io.atomix.core.election.impl.LeaderElectionProxyBuilder + configClass: io.atomix.core.election.LeaderElectionConfig + primitiveClass: io.atomix.core.election.LeaderElection + serviceClass: io.atomix.core.election.impl.LeaderElectionService + resourceClass: io.atomix.core.election.impl.LeaderElectionResource + } + elector { + builderClass: io.atomix.core.election.impl.LeaderElectorProxyBuilder + configClass: io.atomix.core.election.LeaderElectorConfig + primitiveClass: io.atomix.core.election.LeaderElector + serviceClass: io.atomix.core.election.impl.LeaderElectorService + } + idGenerator { + builderClass: io.atomix.core.generator.impl.DelegatingAtomicIdGeneratorBuilder + configClass: io.atomix.core.generator.AtomicIdGeneratorConfig + primitiveClass: io.atomix.core.generator.AtomicIdGenerator + serviceClass: io.atomix.core.counter.impl.AtomicCounterService + } + lock { + builderClass: io.atomix.core.lock.impl.DistributedLockProxyBuilder + configClass: io.atomix.core.lock.DistributedLockConfig + primitiveClass: io.atomix.core.lock.DistributedLock + serviceClass: io.atomix.core.lock.impl.DefaultDistributedLockService + resourceClass: io.atomix.core.lock.impl.DistributedLockResource + } + map { + builderClass: io.atomix.core.map.impl.ConsistentMapProxyBuilder + configClass: io.atomix.core.map.ConsistentMapConfig + primitiveClass: io.atomix.core.map.ConsistentMap + serviceClass: io.atomix.core.map.impl.ConsistentMapService + resourceClass: io.atomix.core.map.impl.ConsistentMapResource + } + counterMap { + builderClass: io.atomix.core.map.impl.AtomicCounterMapProxyBuilder + configClass: io.atomix.core.map.AtomicCounterMapConfig + primitiveClass: io.atomix.core.map.AtomicCounterMap + serviceClass: io.atomix.core.map.impl.AtomicCounterMapService + } + treeMap { + builderClass: io.atomix.core.map.impl.ConsistentTreeMapProxyBuilder + configClass: io.atomix.core.map.ConsistentTreeMapConfig + primitiveClass: io.atomix.core.map.ConsistentTreeMap + serviceClass: io.atomix.core.map.impl.ConsistentTreeMapService + } + multimap { + builderClass: io.atomix.core.multimap.impl.ConsistentMultimapProxyBuilder + configClass: io.atomix.core.multimap.ConsistentMultimapConfig + primitiveClass: io.atomix.core.multimap.ConsistentMultimap + serviceClass: io.atomix.core.multimap.impl.ConsistentSetMultimapService + } + workQueue { + builderClass: io.atomix.core.queue.impl.WorkQueueProxyBuilder + configClass: io.atomix.core.queue.WorkQueueConfig + primitiveClass: io.atomix.core.queue.WorkQueue + serviceClass: io.atomix.core.queue.impl.WorkQueueService + resourceClass: io.atomix.core.queue.impl.WorkQueueResource + } + documentTree { + builderClass: io.atomix.core.tree.impl.DocumentTreeProxyBuilder + configClass: io.atomix.core.tree.DocumentTreeConfig + primitiveClass: io.atomix.core.tree.DocumentTree + serviceClass: io.atomix.core.tree.impl.DocumentTreeService + resourceClass: io.atomix.core.tree.impl.DocumentTreeResource + } + semaphore { + builderClass: io.atomix.core.semaphore.impl.DistributedSemaphoreProxyBuilder + configClass: io.atomix.core.semaphore.DistributedSemaphoreConfig + primitiveClass: io.atomix.core.semaphore.DistributedSemaphore + serviceClass: io.atomix.core.semaphore.impl.DistributedSemaphoreService + serviceConfigClass: io.atomix.core.semaphore.DistributedSemaphoreServiceConfig + } + set { + builderClass: io.atomix.core.set.impl.DelegatingDistributedSetBuilder + configClass: io.atomix.core.set.DistributedSetConfig + primitiveClass: io.atomix.core.set.DistributedSet + serviceClass: io.atomix.core.map.impl.ConsistentMapService + } + value { + builderClass: io.atomix.core.value.impl.AtomicValueProxyBuilder + configClass: io.atomix.core.value.AtomicValueConfig + primitiveClass: io.atomix.core.value.AtomicValue + serviceClass: io.atomix.core.value.impl.AtomicValueService + resourceClass: io.atomix.core.value.impl.AtomicValueResource + } + } + + # partitionGroupTypes describes available partition groups. These group types can be referenced in the Atomix + # configuration to construct new partition groups. The key is the group type name and the value is an object + # describing how an instance of the group type is configured and constructed. + partitionGroupTypes { + raft { + configClass: io.atomix.protocols.raft.partition.RaftPartitionGroupConfig + factoryClass: io.atomix.protocols.raft.partition.RaftPartitionGroupFactory + } + primary-backup { + configClass: io.atomix.protocols.backup.partition.PrimaryBackupPartitionGroupConfig + factoryClass: io.atomix.protocols.backup.partition.PrimaryBackupPartitionGroupFactory + } + } + + # protocolTypes desribes the available protocol implementations. The key is the protocol type name and the value + # is an object describing how an instance of the protocol type is configured and constructed. + protocolTypes { + multi-raft { + configClass: io.atomix.protocols.raft.MultiRaftProtocolConfig + factoryClass: io.atomix.protocols.raft.MultiRaftProtocolFactory + } + multi-primary { + configClass: io.atomix.protocols.backup.MultiPrimaryProtocolConfig + factoryClass: io.atomix.protocols.backup.MultiPrimaryProtocolFactory + } + } + + # profileTypes describes the available profile implementations. The key is the profile type name and the value is + # an object describing the profile implementation. + profileTypes { + data-grid { + profileClass: io.atomix.core.profile.DataGridProfile + } + consensus { + profileClass: io.atomix.core.profile.ConsensusProfile + } + client { + profileClass: io.atomix.core.profile.ClientProfile + } + } +} \ No newline at end of file diff --git a/core/src/test/java/io/atomix/core/election/impl/LeaderElectionServiceTest.java b/core/src/test/java/io/atomix/core/election/impl/LeaderElectionServiceTest.java index 15d61f8d31..fbb1bc1208 100644 --- a/core/src/test/java/io/atomix/core/election/impl/LeaderElectionServiceTest.java +++ b/core/src/test/java/io/atomix/core/election/impl/LeaderElectionServiceTest.java @@ -15,7 +15,7 @@ */ package io.atomix.core.election.impl; -import io.atomix.core.election.LeaderElectionType; +import io.atomix.core.PrimitiveTypes; import io.atomix.core.election.Leadership; import io.atomix.core.election.impl.LeaderElectionOperations.Run; import io.atomix.primitive.PrimitiveId; @@ -44,7 +44,7 @@ public class LeaderElectionServiceTest { @Test public void testSnapshot() throws Exception { ServiceContext context = mock(ServiceContext.class); - when(context.serviceType()).thenReturn(LeaderElectionType.instance()); + when(context.serviceType()).thenReturn(PrimitiveTypes.leaderElection()); when(context.serviceName()).thenReturn("test"); when(context.serviceId()).thenReturn(PrimitiveId.from(1)); when(context.wallClock()).thenReturn(new WallClock()); diff --git a/core/src/test/java/io/atomix/core/queue/impl/WorkQueueServiceTest.java b/core/src/test/java/io/atomix/core/queue/impl/WorkQueueServiceTest.java index 89099d0658..511b9c4020 100644 --- a/core/src/test/java/io/atomix/core/queue/impl/WorkQueueServiceTest.java +++ b/core/src/test/java/io/atomix/core/queue/impl/WorkQueueServiceTest.java @@ -15,8 +15,8 @@ */ package io.atomix.core.queue.impl; +import io.atomix.core.PrimitiveTypes; import io.atomix.core.queue.Task; -import io.atomix.core.queue.WorkQueueType; import io.atomix.core.queue.impl.WorkQueueOperations.Add; import io.atomix.core.queue.impl.WorkQueueOperations.Take; import io.atomix.primitive.PrimitiveId; @@ -49,7 +49,7 @@ public class WorkQueueServiceTest { @Test public void testSnapshot() throws Exception { ServiceContext context = mock(ServiceContext.class); - when(context.serviceType()).thenReturn(WorkQueueType.instance()); + when(context.serviceType()).thenReturn(PrimitiveTypes.workQueue()); when(context.serviceName()).thenReturn("test"); when(context.serviceId()).thenReturn(PrimitiveId.from(1)); diff --git a/core/src/test/java/io/atomix/core/utils/config/ConfigMapperTest.java b/core/src/test/java/io/atomix/core/utils/config/ConfigMapperTest.java new file mode 100644 index 0000000000..7ea614ac78 --- /dev/null +++ b/core/src/test/java/io/atomix/core/utils/config/ConfigMapperTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.core.utils.config; + +import io.atomix.core.AtomixConfig; +import io.atomix.utils.config.ConfigMapper; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Default configuration provider test. + */ +public class ConfigMapperTest { + + private ConfigMapper getMapper() { + return new ConfigMapper( + Thread.currentThread().getContextClassLoader(), + new PartitionGroupConfigMapper(), + new PrimitiveConfigMapper(), + new PrimitiveProtocolConfigMapper(), + new ProfileMapper()); + } + + @Test + public void testDefaults() throws Exception { + ConfigMapper mapper = getMapper(); + AtomixConfig config = mapper.loadResources(AtomixConfig.class, "defaults.conf"); + assertEquals("raft", config.getRegistry().getPartitionGroupTypes().get("raft").name()); + assertEquals("primary-backup", config.getRegistry().getPartitionGroupTypes().get("primary-backup").name()); + assertEquals("multi-raft", config.getRegistry().getProtocolTypes().get("multi-raft").name()); + assertEquals("multi-primary", config.getRegistry().getProtocolTypes().get("multi-primary").name()); + } + + @Test + public void testOverrides() throws Exception { + ConfigMapper mapper = getMapper(); + AtomixConfig config = mapper.loadResources(AtomixConfig.class, "test.conf", "defaults.conf"); + assertEquals("raft", config.getRegistry().getPartitionGroupTypes().get("raft").name()); + assertEquals("primary-backup", config.getRegistry().getPartitionGroupTypes().get("primary-backup").name()); + assertEquals("multi-raft", config.getRegistry().getProtocolTypes().get("multi-raft").name()); + assertEquals("multi-primary", config.getRegistry().getProtocolTypes().get("multi-primary").name()); + assertEquals(3, config.getClusterConfig().getMembers().size()); + assertEquals("raft", config.getManagementGroup().getType()); + assertEquals(1, config.getManagementGroup().getPartitions()); + assertEquals("raft", config.getPartitionGroups().get("one").getType()); + assertEquals(7, config.getPartitionGroups().get("one").getPartitions()); + assertEquals("primary-backup", config.getPartitionGroups().get("two").getType()); + assertEquals(32, config.getPartitionGroups().get("two").getPartitions()); + assertEquals(2, config.getProfiles().size()); + } +} diff --git a/core/src/test/resources/test.conf b/core/src/test/resources/test.conf new file mode 100644 index 0000000000..a398b2781c --- /dev/null +++ b/core/src/test/resources/test.conf @@ -0,0 +1,30 @@ +cluster { + name: test + members: [ + {id: one, address: "localhost:5000"} + {id: two, address: "localhost:5001"} + {id: three, address: "localhost:5002"} + ] +} + +profiles: [ + {type: "consensus"} + {type: "data-grid"} +] + +managementGroup { + type: raft + partitions: 1 +} + +partitionGroups { + one: { + type: raft + partitions: 7 + } + two: { + type: primary-backup + partitions: 32 + } +} + diff --git a/pom.xml b/pom.xml index 8930d08542..59e5960561 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,7 @@ 3.5.0 2.0 2.9.5 + 1.3.2 3.1.4.Final 3.0.7 0.7.0 @@ -103,7 +104,6 @@ agent cluster - config core primitive protocols diff --git a/primitive/src/main/java/io/atomix/primitive/AbstractAsyncPrimitive.java b/primitive/src/main/java/io/atomix/primitive/AbstractAsyncPrimitive.java index 8f7cd5ac1b..0c03380ccc 100644 --- a/primitive/src/main/java/io/atomix/primitive/AbstractAsyncPrimitive.java +++ b/primitive/src/main/java/io/atomix/primitive/AbstractAsyncPrimitive.java @@ -18,9 +18,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import io.atomix.primitive.AsyncPrimitive; -import io.atomix.primitive.PrimitiveRegistry; -import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.event.EventType; import io.atomix.primitive.event.PrimitiveEvent; import io.atomix.primitive.operation.OperationId; @@ -63,7 +60,6 @@ public abstract class AbstractAsyncPrimitive implement private final PrimitiveProxy proxy; private final PrimitiveRegistry registry; - private final Serializer serializer; private final Set> statusChangeListeners = Sets.newCopyOnWriteArraySet(); private final Map>> eventListeners = Maps.newIdentityHashMap(); private final Map, Map>> stateChangeListeners = @@ -72,7 +68,6 @@ public abstract class AbstractAsyncPrimitive implement public AbstractAsyncPrimitive(PrimitiveProxy proxy, PrimitiveRegistry registry) { this.proxy = checkNotNull(proxy, "proxy cannot be null"); this.registry = checkNotNull(registry, "registry cannot be null"); - this.serializer = Serializer.using(proxy.type().namespace()); proxy.addStateChangeListener(this::onStateChange); } @@ -92,7 +87,7 @@ public PrimitiveType primitiveType() { * @return the serializer for the primitive operations */ protected Serializer serializer() { - return serializer; + return primitiveType().serializer(); } /** diff --git a/primitive/src/main/java/io/atomix/primitive/impl/DelegatingAsyncPrimitive.java b/primitive/src/main/java/io/atomix/primitive/DelegatingAsyncPrimitive.java similarity index 95% rename from primitive/src/main/java/io/atomix/primitive/impl/DelegatingAsyncPrimitive.java rename to primitive/src/main/java/io/atomix/primitive/DelegatingAsyncPrimitive.java index f0a661fd7b..3d9a6ccb5d 100644 --- a/primitive/src/main/java/io/atomix/primitive/impl/DelegatingAsyncPrimitive.java +++ b/primitive/src/main/java/io/atomix/primitive/DelegatingAsyncPrimitive.java @@ -13,11 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.atomix.primitive.impl; +package io.atomix.primitive; import com.google.common.base.MoreObjects; -import io.atomix.primitive.AsyncPrimitive; -import io.atomix.primitive.PrimitiveType; import java.util.Collection; import java.util.Objects; diff --git a/primitive/src/main/java/io/atomix/primitive/DistributedPrimitiveBuilder.java b/primitive/src/main/java/io/atomix/primitive/DistributedPrimitiveBuilder.java index f58c1f57dd..07f0122011 100644 --- a/primitive/src/main/java/io/atomix/primitive/DistributedPrimitiveBuilder.java +++ b/primitive/src/main/java/io/atomix/primitive/DistributedPrimitiveBuilder.java @@ -19,7 +19,6 @@ import io.atomix.primitive.partition.PartitionGroup; import io.atomix.primitive.protocol.PrimitiveProtocol; import io.atomix.primitive.protocol.PrimitiveProtocolConfig; -import io.atomix.primitive.protocol.PrimitiveProtocols; import io.atomix.utils.Builder; import io.atomix.utils.config.ConfigurationException; import io.atomix.utils.serializer.KryoNamespace; @@ -169,12 +168,12 @@ public PrimitiveProtocol protocol() { protocol = partitionGroups.iterator().next().newProtocol(); } else { String groups = Joiner.on(", ").join(partitionGroups.stream() - .map(group -> String.format("%s:%s", group.type().name(), group.name())) + .map(group -> group.name()) .collect(Collectors.toList())); throw new ConfigurationException(String.format("Primitive protocol is ambiguous: %d partition groups found (%s)", partitionGroups.size(), groups)); } } else { - protocol = PrimitiveProtocols.createProtocol(protocolConfig, managementService.getClassLoader()); + protocol = managementService.getProtocolTypeRegistry().createProtocol(protocolConfig); } } return protocol; diff --git a/primitive/src/main/java/io/atomix/primitive/PrimitiveConfig.java b/primitive/src/main/java/io/atomix/primitive/PrimitiveConfig.java index a0ffd60614..ddffc1f87f 100644 --- a/primitive/src/main/java/io/atomix/primitive/PrimitiveConfig.java +++ b/primitive/src/main/java/io/atomix/primitive/PrimitiveConfig.java @@ -16,32 +16,33 @@ package io.atomix.primitive; import io.atomix.primitive.protocol.PrimitiveProtocolConfig; +import io.atomix.utils.config.NamedConfig; +import io.atomix.utils.config.TypedConfig; import io.atomix.utils.serializer.SerializerConfig; /** * Primitive configuration. */ -public abstract class PrimitiveConfig> { +public abstract class PrimitiveConfig> implements TypedConfig, NamedConfig { private static final int DEFAULT_CACHE_SIZE = 1000; - private final PrimitiveType primitiveType; + private String name; private SerializerConfig serializerConfig; private PrimitiveProtocolConfig protocolConfig; private boolean cacheEnabled = false; private int cacheSize = DEFAULT_CACHE_SIZE; private boolean readOnly = false; - protected PrimitiveConfig(PrimitiveType primitiveType) { - this.primitiveType = primitiveType; + @Override + public String getName() { + return name; } - /** - * Returns the primitive type. - * - * @return the primitive type - */ - public PrimitiveType getType() { - return primitiveType; + @Override + @SuppressWarnings("unchecked") + public C setName(String name) { + this.name = name; + return (C) this; } /** diff --git a/primitive/src/main/java/io/atomix/primitive/PrimitiveManagementService.java b/primitive/src/main/java/io/atomix/primitive/PrimitiveManagementService.java index 5fb60948ff..d4672a7280 100644 --- a/primitive/src/main/java/io/atomix/primitive/PrimitiveManagementService.java +++ b/primitive/src/main/java/io/atomix/primitive/PrimitiveManagementService.java @@ -19,6 +19,7 @@ import io.atomix.cluster.messaging.ClusterCommunicationService; import io.atomix.cluster.messaging.ClusterEventingService; import io.atomix.primitive.partition.PartitionService; +import io.atomix.primitive.protocol.PrimitiveProtocolTypeRegistry; import java.util.concurrent.ScheduledExecutorService; @@ -70,10 +71,17 @@ public interface PrimitiveManagementService { PrimitiveRegistry getPrimitiveRegistry(); /** - * Returns the class loader. + * Returns the primitive type registry. * - * @return the class loader + * @return the primitive type registry */ - ClassLoader getClassLoader(); + PrimitiveTypeRegistry getPrimitiveTypeRegistry(); + + /** + * Returns the primitive protocol type registry. + * + * @return the primitive protocol type registry + */ + PrimitiveProtocolTypeRegistry getProtocolTypeRegistry(); } diff --git a/primitive/src/main/java/io/atomix/primitive/PrimitiveType.java b/primitive/src/main/java/io/atomix/primitive/PrimitiveType.java index e2d1a437ce..276e758427 100644 --- a/primitive/src/main/java/io/atomix/primitive/PrimitiveType.java +++ b/primitive/src/main/java/io/atomix/primitive/PrimitiveType.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-present Open Networking Foundation + * Copyright 2018-present Open Networking Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,44 +18,94 @@ import io.atomix.primitive.resource.PrimitiveResource; import io.atomix.primitive.service.PrimitiveService; import io.atomix.primitive.service.ServiceConfig; -import io.atomix.utils.Generics; -import io.atomix.utils.Identifier; +import io.atomix.utils.AbstractNamed; +import io.atomix.utils.Type; +import io.atomix.utils.config.ConfigurationException; import io.atomix.utils.serializer.KryoNamespace; import io.atomix.utils.serializer.KryoNamespaces; -import io.atomix.utils.serializer.Namespace; +import io.atomix.utils.serializer.Serializer; +import io.atomix.utils.serializer.SerializerConfig; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; /** - * Raft service type. + * Primitive type. */ -public interface PrimitiveType, C extends PrimitiveConfig, P extends DistributedPrimitive, S extends ServiceConfig> - extends Identifier { +public class PrimitiveType< + B extends DistributedPrimitiveBuilder, + C extends PrimitiveConfig, + P extends DistributedPrimitive> + extends AbstractNamed implements Type { /** - * Returns the primitive type name. + * Returns a new primitive type builder. * - * @return the primitive type name + * @return a new primitive type builder */ - @Override - String id(); + public static Builder builder() { + return new Builder(null); + } /** - * Returns the primitive type builder class. + * Returns a new primitive type builder. * - * @return the primitive type builder class + * @param name the primitive type name + * @return a new primitive type builder */ - @SuppressWarnings("unchecked") - default Class builderClass() { - return (Class) Generics.getGenericInterfaceType(this, PrimitiveType.class, 0); + public static Builder builder(String name) { + return new Builder(name); + } + + private Class builderClass; + private Class configClass; + private Class

primitiveClass; + private Class serviceClass; + private Class serviceConfigClass = ServiceConfig.class; + private Class resourceClass; + private SerializerConfig namespace; + private transient volatile Serializer serializer; + + public PrimitiveType() { + this(null, null, null, null, null, null, null); + } + + private PrimitiveType( + String name, + Class builderClass, + Class configClass, + Class

primitiveClass, + Class serviceClass, + Class serviceConfigClass, + Class resourceClass) { + super(name); + this.builderClass = builderClass; + this.configClass = configClass; + this.primitiveClass = primitiveClass; + this.serviceClass = serviceClass; + this.serviceConfigClass = serviceConfigClass != null ? serviceConfigClass : ServiceConfig.class; + this.resourceClass = resourceClass; } /** - * Returns the primitive type configuration class. + * Returns the primitive builder class. * - * @return the primitive type configuration class + * @return the primitive builder class */ - @SuppressWarnings("unchecked") - default Class primitiveConfigClass() { - return (Class) Generics.getGenericInterfaceType(this, PrimitiveType.class, 1); + public Class builderClass() { + return builderClass; + } + + /** + * Returns the primitive configuration class. + * + * @return the primitive configuration class + */ + public Class configClass() { + return configClass; } /** @@ -63,9 +113,17 @@ default Class primitiveConfigClass() { * * @return the primitive class */ - @SuppressWarnings("unchecked") - default Class primitiveClass() { - return (Class) Generics.getGenericInterfaceType(this, PrimitiveType.class, 2); + public Class

primitiveClass() { + return primitiveClass; + } + + /** + * Returns the primitive service class. + * + * @return the primitive service class + */ + public Class serviceClass() { + return serviceClass; } /** @@ -73,59 +131,261 @@ default Class primitiveClass() { * * @return the service configuration class */ - @SuppressWarnings("unchecked") - default Class serviceConfigClass() { - Class serviceConfigClass = (Class) Generics.getGenericInterfaceType(this, PrimitiveType.class, 3); - return serviceConfigClass != null ? serviceConfigClass : ServiceConfig.class; + public Class serviceConfigClass() { + return serviceConfigClass; } /** - * Returns the primitive namespace. + * Returns the primitive resource class. * - * @return the primitive namespace + * @return the primitive resource class */ - default Namespace namespace() { - return KryoNamespace.builder() - .register(KryoNamespaces.BASIC) - .register(serviceConfigClass()) - .build(); + public Class resourceClass() { + return resourceClass; } /** - * Returns the primitive service factory. + * Returns the primitive type serializer. * - * @param config the primitive service configuration - * @return the primitive service factory. + * @return the primitive type serializer */ - PrimitiveService newService(S config); + public Serializer serializer() { + if (serializer == null) { + synchronized (this) { + if (serializer == null) { + if (namespace != null) { + serializer = Serializer.using(KryoNamespace.builder() + .register(KryoNamespaces.BASIC) + .register(serviceConfigClass()) + .register(new KryoNamespace(namespace)) + .build()); + } else { + serializer = Serializer.using(KryoNamespace.builder() + .register(KryoNamespaces.BASIC) + .register(serviceConfigClass()) + .build()); + } + } + } + } + return serializer; + } /** - * Returns the primitive resource factory. + * Returns a new configuration for the primitive type. * - * @param primitive the primitive instance - * @return the primitive resource factory + * @return a new primitive configuration */ - default PrimitiveResource newResource(P primitive) { - return null; + public C newConfig() { + if (configClass == null) { + throw new ConfigurationException("No configuration class specified for primitive type " + name()); + } + + try { + return configClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new ConfigurationException("Failed to instantiate configuration for primitive type " + name() + ". Must provide a no-arg constructor", e); + } } /** - * Returns a new primitive builder for the given partition. + * Returns a new primitive builder. * - * @param name the primitive name + * @param primitiveName the primitive name * @param managementService the primitive management service - * @return the primitive builder + * @return a new primitive builder */ - B newPrimitiveBuilder(String name, PrimitiveManagementService managementService); + public B newBuilder(String primitiveName, PrimitiveManagementService managementService) { + return newBuilder(primitiveName, newConfig(), managementService); + } /** - * Returns a new primitive builder for the given partition. + * Returns a new primitive builder. * - * @param name the primitive name + * @param primitiveName the primitive name * @param config the primitive configuration * @param managementService the primitive management service - * @return the primitive builder + * @return a new primitive builder */ - B newPrimitiveBuilder(String name, C config, PrimitiveManagementService managementService); + public B newBuilder(String primitiveName, C config, PrimitiveManagementService managementService) { + if (builderClass == null) { + throw new ConfigurationException("No builder class configured for primitive type " + name()); + } + try { + Constructor constructor = builderClass.getConstructor(PrimitiveType.class, String.class, configClass, PrimitiveManagementService.class); + return constructor.newInstance(this, primitiveName, config, managementService); + } catch (NoSuchMethodException e) { + throw new ConfigurationException("No valid constructor found for builder class " + builderClass.getName(), e); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new ConfigurationException("Failed to instantiate primitive builder class " + builderClass.getName(), e); + } + } + + /** + * Creates a new service instance from the given configuration. + * + * @param config the service configuration + * @return the service instance + */ + public PrimitiveService newService(ServiceConfig config) { + if (serviceClass == null) { + throw new ConfigurationException("No service class configured"); + } + + try { + Constructor configConstructor = serviceClass.getConstructor(serviceConfigClass); + try { + return configConstructor.newInstance(config); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new ConfigurationException("Failed to instantiate primitive service using config constructor", e); + } + } catch (NoSuchMethodException e) { + try { + Constructor noArgConstructor = serviceClass.getConstructor(); + try { + return noArgConstructor.newInstance(); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e2) { + throw new ConfigurationException("Failed to instantiate primitive service using no-arg constructor", e2); + } + } catch (NoSuchMethodException e2) { + throw new ConfigurationException("Failed to instantiate primitive service: no valid constructor found", e); + } + } + } + + /** + * Creates a new resource for the given primitive. + * + * @param primitive the primitive instance + * @return a new resource for the given primitive instance + */ + public PrimitiveResource newResource(P primitive) { + if (resourceClass == null) { + throw new ConfigurationException("No resource class configured for primitive type " + name()); + } + + try { + return resourceClass.getConstructor(primitiveClass).newInstance(primitive); + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new ConfigurationException("Failed to instantiate resource class for primitive type " + name(), e); + } + } + + @Override + public int hashCode() { + return Objects.hash(name()); + } + + @Override + public boolean equals(Object object) { + return object instanceof PrimitiveType && Objects.equals(((PrimitiveType) object).name(), name()); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("name", name()) + .toString(); + } + + /** + * Primitive type builder. + */ + public static class Builder implements io.atomix.utils.Builder { + private String name; + private Class builderClass; + private Class configClass; + private Class primitiveClass; + private Class serviceClass; + private Class serviceConfigClass = ServiceConfig.class; + private Class resourceClass; + + private Builder(String name) { + this.name = name; + } + + /** + * Sets the primitive type name. + * + * @param name the primitive type name + * @return the primitive type builder + */ + public Builder withName(String name) { + this.name = name; + return this; + } + + /** + * Sets the primitive builder class. + * + * @param builderClass the primitive builder class + * @return the primitive type builder + */ + public Builder withBuilderClass(Class builderClass) { + this.builderClass = builderClass; + return this; + } + + /** + * Sets the primitive configuration class. + * + * @param configClass the primitive configuration class + * @return the primitive type builder + */ + public Builder withConfigClass(Class configClass) { + this.configClass = configClass; + return this; + } + + /** + * Sets the primitive class. + * + * @param primitiveClass the builder class + * @return the primitive type builder + */ + public Builder withPrimitiveClass(Class primitiveClass) { + this.primitiveClass = primitiveClass; + return this; + } + + /** + * Sets the primitive service class. + * + * @param serviceClass the primitive service class + * @return the primitive type builder + */ + public Builder withServiceClass(Class serviceClass) { + this.serviceClass = serviceClass; + return this; + } + + /** + * Sets the primitive service configuration class. + * + * @param serviceConfigClass the primitive service configuration class + * @return the primitive type builder + */ + public Builder withServiceConfigClass(Class serviceConfigClass) { + this.serviceConfigClass = serviceConfigClass; + return this; + } + + /** + * Sets the primitive resource class. + * + * @param resourceClass the primitive resource class + * @return the primitive type builder + */ + public Builder withResourceClass(Class resourceClass) { + this.resourceClass = resourceClass; + return this; + } + + @Override + @SuppressWarnings("unchecked") + public PrimitiveType build() { + return new PrimitiveType(name, builderClass, configClass, primitiveClass, serviceClass, serviceConfigClass, resourceClass); + } + } } diff --git a/primitive/src/main/java/io/atomix/primitive/PrimitiveTypeRegistry.java b/primitive/src/main/java/io/atomix/primitive/PrimitiveTypeRegistry.java index caf11361ed..e9a73cad29 100644 --- a/primitive/src/main/java/io/atomix/primitive/PrimitiveTypeRegistry.java +++ b/primitive/src/main/java/io/atomix/primitive/PrimitiveTypeRegistry.java @@ -15,71 +15,40 @@ */ package io.atomix.primitive; -import com.google.common.collect.Maps; -import io.atomix.utils.config.ConfigurationException; - -import java.util.ArrayList; import java.util.Collection; -import java.util.Map; /** * Primitive registry. */ -public class PrimitiveTypeRegistry { - private final Map types = Maps.newConcurrentMap(); - - public PrimitiveTypeRegistry(ClassLoader classLoader) { - this(new ArrayList<>(), classLoader); - } - - public PrimitiveTypeRegistry(Collection> types, ClassLoader classLoader) { - for (PrimitiveType type : PrimitiveTypes.getPrimitiveTypes(classLoader)) { - this.types.put(type.id(), type); - } - for (Class typeClass : types) { - try { - PrimitiveType type = typeClass.newInstance(); - this.types.put(type.id(), type); - } catch (InstantiationException | IllegalAccessException e) { - throw new ConfigurationException("Failed to instantiate primitive type", e); - } - } - } +public interface PrimitiveTypeRegistry { /** * Registers a primitive type. * * @param type the primitive type */ - public void register(PrimitiveType type) { - types.put(type.id(), type); - } + void addPrimitiveType(PrimitiveType type); /** * Unregisters a primitive type. * * @param type the primitive type */ - public void unregister(PrimitiveType type) { - types.remove(type.id()); - } + void removePrimitiveType(PrimitiveType type); /** - * Returns a primitive type by name. + * Returns the collection of registered primitive types. * - * @param typeName the primitive type name - * @return the primitive type or {@code null} if no type with the given name is registered + * @return the collection of registered primitive types */ - public PrimitiveType get(String typeName) { - return types.get(typeName); - } + Collection getPrimitiveTypes(); /** - * Returns the number of registered primitive types. + * Returns the primitive type for the given name. * - * @return the number of registered primitive types + * @param typeName the primitive type name + * @return the primitive type */ - public int size() { - return types.size(); - } + PrimitiveType getPrimitiveType(String typeName); + } diff --git a/primitive/src/main/java/io/atomix/primitive/PrimitiveTypes.java b/primitive/src/main/java/io/atomix/primitive/PrimitiveTypes.java deleted file mode 100644 index 77cd8aac89..0000000000 --- a/primitive/src/main/java/io/atomix/primitive/PrimitiveTypes.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018-present Open Networking Foundation - * - * 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.atomix.primitive; - -import io.atomix.utils.config.ConfigurationException; -import io.atomix.utils.Services; - -import java.util.Collection; - -/** - * Primitive types. - */ -public class PrimitiveTypes { - - /** - * Loads all registered primitive types. - * - * @return a collection of all registered primitive types - */ - public static Collection getPrimitiveTypes(ClassLoader classLoader) { - return Services.loadAll(PrimitiveType.class, classLoader); - } - - /** - * Returns the primitive type for the given type. - * - * @param typeName the type name for which to return the primitive type - * @return the primitive type for the given type - */ - public static PrimitiveType getPrimitiveType(String typeName, ClassLoader classLoader) { - for (PrimitiveType type : Services.loadAll(PrimitiveType.class, classLoader)) { - if (type.id().replace("_", "-").equalsIgnoreCase(typeName.replace("_", "-"))) { - return type; - } - } - throw new ConfigurationException("Unknown primitive type: " + typeName); - } - - private PrimitiveTypes() { - } -} diff --git a/primitive/src/main/java/io/atomix/primitive/impl/DefaultPrimitiveTypeRegistry.java b/primitive/src/main/java/io/atomix/primitive/impl/DefaultPrimitiveTypeRegistry.java new file mode 100644 index 0000000000..dffb3d9f7f --- /dev/null +++ b/primitive/src/main/java/io/atomix/primitive/impl/DefaultPrimitiveTypeRegistry.java @@ -0,0 +1,64 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.primitive.impl; + +import com.google.common.collect.Maps; +import io.atomix.primitive.PrimitiveType; +import io.atomix.primitive.PrimitiveTypeRegistry; +import io.atomix.utils.config.ConfigurationException; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; + +/** + * Default primitive type registry. + */ +public class DefaultPrimitiveTypeRegistry implements PrimitiveTypeRegistry { + private final Map types = Maps.newConcurrentMap(); + + public DefaultPrimitiveTypeRegistry() { + this(new ArrayList<>()); + } + + public DefaultPrimitiveTypeRegistry(Collection types) { + types.forEach(type -> this.types.put(type.name(), type)); + } + + @Override + public void addPrimitiveType(PrimitiveType type) { + types.put(type.name(), type); + } + + @Override + public void removePrimitiveType(PrimitiveType type) { + types.remove(type.name()); + } + + @Override + public Collection getPrimitiveTypes() { + return types.values(); + } + + @Override + public PrimitiveType getPrimitiveType(String typeName) { + PrimitiveType type = types.get(typeName); + if (type == null) { + throw new ConfigurationException("Unknown primitive type " + typeName); + } + return type; + } +} diff --git a/primitive/src/main/java/io/atomix/primitive/impl/ImmutablePrimitiveTypeRegistry.java b/primitive/src/main/java/io/atomix/primitive/impl/ImmutablePrimitiveTypeRegistry.java new file mode 100644 index 0000000000..24c3c3d5a9 --- /dev/null +++ b/primitive/src/main/java/io/atomix/primitive/impl/ImmutablePrimitiveTypeRegistry.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.primitive.impl; + +import com.google.common.collect.ImmutableList; +import io.atomix.primitive.PrimitiveType; +import io.atomix.primitive.PrimitiveTypeRegistry; + +import java.util.Collection; + +/** + * Immutable primitive type registry. + */ +public class ImmutablePrimitiveTypeRegistry implements PrimitiveTypeRegistry { + private final PrimitiveTypeRegistry primitiveTypes; + + public ImmutablePrimitiveTypeRegistry(PrimitiveTypeRegistry primitiveTypes) { + this.primitiveTypes = primitiveTypes; + } + + @Override + public void addPrimitiveType(PrimitiveType type) { + throw new UnsupportedOperationException(); + } + + @Override + public void removePrimitiveType(PrimitiveType type) { + throw new UnsupportedOperationException(); + } + + @Override + public Collection getPrimitiveTypes() { + return ImmutableList.copyOf(primitiveTypes.getPrimitiveTypes()); + } + + @Override + public PrimitiveType getPrimitiveType(String typeName) { + return primitiveTypes.getPrimitiveType(typeName); + } +} diff --git a/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroup.java b/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroup.java index b40521aaa4..de0245030f 100644 --- a/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroup.java +++ b/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroup.java @@ -17,6 +17,7 @@ import com.google.common.hash.Hashing; import io.atomix.primitive.protocol.PrimitiveProtocol; +import io.atomix.primitive.protocol.PrimitiveProtocolType; import io.atomix.utils.config.Configured; import java.nio.charset.StandardCharsets; @@ -28,18 +29,6 @@ */ public interface PartitionGroup extends Configured { - /** - * Primitive protocol type. - */ - interface Type { - /** - * Returns the protocol type name. - * - * @return the protocol type name - */ - String name(); - } - /** * Returns the partition group name. * @@ -52,14 +41,14 @@ interface Type { * * @return the partition group type */ - Type type(); + String type(); /** * Returns the primitive protocol type supported by the partition group. * * @return the primitive protocol type supported by the partition group */ - PrimitiveProtocol.Type protocol(); + PrimitiveProtocolType protocol(); /** * Returns a new primitive protocol. diff --git a/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroupConfig.java b/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroupConfig.java index 0b569f71a1..b6ae1e629e 100644 --- a/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroupConfig.java +++ b/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroupConfig.java @@ -15,37 +15,22 @@ */ package io.atomix.primitive.partition; -import io.atomix.primitive.protocol.PrimitiveProtocol; -import io.atomix.utils.config.Config; +import io.atomix.utils.config.NamedConfig; +import io.atomix.utils.config.TypedConfig; /** * Partition group configuration. */ -public abstract class PartitionGroupConfig> implements Config { +public abstract class PartitionGroupConfig> implements TypedConfig, NamedConfig { private String name; private int partitions = getDefaultPartitions(); - /** - * Returns the primitive protocol type supported by the partition group. - * - * @return the primitive protocol type supported by the partition group - */ - public abstract PrimitiveProtocol.Type getType(); - - /** - * Returns the partition group name. - * - * @return the partition group name - */ + @Override public String getName() { return name; } - /** - * Sets the partition group name. - * - * @param name the partition group name - */ + @Override @SuppressWarnings("unchecked") public C setName(String name) { this.name = name; diff --git a/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroupFactory.java b/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroupFactory.java index cb6e27b49b..11423abb4a 100644 --- a/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroupFactory.java +++ b/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroupFactory.java @@ -15,40 +15,11 @@ */ package io.atomix.primitive.partition; -import io.atomix.utils.Generics; - /** * Partition group factory. */ public interface PartitionGroupFactory, P extends ManagedPartitionGroup> { - /** - * Returns the partition group protocol type. - * - * @return the partition group protocol type - */ - PartitionGroup.Type type(); - - /** - * Returns the partition group configuration class. - * - * @return the partition group configuration class - */ - @SuppressWarnings("unchecked") - default Class configClass() { - return (Class) Generics.getGenericInterfaceType(this, PartitionGroupFactory.class, 0); - } - - /** - * Returns the partition group class. - * - * @return the partition group class - */ - @SuppressWarnings("unchecked") - default Class groupClass() { - return (Class) Generics.getGenericInterfaceType(this, PartitionGroupFactory.class, 1); - } - /** * Creates a new partition group. * diff --git a/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroupType.java b/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroupType.java new file mode 100644 index 0000000000..0ac50689c0 --- /dev/null +++ b/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroupType.java @@ -0,0 +1,85 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.primitive.partition; + +import io.atomix.utils.AbstractNamed; +import io.atomix.utils.Type; +import io.atomix.utils.config.ConfigurationException; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Partition group type configuration. + */ +public class PartitionGroupType extends AbstractNamed implements Type { + private Class configClass; + private Class factoryClass; + + /** + * Returns the partition group configuration class. + * + * @return the partition group configuration class + */ + public Class configClass() { + return configClass; + } + + /** + * Returns the partition group factory class. + * + * @return the partition group factory class + */ + public Class factoryClass() { + return factoryClass; + } + + /** + * Creates a new partition group instance. + * + * @param config the partition group configuration + * @return the partition group + */ + @SuppressWarnings("unchecked") + public ManagedPartitionGroup newGroup(PartitionGroupConfig config) { + if (factoryClass == null) { + throw new ConfigurationException("No partition group factory class configured for group " + name()); + } + try { + return factoryClass.newInstance().createGroup(config); + } catch (InstantiationException | IllegalAccessException e) { + throw new ConfigurationException("Failed to instantiate partition group factory", e); + } + } + + @Override + public int hashCode() { + return Objects.hash(name()); + } + + @Override + public boolean equals(Object object) { + return object instanceof PartitionGroupType && Objects.equals(((PartitionGroupType) object).name(), name()); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("name", name()) + .toString(); + } +} diff --git a/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroupTypeRegistry.java b/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroupTypeRegistry.java new file mode 100644 index 0000000000..593c264c91 --- /dev/null +++ b/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroupTypeRegistry.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.primitive.partition; + +import java.util.Collection; + +/** + * Partition group type registry. + */ +public interface PartitionGroupTypeRegistry { + + /** + * Returns the collection of partition group type configurations. + * + * @return the collection of partition group type configurations + */ + Collection getGroupTypes(); + + /** + * Returns the partition group type with the given name. + * + * @param name the partition group type name + * @return the group type + */ + PartitionGroupType getGroupType(String name); + + /** + * Creates a new partition group. + * + * @param config the partition group configuration + * @return the partition group + */ + ManagedPartitionGroup createGroup(PartitionGroupConfig config); + +} diff --git a/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroups.java b/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroups.java deleted file mode 100644 index c094f7dc5e..0000000000 --- a/primitive/src/main/java/io/atomix/primitive/partition/PartitionGroups.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2018-present Open Networking Foundation - * - * 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.atomix.primitive.partition; - -import io.atomix.utils.Services; -import io.atomix.utils.config.ConfigurationException; - -import java.util.Collection; - -/** - * Partition groups. - */ -public class PartitionGroups { - - /** - * Creates a new protocol instance from the given configuration. - * - * @param config the configuration from which to create the protocol instance - * @return the protocol instance for the given configuration - */ - @SuppressWarnings("unchecked") - public static ManagedPartitionGroup createGroup(PartitionGroupConfig config, ClassLoader classLoader) { - for (PartitionGroupFactory factory : Services.loadAll(PartitionGroupFactory.class, classLoader)) { - if (factory.configClass().isAssignableFrom(config.getClass())) { - return factory.createGroup(config); - } - } - throw new ConfigurationException("Unknown partition group configuration type: " + config.getClass().getSimpleName()); - } - - /** - * Returns the partition group factory for the given type. - * - * @param type the type for which to return the factory - * @return the partition group factory for the given type - */ - public static PartitionGroupFactory getGroupFactory(String type, ClassLoader classLoader) { - for (PartitionGroupFactory factory : Services.loadAll(PartitionGroupFactory.class, classLoader)) { - if (factory.type().name().equals(type)) { - return factory; - } - } - throw new ConfigurationException("Unknown partition group type: " + type); - } - - /** - * Returns the partition group factories. - * - * @return the partition group factories - */ - public static Collection getGroupFactories(ClassLoader classLoader) { - return Services.loadAll(PartitionGroupFactory.class, classLoader); - } - - private PartitionGroups() { - } -} diff --git a/primitive/src/main/java/io/atomix/primitive/partition/PartitionService.java b/primitive/src/main/java/io/atomix/primitive/partition/PartitionService.java index 8e3a5edee3..70853c6dd4 100644 --- a/primitive/src/main/java/io/atomix/primitive/partition/PartitionService.java +++ b/primitive/src/main/java/io/atomix/primitive/partition/PartitionService.java @@ -16,6 +16,7 @@ package io.atomix.primitive.partition; import io.atomix.primitive.protocol.PrimitiveProtocol; +import io.atomix.primitive.protocol.PrimitiveProtocolType; import java.util.Collection; @@ -46,9 +47,9 @@ public interface PartitionService { * @return the first partition group that matches the given primitive type */ @SuppressWarnings("unchecked") - default PartitionGroup getPartitionGroup(PrimitiveProtocol.Type type) { + default PartitionGroup getPartitionGroup(PrimitiveProtocolType type) { return getPartitionGroups().stream() - .filter(group -> group.protocol().equals(type)) + .filter(group -> group.protocol().name().equals(type.name())) .findFirst() .orElse(null); } @@ -71,7 +72,13 @@ default PartitionGroup getPartitionGroup(PrimitiveProtocol protocol) { return systemGroup; } } - return getPartitionGroup(protocol.type()); + + for (PartitionGroup partitionGroup : getPartitionGroups()) { + if (partitionGroup.protocol().name().equals(protocol.type())) { + return partitionGroup; + } + } + return null; } /** diff --git a/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPartitionGroupMembershipService.java b/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPartitionGroupMembershipService.java index 4559dac40a..63e31b4e12 100644 --- a/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPartitionGroupMembershipService.java +++ b/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPartitionGroupMembershipService.java @@ -31,12 +31,12 @@ import io.atomix.primitive.partition.ManagedPartitionGroupMembershipService; import io.atomix.primitive.partition.MemberGroupStrategy; import io.atomix.primitive.partition.PartitionGroupConfig; -import io.atomix.primitive.partition.PartitionGroupFactory; import io.atomix.primitive.partition.PartitionGroupMembership; import io.atomix.primitive.partition.PartitionGroupMembershipEvent; import io.atomix.primitive.partition.PartitionGroupMembershipEventListener; import io.atomix.primitive.partition.PartitionGroupMembershipService; -import io.atomix.primitive.partition.PartitionGroups; +import io.atomix.primitive.partition.PartitionGroupType; +import io.atomix.primitive.partition.PartitionGroupTypeRegistry; import io.atomix.utils.concurrent.Futures; import io.atomix.utils.concurrent.SingleThreadContext; import io.atomix.utils.concurrent.ThreadContext; @@ -72,7 +72,7 @@ public class DefaultPartitionGroupMembershipService private final ClusterMembershipService membershipService; private final ClusterCommunicationService messagingService; - private final ClassLoader classLoader; + private final PartitionGroupTypeRegistry groupTypeRegistry; private final Serializer serializer; private volatile PartitionGroupMembership systemGroup; private final Map groups = Maps.newConcurrentMap(); @@ -84,12 +84,12 @@ public class DefaultPartitionGroupMembershipService public DefaultPartitionGroupMembershipService( ClusterMembershipService membershipService, ClusterCommunicationService messagingService, - ClassLoader classLoader, ManagedPartitionGroup systemGroup, - Collection groups) { + Collection groups, + PartitionGroupTypeRegistry groupTypeRegistry) { this.membershipService = membershipService; this.messagingService = messagingService; - this.classLoader = classLoader; + this.groupTypeRegistry = groupTypeRegistry; this.systemGroup = systemGroup != null ? new PartitionGroupMembership( systemGroup.name(), @@ -110,8 +110,8 @@ public DefaultPartitionGroupMembershipService( .register(PartitionGroupInfo.class) .register(PartitionGroupConfig.class) .register(MemberGroupStrategy.class); - for (PartitionGroupFactory factory : PartitionGroups.getGroupFactories(classLoader)) { - builder.register(factory.configClass()); + for (PartitionGroupType groupType : groupTypeRegistry.getGroupTypes()) { + builder.register(groupType.configClass()); } serializer = Serializer.using(builder.build()); } diff --git a/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPartitionGroupTypeRegistry.java b/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPartitionGroupTypeRegistry.java new file mode 100644 index 0000000000..4225b96f55 --- /dev/null +++ b/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPartitionGroupTypeRegistry.java @@ -0,0 +1,64 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.primitive.partition.impl; + +import com.google.common.collect.Maps; +import io.atomix.primitive.partition.ManagedPartitionGroup; +import io.atomix.primitive.partition.PartitionGroupConfig; +import io.atomix.primitive.partition.PartitionGroupFactory; +import io.atomix.primitive.partition.PartitionGroupType; +import io.atomix.primitive.partition.PartitionGroupTypeRegistry; +import io.atomix.utils.config.ConfigurationException; + +import java.util.Collection; +import java.util.Map; + +/** + * Default partition group type registry. + */ +public class DefaultPartitionGroupTypeRegistry implements PartitionGroupTypeRegistry { + private final Map partitionGroupTypes = Maps.newConcurrentMap(); + + public DefaultPartitionGroupTypeRegistry(Collection partitionGroupTypes) { + partitionGroupTypes.forEach(partitionGroupType -> this.partitionGroupTypes.put(partitionGroupType.name(), partitionGroupType)); + } + + @Override + public Collection getGroupTypes() { + return partitionGroupTypes.values(); + } + + @Override + public PartitionGroupType getGroupType(String name) { + return partitionGroupTypes.get(name); + } + + @Override + @SuppressWarnings("unchecked") + public ManagedPartitionGroup createGroup(PartitionGroupConfig config) { + PartitionGroupType typeConfig = partitionGroupTypes.get(config.getType()); + if (typeConfig == null) { + throw new ConfigurationException("Unknown partition group type " + config.getType()); + } + + try { + PartitionGroupFactory factory = typeConfig.factoryClass().newInstance(); + return factory.createGroup(config); + } catch (InstantiationException | IllegalAccessException e) { + throw new ConfigurationException("Failed to instantiate partition group factory", e); + } + } +} diff --git a/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPartitionService.java b/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPartitionService.java index cfe00d6ec0..a8d6e70fa0 100644 --- a/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPartitionService.java +++ b/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPartitionService.java @@ -27,7 +27,7 @@ import io.atomix.primitive.partition.PartitionGroupMembership; import io.atomix.primitive.partition.PartitionGroupMembershipEvent; import io.atomix.primitive.partition.PartitionGroupMembershipEventListener; -import io.atomix.primitive.partition.PartitionGroups; +import io.atomix.primitive.partition.PartitionGroupTypeRegistry; import io.atomix.primitive.partition.PartitionManagementService; import io.atomix.primitive.partition.PartitionService; import io.atomix.primitive.session.ManagedSessionIdService; @@ -54,13 +54,15 @@ public class DefaultPartitionService implements ManagedPartitionService { private final ClusterMembershipService clusterMembershipService; private final ClusterCommunicationService communicationService; - private final ClassLoader classLoader; private final PrimitiveTypeRegistry primitiveTypeRegistry; private final ManagedPartitionGroupMembershipService groupMembershipService; private ManagedPartitionGroup systemGroup; + private volatile ManagedPrimaryElectionService systemElectionService; + private volatile ManagedSessionIdService systemSessionIdService; private volatile ManagedPrimaryElectionService electionService; private volatile PartitionManagementService partitionManagementService; private final Map groups = Maps.newConcurrentMap(); + private final PartitionGroupTypeRegistry groupTypeRegistry; private final PartitionGroupMembershipEventListener groupMembershipEventListener = this::handleMembershipChange; private final AtomicBoolean started = new AtomicBoolean(); @@ -68,15 +70,16 @@ public class DefaultPartitionService implements ManagedPartitionService { public DefaultPartitionService( ClusterMembershipService membershipService, ClusterCommunicationService messagingService, - ClassLoader classLoader, PrimitiveTypeRegistry primitiveTypeRegistry, ManagedPartitionGroup systemGroup, - Collection groups) { + Collection groups, + PartitionGroupTypeRegistry groupTypeRegistry) { this.clusterMembershipService = membershipService; this.communicationService = messagingService; - this.classLoader = classLoader; this.primitiveTypeRegistry = primitiveTypeRegistry; - this.groupMembershipService = new DefaultPartitionGroupMembershipService(membershipService, messagingService, classLoader, systemGroup, groups); + this.groupTypeRegistry = groupTypeRegistry; + this.groupMembershipService = new DefaultPartitionGroupMembershipService( + membershipService, messagingService, systemGroup, groups, groupTypeRegistry); this.systemGroup = systemGroup; groups.forEach(group -> this.groups.put(group.name(), group)); } @@ -115,7 +118,7 @@ private void handleMembershipChange(PartitionGroupMembershipEvent event) { synchronized (groups) { ManagedPartitionGroup group = groups.get(event.membership().group()); if (group == null) { - group = PartitionGroups.createGroup(event.membership().config(), classLoader); + group = groupTypeRegistry.createGroup(event.membership().config()); groups.put(event.membership().group(), group); if (event.membership().members().contains(clusterMembershipService.getLocalMember().id())) { group.join(partitionManagementService); @@ -136,8 +139,11 @@ public CompletableFuture start() { PartitionGroupMembership systemGroupMembership = groupMembershipService.getSystemMembership(); if (systemGroupMembership != null) { if (systemGroup == null) { - systemGroup = PartitionGroups.createGroup(systemGroupMembership.config(), classLoader); + systemGroup = groupTypeRegistry.createGroup(systemGroupMembership.config()); } + + systemElectionService = new DefaultPrimaryElectionService(systemGroup, primitiveTypeRegistry); + systemSessionIdService = new ReplicatedSessionIdService(systemGroup, primitiveTypeRegistry); electionService = new HashBasedPrimaryElectionService(clusterMembershipService, groupMembershipService, communicationService); return electionService.start() .thenCompose(s -> { @@ -157,18 +163,14 @@ public CompletableFuture start() { return Futures.exceptionalFuture(new ConfigurationException("No system partition group found")); } }) - .thenCompose(v -> { - ManagedPrimaryElectionService systemElectionService = new DefaultPrimaryElectionService(systemGroup); - ManagedSessionIdService systemSessionIdService = new ReplicatedSessionIdService(systemGroup); - return systemElectionService.start() - .thenCompose(v2 -> systemSessionIdService.start()) - .thenApply(v2 -> new DefaultPartitionManagementService( - clusterMembershipService, - communicationService, - primitiveTypeRegistry, - systemElectionService, - systemSessionIdService)); - }) + .thenCompose(v -> systemElectionService.start() + .thenCompose(v2 -> systemSessionIdService.start()) + .thenApply(v2 -> new DefaultPartitionManagementService( + clusterMembershipService, + communicationService, + primitiveTypeRegistry, + systemElectionService, + systemSessionIdService))) .thenCompose(managementService -> { this.partitionManagementService = (PartitionManagementService) managementService; List futures = groupMembershipService.getMemberships().stream() @@ -177,7 +179,7 @@ public CompletableFuture start() { synchronized (groups) { group = groups.get(membership.group()); if (group == null) { - group = PartitionGroups.createGroup(membership.config(), classLoader); + group = groupTypeRegistry.createGroup(membership.config()); groups.put(group.name(), group); } } diff --git a/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPrimaryElectionService.java b/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPrimaryElectionService.java index 777140e298..d60a916ae5 100644 --- a/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPrimaryElectionService.java +++ b/primitive/src/main/java/io/atomix/primitive/partition/impl/DefaultPrimaryElectionService.java @@ -17,6 +17,8 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import io.atomix.primitive.PrimitiveType; +import io.atomix.primitive.PrimitiveTypeRegistry; import io.atomix.primitive.event.PrimitiveEvent; import io.atomix.primitive.partition.ManagedPrimaryElection; import io.atomix.primitive.partition.ManagedPrimaryElectionService; @@ -48,6 +50,10 @@ */ public class DefaultPrimaryElectionService implements ManagedPrimaryElectionService { private static final String PRIMITIVE_NAME = "atomix-primary-elector"; + private static final PrimitiveType PRIMITIVE_TYPE = PrimitiveType.builder() + .withName("PRIMARY_ELECTOR") + .withServiceClass(PrimaryElectorService.class) + .build(); private static final Serializer SERIALIZER = Serializer.using(KryoNamespace.builder() .register(PrimaryElectorOperations.NAMESPACE) @@ -64,8 +70,9 @@ public class DefaultPrimaryElectionService implements ManagedPrimaryElectionServ private final AtomicBoolean started = new AtomicBoolean(); private PartitionProxy proxy; - public DefaultPrimaryElectionService(PartitionGroup partitionGroup) { + public DefaultPrimaryElectionService(PartitionGroup partitionGroup, PrimitiveTypeRegistry primitiveTypeRegistry) { this.partitions = checkNotNull(partitionGroup); + primitiveTypeRegistry.addPrimitiveType(PRIMITIVE_TYPE); } @Override @@ -88,7 +95,7 @@ public void removeListener(PrimaryElectionEventListener listener) { @SuppressWarnings("unchecked") public CompletableFuture start() { return partitions.getPartitions().iterator().next().getProxyClient() - .proxyBuilder(PRIMITIVE_NAME, PrimaryElectorType.instance(), new ServiceConfig()) + .proxyBuilder(PRIMITIVE_NAME, PRIMITIVE_TYPE, new ServiceConfig()) .build() .connect() .thenAccept(proxy -> { diff --git a/primitive/src/main/java/io/atomix/primitive/partition/impl/ImmutablePartitionGroupTypeRegistry.java b/primitive/src/main/java/io/atomix/primitive/partition/impl/ImmutablePartitionGroupTypeRegistry.java new file mode 100644 index 0000000000..7a6b288a1f --- /dev/null +++ b/primitive/src/main/java/io/atomix/primitive/partition/impl/ImmutablePartitionGroupTypeRegistry.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.primitive.partition.impl; + +import com.google.common.collect.ImmutableList; +import io.atomix.primitive.partition.ManagedPartitionGroup; +import io.atomix.primitive.partition.PartitionGroupConfig; +import io.atomix.primitive.partition.PartitionGroupType; +import io.atomix.primitive.partition.PartitionGroupTypeRegistry; + +import java.util.Collection; + +/** + * Immutable partition group type registry. + */ +public class ImmutablePartitionGroupTypeRegistry implements PartitionGroupTypeRegistry { + private final PartitionGroupTypeRegistry partitionGroupTypes; + + public ImmutablePartitionGroupTypeRegistry(PartitionGroupTypeRegistry partitionGroupTypes) { + this.partitionGroupTypes = partitionGroupTypes; + } + + @Override + public Collection getGroupTypes() { + return ImmutableList.copyOf(partitionGroupTypes.getGroupTypes()); + } + + @Override + public PartitionGroupType getGroupType(String name) { + return partitionGroupTypes.getGroupType(name); + } + + @Override + public ManagedPartitionGroup createGroup(PartitionGroupConfig config) { + return partitionGroupTypes.createGroup(config); + } +} diff --git a/primitive/src/main/java/io/atomix/primitive/partition/impl/PrimaryElectorType.java b/primitive/src/main/java/io/atomix/primitive/partition/impl/PrimaryElectorType.java deleted file mode 100644 index 1c95489cbf..0000000000 --- a/primitive/src/main/java/io/atomix/primitive/partition/impl/PrimaryElectorType.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.primitive.partition.impl; - -import io.atomix.primitive.DistributedPrimitiveBuilder; -import io.atomix.primitive.PrimitiveConfig; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Primary elector primitive type. - */ -public class PrimaryElectorType implements PrimitiveType { - private static final String NAME = "PRIMARY_ELECTOR"; - private static final PrimaryElectorType TYPE = new PrimaryElectorType(); - - /** - * Returns a new primary elector type. - * - * @return a new primary elector type - */ - public static PrimaryElectorType instance() { - return TYPE; - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new PrimaryElectorService(config); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveConfig config, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocol.java b/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocol.java index 2006312456..9f9be8ba2f 100644 --- a/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocol.java +++ b/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocol.java @@ -25,24 +25,12 @@ */ public interface PrimitiveProtocol { - /** - * Primitive protocol type. - */ - interface Type { - /** - * Returns the protocol type name. - * - * @return the protocol type name - */ - String name(); - } - /** * Returns the protocol type. * * @return the protocol type */ - Type type(); + String type(); /** * Returns the protocol group name. diff --git a/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocolConfig.java b/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocolConfig.java index 5109088c8c..e7377bf1c8 100644 --- a/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocolConfig.java +++ b/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocolConfig.java @@ -15,21 +15,14 @@ */ package io.atomix.primitive.protocol; -import io.atomix.utils.config.Config; +import io.atomix.utils.config.TypedConfig; /** * Primitive protocol configuration. */ -public abstract class PrimitiveProtocolConfig> implements Config { +public abstract class PrimitiveProtocolConfig> implements TypedConfig { private String group; - /** - * Returns the primitive protocol type. - * - * @return the primitive protocol type - */ - public abstract PrimitiveProtocol.Type getType(); - /** * Returns the protocol group. * diff --git a/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocolFactory.java b/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocolFactory.java index 9fbf2233c5..1c330d98ff 100644 --- a/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocolFactory.java +++ b/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocolFactory.java @@ -15,46 +15,17 @@ */ package io.atomix.primitive.protocol; -import io.atomix.utils.Generics; - /** * Primitive protocol factory. */ public interface PrimitiveProtocolFactory, P extends PrimitiveProtocol> { - /** - * Returns the protocol type. - * - * @return the protocol type - */ - PrimitiveProtocol.Type type(); - - /** - * Returns the protocol configuration class. - * - * @return the protocol configuration class - */ - @SuppressWarnings("unchecked") - default Class configClass() { - return (Class) Generics.getGenericInterfaceType(this, PrimitiveProtocolFactory.class, 0); - } - - /** - * Returns the protocol class. - * - * @return the protocol class - */ - @SuppressWarnings("unchecked") - default Class protocolClass() { - return (Class) Generics.getGenericInterfaceType(this, PrimitiveProtocolFactory.class, 1); - } - /** * Creates a new primitive protocol. * * @param config the protocol configuration * @return the primitive protocol */ - P create(C config); + P createProtocol(C config); } diff --git a/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocolType.java b/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocolType.java new file mode 100644 index 0000000000..ebdac20b8d --- /dev/null +++ b/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocolType.java @@ -0,0 +1,214 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.primitive.protocol; + +import io.atomix.utils.AbstractNamed; +import io.atomix.utils.Type; +import io.atomix.utils.config.Config; +import io.atomix.utils.config.ConfigurationException; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Distributed primitive protocol type. + */ +public class PrimitiveProtocolType extends AbstractNamed implements Type, Config { + + /** + * Returns a new protocol type builder. + * + * @return the protocol type builder + */ + public static Builder builder() { + return new Builder(null); + } + + /** + * Returns a new protocol type builder. + * + * @param name the protocol type name + * @return the protocol type builder + */ + public static Builder builder(String name) { + return new Builder(name); + } + + private Class configClass; + private Class factoryClass; + private Class protocolClass; + + public PrimitiveProtocolType() { + this(null, null, null, null); + } + + private PrimitiveProtocolType( + String name, + Class configClass, + Class factoryClass, + Class protocolClass) { + super(name); + this.configClass = configClass; + this.factoryClass = factoryClass; + this.protocolClass = protocolClass; + } + + /** + * Returns the protocol configuration class. + * + * @return the protocol configuration class + */ + public Class configClass() { + return configClass; + } + + /** + * Returns the protocol factory class. + * + * @return the protocol factory class + */ + public Class factoryClass() { + return factoryClass; + } + + /** + * Returns the protocol class. + * + * @return the protocol class + */ + public Class protocolClass() { + return protocolClass; + } + + /** + * Creates a new protocol instance. + * + * @param config the protocol configuration + * @return the protocol instance + */ + @SuppressWarnings("unchecked") + public PrimitiveProtocol createProtocol(PrimitiveProtocolConfig config) { + if (factoryClass != null) { + try { + return factoryClass.newInstance().createProtocol(config); + } catch (InstantiationException | IllegalAccessException e) { + throw new ConfigurationException("Failed to instantiate protocol factory", e); + } + } + + if (protocolClass != null) { + try { + Constructor constructor = protocolClass.getConstructor(configClass); + return constructor.newInstance(config); + } catch (NoSuchMethodException e) { + try { + Constructor constructor = protocolClass.getConstructor(PrimitiveProtocolConfig.class); + return constructor.newInstance(config); + } catch (NoSuchMethodException e2) { + throw new ConfigurationException("No configuration constructor found for protocol class " + protocolClass.getName()); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e2) { + throw new ConfigurationException("Failed to instantiate primitive protocol", e2); + } + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new ConfigurationException("Failed to instantiate primitive protocol", e); + } + } + throw new ConfigurationException("No protocol factory specified"); + } + + @Override + public int hashCode() { + return Objects.hash(name()); + } + + @Override + public boolean equals(Object object) { + return object instanceof PrimitiveProtocolType && Objects.equals(((PrimitiveProtocolType) object).name(), name()); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("name", name()) + .toString(); + } + + /** + * Primitive protocol type builder. + */ + public static class Builder implements io.atomix.utils.Builder { + private String name; + private Class configClass; + private Class factoryClass; + private Class protocolClass; + + private Builder(String name) { + this.name = name; + } + + /** + * Sets the protocol type name. + * + * @param name the protocol type name + * @return the protocol type builder + */ + public Builder withName(String name) { + this.name = name; + return this; + } + + /** + * Sets the protocol configuration class. + * + * @param configClass the protocol configuration class + * @return the protocol type builder + */ + public Builder withConfigClass(Class configClass) { + this.configClass = configClass; + return this; + } + + /** + * Sets the protocol factory class. + * + * @param factoryClass the protocol factory class + * @return the protocol type builder + */ + public Builder withFactoryClass(Class factoryClass) { + this.factoryClass = factoryClass; + return this; + } + + /** + * Sets the protocol class. + * + * @param protocolClass the protocol class + * @return the protocol type builder + */ + public Builder withProtocolClass(Class protocolClass) { + this.protocolClass = protocolClass; + return this; + } + + @Override + public PrimitiveProtocolType build() { + return new PrimitiveProtocolType(name, configClass, factoryClass, protocolClass); + } + } +} diff --git a/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocolTypeRegistry.java b/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocolTypeRegistry.java new file mode 100644 index 0000000000..8c2cdc915b --- /dev/null +++ b/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocolTypeRegistry.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.primitive.protocol; + +import java.util.Collection; + +/** + * Primitive protocol type registry. + */ +public interface PrimitiveProtocolTypeRegistry { + + /** + * Returns the collection of registered protocol types. + * + * @return the collection of registered protocol types + */ + Collection getProtocolTypes(); + + /** + * Returns the protocol type for the given configuration. + * + * @param type the type name for which to return the protocol type + * @return the protocol type for the given configuration + */ + PrimitiveProtocolType getProtocolType(String type); + + /** + * Creates a new protocol instance. + * + * @param config the protocol configuration + * @return the protocol instance + */ + PrimitiveProtocol createProtocol(PrimitiveProtocolConfig config); + +} diff --git a/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocols.java b/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocols.java deleted file mode 100644 index 914544f4ae..0000000000 --- a/primitive/src/main/java/io/atomix/primitive/protocol/PrimitiveProtocols.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2018-present Open Networking Foundation - * - * 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.atomix.primitive.protocol; - -import io.atomix.utils.Services; -import io.atomix.utils.config.ConfigurationException; - -/** - * Primitive protocols. - */ -public class PrimitiveProtocols { - - /** - * Creates a new protocol instance from the given configuration. - * - * @param config the configuration from which to create the protocol instance - * @return the protocol instance for the given configuration - */ - @SuppressWarnings("unchecked") - public static PrimitiveProtocol createProtocol(PrimitiveProtocolConfig config, ClassLoader classLoader) { - for (PrimitiveProtocolFactory factory : Services.loadAll(PrimitiveProtocolFactory.class, classLoader)) { - if (factory.type().equals(config.getType())) { - return factory.create(config); - } - } - throw new ConfigurationException("Unknown protocol configuration type: " + config.getClass().getSimpleName()); - } - - /** - * Returns the protocol factory for the given type. - * - * @param type the type for which to return the factory - * @return the protocol factory for the given type - */ - public static PrimitiveProtocolFactory getProtocolFactory(String type, ClassLoader classLoader) { - for (PrimitiveProtocolFactory factory : Services.loadAll(PrimitiveProtocolFactory.class, classLoader)) { - if (factory.type().name().equals(type)) { - return factory; - } - } - throw new ConfigurationException("Unknown protocol type: " + type); - } - - private PrimitiveProtocols() { - } -} diff --git a/primitive/src/main/java/io/atomix/primitive/protocol/impl/DefaultPrimitiveProtocolTypeRegistry.java b/primitive/src/main/java/io/atomix/primitive/protocol/impl/DefaultPrimitiveProtocolTypeRegistry.java new file mode 100644 index 0000000000..6b5eddf703 --- /dev/null +++ b/primitive/src/main/java/io/atomix/primitive/protocol/impl/DefaultPrimitiveProtocolTypeRegistry.java @@ -0,0 +1,57 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.primitive.protocol.impl; + +import com.google.common.collect.Maps; +import io.atomix.primitive.protocol.PrimitiveProtocol; +import io.atomix.primitive.protocol.PrimitiveProtocolConfig; +import io.atomix.primitive.protocol.PrimitiveProtocolType; +import io.atomix.primitive.protocol.PrimitiveProtocolTypeRegistry; +import io.atomix.utils.config.ConfigurationException; + +import java.util.Collection; +import java.util.Map; + +/** + * Default primitive protocol type registry. + */ +public class DefaultPrimitiveProtocolTypeRegistry implements PrimitiveProtocolTypeRegistry { + private final Map protocolTypes = Maps.newConcurrentMap(); + + public DefaultPrimitiveProtocolTypeRegistry(Collection protocolTypes) { + protocolTypes.forEach(protocolType -> this.protocolTypes.put(protocolType.name(), protocolType)); + } + + @Override + public Collection getProtocolTypes() { + return protocolTypes.values(); + } + + @Override + public PrimitiveProtocolType getProtocolType(String type) { + return protocolTypes.get(type); + } + + @Override + @SuppressWarnings("unchecked") + public PrimitiveProtocol createProtocol(PrimitiveProtocolConfig config) { + PrimitiveProtocolType protocolType = protocolTypes.get(config.getType()); + if (protocolType == null) { + throw new ConfigurationException("Unknown protocol type " + config.getType()); + } + return protocolType.createProtocol(config); + } +} diff --git a/primitive/src/main/java/io/atomix/primitive/protocol/impl/ImmutablePrimitiveProtocolTypeRegistry.java b/primitive/src/main/java/io/atomix/primitive/protocol/impl/ImmutablePrimitiveProtocolTypeRegistry.java new file mode 100644 index 0000000000..4cd380bbc9 --- /dev/null +++ b/primitive/src/main/java/io/atomix/primitive/protocol/impl/ImmutablePrimitiveProtocolTypeRegistry.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.primitive.protocol.impl; + +import com.google.common.collect.ImmutableList; +import io.atomix.primitive.protocol.PrimitiveProtocol; +import io.atomix.primitive.protocol.PrimitiveProtocolConfig; +import io.atomix.primitive.protocol.PrimitiveProtocolType; +import io.atomix.primitive.protocol.PrimitiveProtocolTypeRegistry; + +import java.util.Collection; + +/** + * Immutable primitive protocol type registry. + */ +public class ImmutablePrimitiveProtocolTypeRegistry implements PrimitiveProtocolTypeRegistry { + private final PrimitiveProtocolTypeRegistry protocolTypes; + + public ImmutablePrimitiveProtocolTypeRegistry(PrimitiveProtocolTypeRegistry protocolTypes) { + this.protocolTypes = protocolTypes; + } + + @Override + public Collection getProtocolTypes() { + return ImmutableList.copyOf(protocolTypes.getProtocolTypes()); + } + + @Override + public PrimitiveProtocolType getProtocolType(String name) { + return protocolTypes.getProtocolType(name); + } + + @Override + public PrimitiveProtocol createProtocol(PrimitiveProtocolConfig config) { + return protocolTypes.createProtocol(config); + } +} diff --git a/primitive/src/main/java/io/atomix/primitive/service/AbstractPrimitiveService.java b/primitive/src/main/java/io/atomix/primitive/service/AbstractPrimitiveService.java index 75dfb0671a..c2141642a6 100644 --- a/primitive/src/main/java/io/atomix/primitive/service/AbstractPrimitiveService.java +++ b/primitive/src/main/java/io/atomix/primitive/service/AbstractPrimitiveService.java @@ -30,6 +30,7 @@ import io.atomix.utils.concurrent.Scheduler; import io.atomix.utils.logging.ContextualLoggerFactory; import io.atomix.utils.logging.LoggerContext; +import io.atomix.utils.serializer.Serializer; import io.atomix.utils.time.Clock; import io.atomix.utils.time.LogicalClock; import io.atomix.utils.time.WallClock; @@ -64,6 +65,11 @@ protected AbstractPrimitiveService(Class clientInterface, F config) { this.config = config; } + @Override + public Serializer serializer() { + return getPrimitiveType().serializer(); + } + /** * Encodes the given object using the configured {@link #serializer()}. * diff --git a/primitive/src/main/java/io/atomix/primitive/session/impl/ReplicatedSessionIdService.java b/primitive/src/main/java/io/atomix/primitive/session/impl/ReplicatedSessionIdService.java index 40f995ac0f..0c80dca1f1 100644 --- a/primitive/src/main/java/io/atomix/primitive/session/impl/ReplicatedSessionIdService.java +++ b/primitive/src/main/java/io/atomix/primitive/session/impl/ReplicatedSessionIdService.java @@ -15,6 +15,8 @@ */ package io.atomix.primitive.session.impl; +import io.atomix.primitive.PrimitiveType; +import io.atomix.primitive.PrimitiveTypeRegistry; import io.atomix.primitive.partition.PartitionGroup; import io.atomix.primitive.proxy.PartitionProxy; import io.atomix.primitive.service.ServiceConfig; @@ -38,13 +40,18 @@ public class ReplicatedSessionIdService implements ManagedSessionIdService { .register(SessionIdGeneratorOperations.NAMESPACE) .build()); private static final String PRIMITIVE_NAME = "session-id"; + private static final PrimitiveType PRIMITIVE_TYPE = PrimitiveType.builder() + .withName("SESSION_ID_GENERATOR") + .withServiceClass(SessionIdGeneratorService.class) + .build(); private final PartitionGroup systemPartitionGroup; private PartitionProxy proxy; private final AtomicBoolean started = new AtomicBoolean(); - public ReplicatedSessionIdService(PartitionGroup systemPartitionGroup) { + public ReplicatedSessionIdService(PartitionGroup systemPartitionGroup, PrimitiveTypeRegistry primitiveTypeRegistry) { this.systemPartitionGroup = systemPartitionGroup; + primitiveTypeRegistry.addPrimitiveType(PRIMITIVE_TYPE); } @Override @@ -57,7 +64,7 @@ public CompletableFuture nextSessionId() { @Override public CompletableFuture start() { return systemPartitionGroup.getPartitions().iterator().next().getProxyClient() - .proxyBuilder(PRIMITIVE_NAME, SessionIdGeneratorType.instance(), new ServiceConfig()) + .proxyBuilder(PRIMITIVE_NAME, PRIMITIVE_TYPE, new ServiceConfig()) .build() .connect() .thenApply(proxy -> { diff --git a/primitive/src/main/java/io/atomix/primitive/session/impl/SessionIdGeneratorType.java b/primitive/src/main/java/io/atomix/primitive/session/impl/SessionIdGeneratorType.java deleted file mode 100644 index 6c7de261cd..0000000000 --- a/primitive/src/main/java/io/atomix/primitive/session/impl/SessionIdGeneratorType.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.primitive.session.impl; - -import io.atomix.primitive.DistributedPrimitiveBuilder; -import io.atomix.primitive.PrimitiveConfig; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Session ID generator primitive type. - */ -public class SessionIdGeneratorType implements PrimitiveType { - private static final String NAME = "SESSION_ID_GENERATOR"; - private static final SessionIdGeneratorType TYPE = new SessionIdGeneratorType(); - - /** - * Returns a new session ID generator type. - * - * @return a new session ID generator type - */ - public static SessionIdGeneratorType instance() { - return TYPE; - } - - @Override - public String id() { - return NAME; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new SessionIdGeneratorService(config); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveConfig config, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("id", id()) - .toString(); - } -} diff --git a/primitive/src/test/java/io/atomix/primitive/TestPrimitiveType.java b/primitive/src/test/java/io/atomix/primitive/TestPrimitiveType.java deleted file mode 100644 index d1bc553822..0000000000 --- a/primitive/src/test/java/io/atomix/primitive/TestPrimitiveType.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.primitive; - -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -/** - * Test primitive type. - */ -public class TestPrimitiveType implements PrimitiveType { - @Override - public String id() { - return "test"; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - throw new UnsupportedOperationException(); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveConfig config, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } -} diff --git a/primitive/src/test/java/io/atomix/primitive/service/DefaultServiceExecutorTest.java b/primitive/src/test/java/io/atomix/primitive/service/DefaultServiceExecutorTest.java index a37c785fb8..a6f415d0f7 100644 --- a/primitive/src/test/java/io/atomix/primitive/service/DefaultServiceExecutorTest.java +++ b/primitive/src/test/java/io/atomix/primitive/service/DefaultServiceExecutorTest.java @@ -16,7 +16,7 @@ package io.atomix.primitive.service; import io.atomix.primitive.PrimitiveId; -import io.atomix.primitive.TestPrimitiveType; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.operation.OperationId; import io.atomix.primitive.operation.OperationType; import io.atomix.primitive.service.impl.DefaultCommit; @@ -95,7 +95,7 @@ public void testScheduling() throws Exception { private ServiceExecutor executor() { ServiceContext context = mock(ServiceContext.class); when(context.serviceId()).thenReturn(PrimitiveId.from(1)); - when(context.serviceType()).thenReturn(new TestPrimitiveType()); + when(context.serviceType()).thenReturn(PrimitiveType.builder("test").build()); when(context.serviceName()).thenReturn("test"); when(context.currentOperation()).thenReturn(OperationType.COMMAND); return new DefaultServiceExecutor(context, Serializer.using(KryoNamespaces.BASIC)); diff --git a/primitive/src/test/java/io/atomix/primitive/session/SessionMetadataTest.java b/primitive/src/test/java/io/atomix/primitive/session/SessionMetadataTest.java index a13043ba03..7e79591145 100644 --- a/primitive/src/test/java/io/atomix/primitive/session/SessionMetadataTest.java +++ b/primitive/src/test/java/io/atomix/primitive/session/SessionMetadataTest.java @@ -15,7 +15,6 @@ */ package io.atomix.primitive.session; -import io.atomix.primitive.TestPrimitiveType; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -29,6 +28,6 @@ public void testRaftSessionMetadata() throws Exception { SessionMetadata metadata = new SessionMetadata(1, "foo", "test"); assertEquals(SessionId.from(1), metadata.sessionId()); assertEquals("foo", metadata.primitiveName()); - assertEquals(new TestPrimitiveType().id(), metadata.primitiveType()); + assertEquals("test", metadata.primitiveType()); } } diff --git a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/MultiPrimaryProtocol.java b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/MultiPrimaryProtocol.java index a5faf831e2..67f5840c27 100644 --- a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/MultiPrimaryProtocol.java +++ b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/MultiPrimaryProtocol.java @@ -26,7 +26,6 @@ import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.proxy.impl.PartitionedPrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; -import io.atomix.protocols.backup.partition.PrimaryBackupPartition; import java.time.Duration; import java.util.Collection; @@ -40,19 +39,7 @@ * Multi-primary protocol. */ public class MultiPrimaryProtocol implements PrimitiveProtocol { - public static final Type TYPE = new Type(); - - /** - * The multi-primary protocol type. - */ - public static class Type implements PrimitiveProtocol.Type { - private static final String NAME = "multi-primary"; - - @Override - public String name() { - return NAME; - } - } + public static final String NAME = "multi-primary"; /** * Returns a new multi-primary protocol builder. @@ -80,8 +67,8 @@ protected MultiPrimaryProtocol(MultiPrimaryProtocolConfig config) { } @Override - public PrimitiveProtocol.Type type() { - return TYPE; + public String type() { + return config.getType(); } @Override diff --git a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/MultiPrimaryProtocolConfig.java b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/MultiPrimaryProtocolConfig.java index 8ed30c94ff..d7bf90352e 100644 --- a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/MultiPrimaryProtocolConfig.java +++ b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/MultiPrimaryProtocolConfig.java @@ -19,7 +19,6 @@ import io.atomix.primitive.Recovery; import io.atomix.primitive.Replication; import io.atomix.primitive.partition.Partitioner; -import io.atomix.primitive.protocol.PrimitiveProtocol; import io.atomix.primitive.protocol.PrimitiveProtocolConfig; import java.time.Duration; @@ -39,8 +38,8 @@ public class MultiPrimaryProtocolConfig extends PrimitiveProtocolConfig { @Override - public PrimitiveProtocol.Type type() { - return MultiPrimaryProtocol.TYPE; - } - - @Override - public MultiPrimaryProtocol create(MultiPrimaryProtocolConfig config) { + public MultiPrimaryProtocol createProtocol(MultiPrimaryProtocolConfig config) { return new MultiPrimaryProtocol(config); } } diff --git a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/PrimaryBackupClient.java b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/PrimaryBackupClient.java index bae82a9b85..7fb692c8d6 100644 --- a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/PrimaryBackupClient.java +++ b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/PrimaryBackupClient.java @@ -35,7 +35,6 @@ import io.atomix.utils.concurrent.ThreadModel; import io.atomix.utils.logging.ContextualLoggerFactory; import io.atomix.utils.logging.LoggerContext; -import io.atomix.utils.serializer.Serializer; import org.slf4j.Logger; import java.util.concurrent.CompletableFuture; @@ -88,7 +87,7 @@ public PrimaryBackupClient( @Override public PrimaryBackupProxy.Builder proxyBuilder(String primitiveName, PrimitiveType primitiveType, ServiceConfig serviceConfig) { - byte[] configBytes = Serializer.using(primitiveType.namespace()).encode(serviceConfig); + byte[] configBytes = primitiveType.serializer().encode(serviceConfig); return new PrimaryBackupProxy.Builder() { @Override public PartitionProxy build() { @@ -99,7 +98,7 @@ public PartitionProxy build() { primitiveType, new PrimitiveDescriptor( primitiveName, - primitiveType.id(), + primitiveType.name(), configBytes, numBackups, replication), diff --git a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/PrimaryBackupServer.java b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/PrimaryBackupServer.java index 6251a915b8..65d7266f93 100644 --- a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/PrimaryBackupServer.java +++ b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/PrimaryBackupServer.java @@ -18,6 +18,7 @@ import io.atomix.cluster.ClusterMembershipService; import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.PrimitiveTypeRegistry; +import io.atomix.primitive.impl.DefaultPrimitiveTypeRegistry; import io.atomix.primitive.partition.MemberGroupProvider; import io.atomix.primitive.partition.PrimaryElection; import io.atomix.primitive.partition.impl.DefaultMemberGroupService; @@ -105,11 +106,10 @@ public CompletableFuture stop() { */ public static class Builder implements io.atomix.utils.Builder { protected String serverName = "atomix"; - protected ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); protected ClusterMembershipService membershipService; protected PrimaryBackupServerProtocol protocol; protected PrimaryElection primaryElection; - protected PrimitiveTypeRegistry primitiveTypes = new PrimitiveTypeRegistry(classLoader); + protected PrimitiveTypeRegistry primitiveTypes = new DefaultPrimitiveTypeRegistry(); protected MemberGroupProvider memberGroupProvider; protected ThreadModel threadModel = ThreadModel.SHARED_THREAD_POOL; protected int threadPoolSize = Runtime.getRuntime().availableProcessors(); @@ -127,18 +127,6 @@ public Builder withServerName(String serverName) { return this; } - /** - * Sets the class loader. - * - * @param classLoader the class loader - * @return the server builder - */ - public Builder withClassLoader(ClassLoader classLoader) { - this.classLoader = checkNotNull(classLoader, "classLoader cannot be null"); - primitiveTypes = new PrimitiveTypeRegistry(classLoader); - return this; - } - /** * Sets the cluster membership service. * @@ -192,7 +180,7 @@ public Builder withPrimitiveTypes(PrimitiveTypeRegistry primitiveTypes) { * @throws NullPointerException if the {@code primitiveType} is {@code null} */ public Builder addPrimitiveType(PrimitiveType primitiveType) { - primitiveTypes.register(primitiveType); + primitiveTypes.addPrimitiveType(primitiveType); return this; } diff --git a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/impl/PrimaryBackupServerContext.java b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/impl/PrimaryBackupServerContext.java index db8c521a71..490106c664 100644 --- a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/impl/PrimaryBackupServerContext.java +++ b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/impl/PrimaryBackupServerContext.java @@ -18,9 +18,10 @@ import com.google.common.collect.Maps; import io.atomix.cluster.ClusterMembershipService; import io.atomix.primitive.PrimitiveId; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.PrimitiveTypeRegistry; -import io.atomix.primitive.partition.ManagedMemberGroupService; import io.atomix.primitive.partition.GroupMember; +import io.atomix.primitive.partition.ManagedMemberGroupService; import io.atomix.primitive.partition.MemberGroup; import io.atomix.primitive.partition.PrimaryElection; import io.atomix.protocols.backup.PrimaryBackupServer.Role; @@ -139,10 +140,11 @@ private CompletableFuture close(CloseRequest request) { */ private CompletableFuture getService(PrimitiveRequest request) { return services.computeIfAbsent(request.primitive().name(), n -> { + PrimitiveType primitiveType = primitiveTypes.getPrimitiveType(request.primitive().type()); PrimaryBackupServiceContext service = new PrimaryBackupServiceContext( serverName, PrimitiveId.from(request.primitive().name()), - primitiveTypes.get(request.primitive().type()), + primitiveType, request.primitive(), threadContextFactory.createContext(), clusterMembershipService, @@ -167,7 +169,7 @@ private CompletableFuture getService(PrimitiveReque */ private CompletableFuture metadata(MetadataRequest request) { return CompletableFuture.completedFuture(MetadataResponse.ok(services.entrySet().stream() - .filter(entry -> entry.getValue().join().serviceType().id().equals(request.primitiveType())) + .filter(entry -> entry.getValue().join().serviceType().name().equals(request.primitiveType())) .map(entry -> entry.getKey()) .collect(Collectors.toSet()))); } diff --git a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/partition/PrimaryBackupPartitionGroup.java b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/partition/PrimaryBackupPartitionGroup.java index c7ebcc57e7..546fd59f3d 100644 --- a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/partition/PrimaryBackupPartitionGroup.java +++ b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/partition/PrimaryBackupPartitionGroup.java @@ -29,6 +29,7 @@ import io.atomix.primitive.partition.PartitionId; import io.atomix.primitive.partition.PartitionManagementService; import io.atomix.primitive.protocol.PrimitiveProtocol; +import io.atomix.primitive.protocol.PrimitiveProtocolType; import io.atomix.protocols.backup.MultiPrimaryProtocol; import io.atomix.utils.concurrent.ThreadContextFactory; import io.atomix.utils.concurrent.ThreadPoolContextFactory; @@ -51,7 +52,6 @@ * Primary-backup partition group. */ public class PrimaryBackupPartitionGroup implements ManagedPartitionGroup { - public static final PartitionGroup.Type TYPE = new Type(); /** * Returns a new primary-backup partition group builder. @@ -63,18 +63,6 @@ public static Builder builder(String name) { return new Builder(new PrimaryBackupPartitionGroupConfig().setName(name)); } - /** - * The primary-backup partition group type. - */ - public static class Type implements PartitionGroup.Type { - private static final String NAME = "primary-backup"; - - @Override - public String name() { - return NAME; - } - } - private static Collection buildPartitions(PrimaryBackupPartitionGroupConfig config) { List partitions = new ArrayList<>(config.getPartitions()); for (int i = 0; i < config.getPartitions(); i++) { @@ -86,6 +74,7 @@ private static Collection buildPartitions(PrimaryBackupP private static final Logger LOGGER = LoggerFactory.getLogger(PrimaryBackupPartitionGroup.class); private final String name; + private final String type; private final PrimaryBackupPartitionGroupConfig config; private final Map partitions = Maps.newConcurrentMap(); private final List sortedPartitionIds = Lists.newCopyOnWriteArrayList(); @@ -94,6 +83,7 @@ private static Collection buildPartitions(PrimaryBackupP public PrimaryBackupPartitionGroup(PrimaryBackupPartitionGroupConfig config) { this.config = config; this.name = checkNotNull(config.getName()); + this.type = config.getType(); buildPartitions(config).forEach(p -> { this.partitions.put(p.id(), p); this.sortedPartitionIds.add(p.id()); @@ -107,13 +97,16 @@ public String name() { } @Override - public PartitionGroup.Type type() { - return TYPE; + public String type() { + return type; } @Override - public PrimitiveProtocol.Type protocol() { - return MultiPrimaryProtocol.TYPE; + public PrimitiveProtocolType protocol() { + return PrimitiveProtocolType.builder() + .withName(MultiPrimaryProtocol.NAME) + .withProtocolClass(MultiPrimaryProtocol.class) + .build(); } @Override diff --git a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/partition/PrimaryBackupPartitionGroupConfig.java b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/partition/PrimaryBackupPartitionGroupConfig.java index 616de7408f..08dac15a4a 100644 --- a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/partition/PrimaryBackupPartitionGroupConfig.java +++ b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/partition/PrimaryBackupPartitionGroupConfig.java @@ -18,8 +18,6 @@ import io.atomix.primitive.partition.MemberGroupProvider; import io.atomix.primitive.partition.MemberGroupStrategy; import io.atomix.primitive.partition.PartitionGroupConfig; -import io.atomix.primitive.protocol.PrimitiveProtocol; -import io.atomix.protocols.backup.MultiPrimaryProtocol; /** * Primary-backup partition group configuration. @@ -30,8 +28,8 @@ public class PrimaryBackupPartitionGroupConfig extends PartitionGroupConfig { - @Override - public PartitionGroup.Type type() { - return PrimaryBackupPartitionGroup.TYPE; - } - @Override public PrimaryBackupPartitionGroup createGroup(PrimaryBackupPartitionGroupConfig config) { return new PrimaryBackupPartitionGroup(config); diff --git a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/proxy/PrimaryBackupProxy.java b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/proxy/PrimaryBackupProxy.java index c5ce1e5574..6e30684c5d 100644 --- a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/proxy/PrimaryBackupProxy.java +++ b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/proxy/PrimaryBackupProxy.java @@ -102,7 +102,7 @@ public PrimaryBackupProxy( primaryElection.addListener(primaryElectionListener); this.log = ContextualLoggerFactory.getLogger(getClass(), LoggerContext.builder(PartitionProxy.class) .addValue(clientName) - .add("type", primitiveType.id()) + .add("type", primitiveType.name()) .add("name", descriptor.name()) .build()); } diff --git a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/service/impl/PrimaryBackupServiceContext.java b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/service/impl/PrimaryBackupServiceContext.java index ae14eaaaf1..408b6f52e7 100644 --- a/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/service/impl/PrimaryBackupServiceContext.java +++ b/protocols/primary-backup/src/main/java/io/atomix/protocols/backup/service/impl/PrimaryBackupServiceContext.java @@ -55,7 +55,6 @@ import io.atomix.utils.concurrent.ThreadContext; import io.atomix.utils.logging.ContextualLoggerFactory; import io.atomix.utils.logging.LoggerContext; -import io.atomix.utils.serializer.Serializer; import io.atomix.utils.time.LogicalClock; import io.atomix.utils.time.LogicalTimestamp; import io.atomix.utils.time.WallClock; @@ -129,7 +128,7 @@ public PrimaryBackupServiceContext( this.serverName = checkNotNull(serverName); this.primitiveId = checkNotNull(primitiveId); this.primitiveType = checkNotNull(primitiveType); - this.serviceConfig = Serializer.using(primitiveType.namespace()).decode(descriptor.config()); + this.serviceConfig = primitiveType.serializer().decode(descriptor.config()); this.descriptor = checkNotNull(descriptor); this.service = primitiveType.newService(serviceConfig); this.threadContext = checkNotNull(threadContext); diff --git a/protocols/primary-backup/src/test/java/io/atomix/protocols/backup/PrimaryBackupTest.java b/protocols/primary-backup/src/test/java/io/atomix/protocols/backup/PrimaryBackupTest.java index f354b04277..d8edf0e21b 100644 --- a/protocols/primary-backup/src/test/java/io/atomix/protocols/backup/PrimaryBackupTest.java +++ b/protocols/primary-backup/src/test/java/io/atomix/protocols/backup/PrimaryBackupTest.java @@ -17,9 +17,6 @@ import io.atomix.cluster.MemberId; import io.atomix.cluster.TestClusterMembershipService; -import io.atomix.primitive.DistributedPrimitiveBuilder; -import io.atomix.primitive.PrimitiveConfig; -import io.atomix.primitive.PrimitiveManagementService; import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.Replication; import io.atomix.primitive.event.EventType; @@ -33,7 +30,6 @@ import io.atomix.primitive.service.BackupInput; import io.atomix.primitive.service.BackupOutput; import io.atomix.primitive.service.Commit; -import io.atomix.primitive.service.PrimitiveService; import io.atomix.primitive.service.ServiceConfig; import io.atomix.primitive.service.ServiceExecutor; import io.atomix.primitive.session.PrimitiveSession; @@ -416,7 +412,7 @@ private PrimaryBackupServer createServer(MemberId memberId) { .withMembershipService(new TestClusterMembershipService(memberId, nodes)) .withMemberGroupProvider(MemberGroupStrategy.NODE_AWARE) .withPrimaryElection(election) - .addPrimitiveType(TestPrimitiveType.INSTANCE) + .addPrimitiveType(TEST_PRIMITIVE_TYPE) .build(); servers.add(server); return server; @@ -443,7 +439,7 @@ private PrimaryBackupClient createClient() throws Throwable { * Creates a new primary-backup proxy. */ private PartitionProxy createProxy(PrimaryBackupClient client, int backups, Replication replication) { - return client.proxyBuilder("test", TestPrimitiveType.INSTANCE, new ServiceConfig()) + return client.proxyBuilder("test", TEST_PRIMITIVE_TYPE, new ServiceConfig()) .withNumBackups(backups) .withReplication(replication) .build() @@ -474,32 +470,10 @@ public void clearTests() throws Exception { private static final EventType EXPIRE_EVENT = EventType.from("expire"); private static final EventType CLOSE_EVENT = EventType.from("close"); - /** - * Test primitive type. - */ - private static class TestPrimitiveType implements PrimitiveType { - static final TestPrimitiveType INSTANCE = new TestPrimitiveType(); - - @Override - public String id() { - return "test"; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new TestPrimitiveService(config); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveConfig config, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } - } + private static final PrimitiveType TEST_PRIMITIVE_TYPE = PrimitiveType.builder() + .withName("test") + .withServiceClass(TestPrimitiveService.class) + .build(); /** * Test state machine. diff --git a/protocols/raft/src/main/java/io/atomix/protocols/raft/MultiRaftProtocol.java b/protocols/raft/src/main/java/io/atomix/protocols/raft/MultiRaftProtocol.java index 9eba25d02d..5d1861e7af 100644 --- a/protocols/raft/src/main/java/io/atomix/protocols/raft/MultiRaftProtocol.java +++ b/protocols/raft/src/main/java/io/atomix/protocols/raft/MultiRaftProtocol.java @@ -24,7 +24,6 @@ import io.atomix.primitive.proxy.PrimitiveProxy; import io.atomix.primitive.proxy.impl.PartitionedPrimitiveProxy; import io.atomix.primitive.service.ServiceConfig; -import io.atomix.protocols.raft.partition.RaftPartition; import io.atomix.protocols.raft.proxy.CommunicationStrategy; import java.time.Duration; @@ -39,19 +38,7 @@ * Multi-Raft protocol. */ public class MultiRaftProtocol implements PrimitiveProtocol { - public static final Type TYPE = new Type(); - - /** - * The multi-raft protocol type. - */ - public static class Type implements PrimitiveProtocol.Type { - private static final String NAME = "multi-raft"; - - @Override - public String name() { - return NAME; - } - } + public static final String NAME = "multi-raft"; /** * Returns a new multi-Raft protocol builder. @@ -79,8 +66,8 @@ protected MultiRaftProtocol(MultiRaftProtocolConfig config) { } @Override - public PrimitiveProtocol.Type type() { - return TYPE; + public String type() { + return config.getType(); } @Override diff --git a/protocols/raft/src/main/java/io/atomix/protocols/raft/MultiRaftProtocolConfig.java b/protocols/raft/src/main/java/io/atomix/protocols/raft/MultiRaftProtocolConfig.java index 751bb49e8f..a54425ac2d 100644 --- a/protocols/raft/src/main/java/io/atomix/protocols/raft/MultiRaftProtocolConfig.java +++ b/protocols/raft/src/main/java/io/atomix/protocols/raft/MultiRaftProtocolConfig.java @@ -17,7 +17,6 @@ import io.atomix.primitive.Recovery; import io.atomix.primitive.partition.Partitioner; -import io.atomix.primitive.protocol.PrimitiveProtocol; import io.atomix.primitive.protocol.PrimitiveProtocolConfig; import io.atomix.protocols.raft.proxy.CommunicationStrategy; @@ -39,8 +38,8 @@ public class MultiRaftProtocolConfig extends PrimitiveProtocolConfig { @Override - public PrimitiveProtocol.Type type() { - return MultiRaftProtocol.TYPE; - } - - @Override - public MultiRaftProtocol create(MultiRaftProtocolConfig config) { + public MultiRaftProtocol createProtocol(MultiRaftProtocolConfig config) { return new MultiRaftProtocol(config); } } diff --git a/protocols/raft/src/main/java/io/atomix/protocols/raft/RaftServer.java b/protocols/raft/src/main/java/io/atomix/protocols/raft/RaftServer.java index 4a67b8fb2e..7d57b3d3fd 100644 --- a/protocols/raft/src/main/java/io/atomix/protocols/raft/RaftServer.java +++ b/protocols/raft/src/main/java/io/atomix/protocols/raft/RaftServer.java @@ -19,6 +19,7 @@ import io.atomix.cluster.MemberId; import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.PrimitiveTypeRegistry; +import io.atomix.primitive.impl.DefaultPrimitiveTypeRegistry; import io.atomix.primitive.operation.OperationType; import io.atomix.primitive.service.PrimitiveService; import io.atomix.protocols.raft.cluster.RaftCluster; @@ -556,14 +557,13 @@ abstract class Builder implements io.atomix.utils.Builder { protected String name; protected MemberId localMemberId; - protected ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); protected ClusterMembershipService membershipService; protected RaftServerProtocol protocol; protected RaftStorage storage; protected Duration electionTimeout = DEFAULT_ELECTION_TIMEOUT; protected Duration heartbeatInterval = DEFAULT_HEARTBEAT_INTERVAL; protected Duration sessionTimeout = DEFAULT_SESSION_TIMEOUT; - protected PrimitiveTypeRegistry primitiveTypes = new PrimitiveTypeRegistry(classLoader); + protected PrimitiveTypeRegistry primitiveTypes = new DefaultPrimitiveTypeRegistry(); protected ThreadModel threadModel = DEFAULT_THREAD_MODEL; protected int threadPoolSize = DEFAULT_THREAD_POOL_SIZE; @@ -584,18 +584,6 @@ public Builder withName(String name) { return this; } - /** - * Sets the class loader. - * - * @param classLoader the class loader - * @return the server builder - */ - public Builder withClassLoader(ClassLoader classLoader) { - this.classLoader = checkNotNull(classLoader, "classLoader cannot be null"); - this.primitiveTypes = new PrimitiveTypeRegistry(classLoader); - return this; - } - /** * Sets the cluster membership service. * @@ -672,7 +660,7 @@ public Builder withPrimitiveTypes(PrimitiveTypeRegistry primitiveTypes) { * @throws NullPointerException if the {@code primitiveType} is {@code null} */ public Builder addPrimitiveType(PrimitiveType primitiveType) { - primitiveTypes.register(primitiveType); + primitiveTypes.addPrimitiveType(primitiveType); return this; } diff --git a/protocols/raft/src/main/java/io/atomix/protocols/raft/impl/DefaultRaftMetadataClient.java b/protocols/raft/src/main/java/io/atomix/protocols/raft/impl/DefaultRaftMetadataClient.java index 177134b636..7717f66e0e 100644 --- a/protocols/raft/src/main/java/io/atomix/protocols/raft/impl/DefaultRaftMetadataClient.java +++ b/protocols/raft/src/main/java/io/atomix/protocols/raft/impl/DefaultRaftMetadataClient.java @@ -95,7 +95,7 @@ public CompletableFuture> getSessions() { public CompletableFuture> getSessions(PrimitiveType primitiveType) { return getMetadata().thenApply(response -> response.sessions() .stream() - .filter(s -> s.primitiveType().equals(primitiveType.id())) + .filter(s -> s.primitiveType().equals(primitiveType.name())) .collect(Collectors.toSet())); } @@ -103,7 +103,7 @@ public CompletableFuture> getSessions(PrimitiveType primiti public CompletableFuture> getSessions(PrimitiveType primitiveType, String serviceName) { return getMetadata().thenApply(response -> response.sessions() .stream() - .filter(s -> s.primitiveType().equals(primitiveType.id()) && s.primitiveName().equals(serviceName)) + .filter(s -> s.primitiveType().equals(primitiveType.name()) && s.primitiveName().equals(serviceName)) .collect(Collectors.toSet())); } } diff --git a/protocols/raft/src/main/java/io/atomix/protocols/raft/impl/DefaultRaftServer.java b/protocols/raft/src/main/java/io/atomix/protocols/raft/impl/DefaultRaftServer.java index eff8c56f39..e178a68106 100644 --- a/protocols/raft/src/main/java/io/atomix/protocols/raft/impl/DefaultRaftServer.java +++ b/protocols/raft/src/main/java/io/atomix/protocols/raft/impl/DefaultRaftServer.java @@ -224,7 +224,7 @@ public Builder(MemberId localMemberId) { @Override public RaftServer build() { - if (primitiveTypes.size() == 0) { + if (primitiveTypes.getPrimitiveTypes().isEmpty()) { throw new IllegalStateException("No primitive services registered"); } diff --git a/protocols/raft/src/main/java/io/atomix/protocols/raft/impl/RaftServiceManager.java b/protocols/raft/src/main/java/io/atomix/protocols/raft/impl/RaftServiceManager.java index 7230a5fe9e..e32f759b6a 100644 --- a/protocols/raft/src/main/java/io/atomix/protocols/raft/impl/RaftServiceManager.java +++ b/protocols/raft/src/main/java/io/atomix/protocols/raft/impl/RaftServiceManager.java @@ -49,9 +49,9 @@ import io.atomix.utils.concurrent.OrderedFuture; import io.atomix.utils.concurrent.ThreadContext; import io.atomix.utils.concurrent.ThreadContextFactory; +import io.atomix.utils.config.ConfigurationException; import io.atomix.utils.logging.ContextualLoggerFactory; import io.atomix.utils.logging.LoggerContext; -import io.atomix.utils.serializer.Serializer; import io.atomix.utils.time.WallClockTimestamp; import org.slf4j.Logger; @@ -451,9 +451,9 @@ private Snapshot snapshot(long index) { */ private void snapshotService(SnapshotWriter writer, RaftServiceContext service) { writer.writeLong(service.serviceId().id()); - writer.writeString(service.serviceType().id()); + writer.writeString(service.serviceType().name()); writer.writeString(service.serviceName()); - byte[] config = Serializer.using(service.serviceType().namespace()).encode(service.serviceConfig()); + byte[] config = service.serviceType().serializer().encode(service.serviceConfig()); writer.writeInt(config.length).writeBytes(config); service.takeSnapshot(writer); } @@ -489,15 +489,19 @@ private void install(long index) { */ private void installService(SnapshotReader reader) { PrimitiveId primitiveId = PrimitiveId.from(reader.readLong()); - PrimitiveType primitiveType = raft.getPrimitiveTypes().get(reader.readString()); - String serviceName = reader.readString(); - byte[] serviceConfig = reader.readBytes(reader.readInt()); - - // Get or create the service associated with the snapshot. - logger.debug("Installing service {} {}", primitiveId, serviceName); - RaftServiceContext service = initializeService(primitiveId, primitiveType, serviceName, serviceConfig); - if (service != null) { - service.installSnapshot(reader); + try { + PrimitiveType primitiveType = raft.getPrimitiveTypes().getPrimitiveType(reader.readString()); + String serviceName = reader.readString(); + byte[] serviceConfig = reader.readBytes(reader.readInt()); + + // Get or create the service associated with the snapshot. + logger.debug("Installing service {} {}", primitiveId, serviceName); + RaftServiceContext service = initializeService(primitiveId, primitiveType, serviceName, serviceConfig); + if (service != null) { + service.installSnapshot(reader); + } + } catch (ConfigurationException e) { + logger.error(e.getMessage(), e); } } @@ -616,7 +620,7 @@ private RaftServiceContext getOrInitializeService(PrimitiveId primitiveId, Primi @SuppressWarnings("unchecked") private RaftServiceContext initializeService(PrimitiveId primitiveId, PrimitiveType primitiveType, String serviceName, byte[] config) { RaftServiceContext oldService = raft.getServices().getService(serviceName); - ServiceConfig serviceConfig = Serializer.using(primitiveType.namespace()).decode(config); + ServiceConfig serviceConfig = primitiveType.serializer().decode(config); RaftServiceContext service = new RaftServiceContext( primitiveId, serviceName, @@ -638,15 +642,12 @@ private RaftServiceContext initializeService(PrimitiveId primitiveId, PrimitiveT * Applies an open session entry to the state machine. */ private long applyOpenSession(Indexed entry) { - PrimitiveType primitiveType = raft.getPrimitiveTypes().get(entry.entry().serviceType()); - if (primitiveType == null) { - throw new RaftException.UnknownService("Unknown service type " + entry.entry().serviceType()); - } + PrimitiveType primitiveType = raft.getPrimitiveTypes().getPrimitiveType(entry.entry().serviceType()); // Get the state machine executor or create one if it doesn't already exist. RaftServiceContext service = getOrInitializeService( PrimitiveId.from(entry.index()), - raft.getPrimitiveTypes().get(entry.entry().serviceType()), + primitiveType, entry.entry().serviceName(), entry.entry().serviceConfig()); @@ -704,14 +705,14 @@ private MetadataResult applyMetadata(Indexed entry) { Set sessions = new HashSet<>(); for (RaftSession s : raft.getSessions().getSessions()) { if (s.serviceName().equals(session.serviceName())) { - sessions.add(new SessionMetadata(s.sessionId().id(), s.serviceName(), s.serviceType().id())); + sessions.add(new SessionMetadata(s.sessionId().id(), s.serviceName(), s.serviceType().name())); } } return new MetadataResult(sessions); } else { Set sessions = new HashSet<>(); for (RaftSession session : raft.getSessions().getSessions()) { - sessions.add(new SessionMetadata(session.sessionId().id(), session.serviceName(), session.serviceType().id())); + sessions.add(new SessionMetadata(session.sessionId().id(), session.serviceName(), session.serviceType().name())); } return new MetadataResult(sessions); } diff --git a/protocols/raft/src/main/java/io/atomix/protocols/raft/partition/RaftPartitionGroup.java b/protocols/raft/src/main/java/io/atomix/protocols/raft/partition/RaftPartitionGroup.java index ea47ae6344..b6db4e3793 100644 --- a/protocols/raft/src/main/java/io/atomix/protocols/raft/partition/RaftPartitionGroup.java +++ b/protocols/raft/src/main/java/io/atomix/protocols/raft/partition/RaftPartitionGroup.java @@ -29,6 +29,7 @@ import io.atomix.primitive.partition.PartitionManagementService; import io.atomix.primitive.partition.PartitionMetadata; import io.atomix.primitive.protocol.PrimitiveProtocol; +import io.atomix.primitive.protocol.PrimitiveProtocolType; import io.atomix.protocols.raft.MultiRaftProtocol; import io.atomix.storage.StorageLevel; import org.slf4j.Logger; @@ -54,7 +55,6 @@ * Raft partition group. */ public class RaftPartitionGroup implements ManagedPartitionGroup { - public static final PartitionGroup.Type TYPE = new Type(); /** * Returns a new Raft partition group builder. @@ -66,18 +66,6 @@ public static Builder builder(String name) { return new Builder(new RaftPartitionGroupConfig().setName(name)); } - /** - * The Raft partition group type. - */ - public static class Type implements PartitionGroup.Type { - private static final String NAME = "raft"; - - @Override - public String name() { - return NAME; - } - } - private static final Logger LOGGER = LoggerFactory.getLogger(RaftPartitionGroup.class); private static Collection buildPartitions(RaftPartitionGroupConfig config) { @@ -94,6 +82,7 @@ private static Collection buildPartitions(RaftPartitionGroupConfi } private final String name; + private final String type; private final RaftPartitionGroupConfig config; private final int partitionSize; private final Map partitions = Maps.newConcurrentMap(); @@ -101,6 +90,7 @@ private static Collection buildPartitions(RaftPartitionGroupConfi private Collection metadata; public RaftPartitionGroup(RaftPartitionGroupConfig config) { + this.type = config.getType(); this.name = config.getName(); this.config = config; this.partitionSize = config.getPartitionSize(); @@ -117,13 +107,16 @@ public String name() { } @Override - public PartitionGroup.Type type() { - return TYPE; + public String type() { + return type; } @Override - public PrimitiveProtocol.Type protocol() { - return MultiRaftProtocol.TYPE; + public PrimitiveProtocolType protocol() { + return PrimitiveProtocolType.builder() + .withName(MultiRaftProtocol.NAME) + .withProtocolClass(MultiRaftProtocol.class) + .build(); } @Override diff --git a/protocols/raft/src/main/java/io/atomix/protocols/raft/partition/RaftPartitionGroupConfig.java b/protocols/raft/src/main/java/io/atomix/protocols/raft/partition/RaftPartitionGroupConfig.java index 9b8d66b3be..4c8cabd40d 100644 --- a/protocols/raft/src/main/java/io/atomix/protocols/raft/partition/RaftPartitionGroupConfig.java +++ b/protocols/raft/src/main/java/io/atomix/protocols/raft/partition/RaftPartitionGroupConfig.java @@ -16,8 +16,6 @@ package io.atomix.protocols.raft.partition; import io.atomix.primitive.partition.PartitionGroupConfig; -import io.atomix.primitive.protocol.PrimitiveProtocol; -import io.atomix.protocols.raft.MultiRaftProtocol; import io.atomix.storage.StorageLevel; import java.util.HashSet; @@ -37,8 +35,8 @@ public class RaftPartitionGroupConfig extends PartitionGroupConfig { - @Override - public PartitionGroup.Type type() { - return RaftPartitionGroup.TYPE; - } - @Override public RaftPartitionGroup createGroup(RaftPartitionGroupConfig config) { return new RaftPartitionGroup(config); diff --git a/protocols/raft/src/main/java/io/atomix/protocols/raft/protocol/OpenSessionRequest.java b/protocols/raft/src/main/java/io/atomix/protocols/raft/protocol/OpenSessionRequest.java index eeca497e8e..1b96cf0b5f 100644 --- a/protocols/raft/src/main/java/io/atomix/protocols/raft/protocol/OpenSessionRequest.java +++ b/protocols/raft/src/main/java/io/atomix/protocols/raft/protocol/OpenSessionRequest.java @@ -195,7 +195,7 @@ public Builder withServiceName(String serviceName) { * @throws NullPointerException if {@code serviceType} is {@code null} */ public Builder withServiceType(PrimitiveType primitiveType) { - this.serviceType = checkNotNull(primitiveType, "serviceType cannot be null").id(); + this.serviceType = checkNotNull(primitiveType, "serviceType cannot be null").name(); return this; } diff --git a/protocols/raft/src/main/java/io/atomix/protocols/raft/proxy/impl/RaftProxyManager.java b/protocols/raft/src/main/java/io/atomix/protocols/raft/proxy/impl/RaftProxyManager.java index 010698fd87..d375039dfc 100644 --- a/protocols/raft/src/main/java/io/atomix/protocols/raft/proxy/impl/RaftProxyManager.java +++ b/protocols/raft/src/main/java/io/atomix/protocols/raft/proxy/impl/RaftProxyManager.java @@ -40,7 +40,6 @@ import io.atomix.utils.concurrent.ThreadContextFactory; import io.atomix.utils.logging.ContextualLoggerFactory; import io.atomix.utils.logging.LoggerContext; -import io.atomix.utils.serializer.Serializer; import org.slf4j.Logger; import java.time.Duration; @@ -170,7 +169,7 @@ public CompletableFuture openSession( .withMemberId(memberId) .withServiceName(serviceName) .withServiceType(primitiveType) - .withServiceConfig(Serializer.using(primitiveType.namespace()).encode(config)) + .withServiceConfig(primitiveType.serializer().encode(config)) .withReadConsistency(readConsistency) .withMinTimeout(minTimeout.toMillis()) .withMaxTimeout(maxTimeout.toMillis()) diff --git a/protocols/raft/src/main/java/io/atomix/protocols/raft/service/RaftServiceContext.java b/protocols/raft/src/main/java/io/atomix/protocols/raft/service/RaftServiceContext.java index 5c4c7a33ef..85b180ddc4 100644 --- a/protocols/raft/src/main/java/io/atomix/protocols/raft/service/RaftServiceContext.java +++ b/protocols/raft/src/main/java/io/atomix/protocols/raft/service/RaftServiceContext.java @@ -40,6 +40,7 @@ import io.atomix.protocols.raft.storage.snapshot.SnapshotWriter; import io.atomix.storage.buffer.Bytes; import io.atomix.utils.concurrent.ThreadContextFactory; +import io.atomix.utils.config.ConfigurationException; import io.atomix.utils.logging.ContextualLoggerFactory; import io.atomix.utils.logging.LoggerContext; import io.atomix.utils.serializer.Serializer; @@ -203,7 +204,14 @@ private void expireSessions(long timestamp) { public void installSnapshot(SnapshotReader reader) { log.debug("Installing snapshot {}", reader.snapshot().index()); reader.skip(Bytes.LONG); // Skip the service ID - PrimitiveType primitiveType = raft.getPrimitiveTypes().get(reader.readString()); + PrimitiveType primitiveType; + try { + primitiveType = raft.getPrimitiveTypes().getPrimitiveType(reader.readString()); + } catch (ConfigurationException e) { + log.error(e.getMessage(), e); + return; + } + String serviceName = reader.readString(); int sessionCount = reader.readInt(); for (int i = 0; i < sessionCount; i++) { @@ -251,7 +259,7 @@ public void takeSnapshot(SnapshotWriter writer) { // Serialize sessions to the in-memory snapshot and request a snapshot from the state machine. writer.writeLong(primitiveId.id()); - writer.writeString(primitiveType.id()); + writer.writeString(primitiveType.name()); writer.writeString(serviceName); writer.writeInt(sessions.getSessions().size()); for (RaftSession session : sessions.getSessions()) { diff --git a/protocols/raft/src/test/java/io/atomix/protocols/raft/RaftTest.java b/protocols/raft/src/test/java/io/atomix/protocols/raft/RaftTest.java index 438bd68b79..69ae2fcb72 100644 --- a/protocols/raft/src/test/java/io/atomix/protocols/raft/RaftTest.java +++ b/protocols/raft/src/test/java/io/atomix/protocols/raft/RaftTest.java @@ -18,16 +18,13 @@ import com.google.common.collect.Sets; import io.atomix.cluster.ClusterMembershipService; import io.atomix.cluster.MemberId; +import io.atomix.primitive.AbstractAsyncPrimitiveProxy; import io.atomix.primitive.AsyncPrimitive; -import io.atomix.primitive.DistributedPrimitiveBuilder; -import io.atomix.primitive.PrimitiveConfig; import io.atomix.primitive.PrimitiveInfo; -import io.atomix.primitive.PrimitiveManagementService; import io.atomix.primitive.PrimitiveRegistry; import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.SyncPrimitive; import io.atomix.primitive.event.Event; -import io.atomix.primitive.AbstractAsyncPrimitiveProxy; import io.atomix.primitive.operation.Operation; import io.atomix.primitive.operation.OperationType; import io.atomix.primitive.operation.PrimitiveOperation; @@ -38,7 +35,6 @@ import io.atomix.primitive.service.AbstractPrimitiveService; import io.atomix.primitive.service.BackupInput; import io.atomix.primitive.service.BackupOutput; -import io.atomix.primitive.service.PrimitiveService; import io.atomix.primitive.service.ServiceConfig; import io.atomix.primitive.session.PrimitiveSession; import io.atomix.primitive.session.SessionId; @@ -148,13 +144,13 @@ public void testSessionMetadata() throws Throwable { createPrimitive(client).write("Hello world again!").join(); assertNotNull(client.metadata().getLeader()); assertNotNull(client.metadata().getServers()); - Set typeSessions = client.metadata().getSessions(TestPrimitiveType.INSTANCE).join(); + Set typeSessions = client.metadata().getSessions(TEST_PRIMITIVE_TYPE).join(); assertEquals(2, typeSessions.size()); - typeSessions = client.metadata().getSessions(TestPrimitiveType.INSTANCE).join(); + typeSessions = client.metadata().getSessions(TEST_PRIMITIVE_TYPE).join(); assertEquals(2, typeSessions.size()); - Set serviceSessions = client.metadata().getSessions(TestPrimitiveType.INSTANCE, "test").join(); + Set serviceSessions = client.metadata().getSessions(TEST_PRIMITIVE_TYPE, "test").join(); assertEquals(2, serviceSessions.size()); - serviceSessions = client.metadata().getSessions(TestPrimitiveType.INSTANCE, "test").join(); + serviceSessions = client.metadata().getSessions(TEST_PRIMITIVE_TYPE, "test").join(); assertEquals(2, serviceSessions.size()); } @@ -1225,7 +1221,7 @@ private RaftServer createServer(MemberId memberId) { .withMaxSegmentSize(1024 * 10) .withMaxEntriesPerSegment(10) .build()) - .addPrimitiveType(TestPrimitiveType.INSTANCE); + .addPrimitiveType(TEST_PRIMITIVE_TYPE); RaftServer server = builder.build(); servers.add(server); @@ -1259,7 +1255,7 @@ private PartitionProxy createSession(RaftClient client) throws Exception { * Creates a test session. */ private PartitionProxy createSession(RaftClient client, ReadConsistency consistency) throws Exception { - return client.proxyBuilder("test", TestPrimitiveType.INSTANCE, new ServiceConfig()) + return client.proxyBuilder("test", TEST_PRIMITIVE_TYPE, new ServiceConfig()) .withReadConsistency(consistency) .withMinTimeout(Duration.ofMillis(250)) .withMaxTimeout(Duration.ofSeconds(5)) @@ -1281,11 +1277,11 @@ private TestPrimitive createPrimitive(RaftClient client) throws Exception { private TestPrimitive createPrimitive(RaftClient client, ReadConsistency consistency) throws Exception { PartitionProxy partition = createSession(client, consistency); PrimitiveProxy proxy = mock(PrimitiveProxy.class); - when(proxy.type()).thenReturn(TestPrimitiveType.INSTANCE); + when(proxy.type()).thenReturn(TEST_PRIMITIVE_TYPE); when(proxy.getPartitions()).thenReturn(Collections.singletonList(partition)); when(proxy.getPartitionId(any(String.class))).thenReturn(partition.partitionId()); PrimitiveRegistry registry = mock(PrimitiveRegistry.class); - when(registry.createPrimitive(any(String.class), any(PrimitiveType.class))).thenReturn(CompletableFuture.completedFuture(new PrimitiveInfo("test", TestPrimitiveType.INSTANCE))); + when(registry.createPrimitive(any(String.class), any(PrimitiveType.class))).thenReturn(CompletableFuture.completedFuture(new PrimitiveInfo("test", TEST_PRIMITIVE_TYPE))); return new TestPrimitiveImpl(proxy, registry); } @@ -1337,32 +1333,10 @@ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOEx protocolFactory = new TestRaftProtocolFactory(context); } - /** - * Test primitive type. - */ - private static class TestPrimitiveType implements PrimitiveType { - static final TestPrimitiveType INSTANCE = new TestPrimitiveType(); - - @Override - public String id() { - return "test"; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new TestPrimitiveServiceImpl(config); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveConfig config, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } - } + private static final PrimitiveType TEST_PRIMITIVE_TYPE = PrimitiveType.builder() + .withName("test") + .withServiceClass(TestPrimitiveServiceImpl.class) + .build(); /** * Test primitive. @@ -1496,11 +1470,6 @@ public TestPrimitiveServiceImpl(ServiceConfig config) { super(TestPrimitiveClient.class, config); } - @Override - public Serializer serializer() { - return Serializer.using(TestPrimitiveType.INSTANCE.namespace()); - } - @Override public void onExpire(PrimitiveSession session) { if (expire != null) { diff --git a/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/RaftProxyInvokerTest.java b/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/RaftProxyInvokerTest.java index f04e35b772..b4c4aac3a0 100644 --- a/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/RaftProxyInvokerTest.java +++ b/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/RaftProxyInvokerTest.java @@ -15,6 +15,7 @@ */ package io.atomix.protocols.raft.proxy.impl; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.operation.OperationId; import io.atomix.primitive.session.SessionId; import io.atomix.protocols.raft.RaftException; @@ -51,6 +52,9 @@ public class RaftProxyInvokerTest { private static final OperationId COMMAND = OperationId.command("command"); private static final OperationId QUERY = OperationId.query("query"); + private static final PrimitiveType TEST_PRIMITIVE_TYPE = PrimitiveType.builder() + .withName("test") + .build(); /** * Tests submitting a command to the cluster. @@ -65,7 +69,7 @@ public void testSubmitCommand() throws Throwable { .withResult("Hello world!".getBytes()) .build())); - RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000); + RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), TEST_PRIMITIVE_TYPE, 1000); RaftProxyManager manager = mock(RaftProxyManager.class); ThreadContext threadContext = new TestContext(); @@ -89,7 +93,7 @@ public void testResequenceCommand() throws Throwable { .thenReturn(future1) .thenReturn(future2); - RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000); + RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), TEST_PRIMITIVE_TYPE, 1000); RaftProxyManager manager = mock(RaftProxyManager.class); ThreadContext threadContext = new TestContext(); @@ -140,7 +144,7 @@ public void testSubmitQuery() throws Throwable { .withResult("Hello world!".getBytes()) .build())); - RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000); + RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), TEST_PRIMITIVE_TYPE, 1000); RaftProxyManager manager = mock(RaftProxyManager.class); ThreadContext threadContext = new TestContext(); @@ -162,7 +166,7 @@ public void testResequenceQuery() throws Throwable { .thenReturn(future1) .thenReturn(future2); - RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000); + RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), TEST_PRIMITIVE_TYPE, 1000); RaftProxyManager manager = mock(RaftProxyManager.class); ThreadContext threadContext = new TestContext(); @@ -209,7 +213,7 @@ public void testSkippingOverFailedQuery() throws Throwable { .thenReturn(future1) .thenReturn(future2); - RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000); + RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), TEST_PRIMITIVE_TYPE, 1000); RaftProxyManager manager = mock(RaftProxyManager.class); ThreadContext threadContext = new TestContext(); @@ -247,7 +251,7 @@ public void testExpireSessionOnCommandFailure() throws Throwable { RaftProxyConnection connection = mock(RaftProxyConnection.class); Mockito.when(connection.command(any(CommandRequest.class))).thenReturn(future); - RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000); + RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), TEST_PRIMITIVE_TYPE, 1000); RaftProxyManager manager = mock(RaftProxyManager.class); ThreadContext threadContext = new TestContext(); @@ -275,7 +279,7 @@ public void testExpireSessionOnQueryFailure() throws Throwable { Mockito.when(connection.query(any(QueryRequest.class))) .thenReturn(future); - RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000); + RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), TEST_PRIMITIVE_TYPE, 1000); RaftProxyManager manager = mock(RaftProxyManager.class); ThreadContext threadContext = new TestContext(); diff --git a/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/RaftProxySequencerTest.java b/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/RaftProxySequencerTest.java index 205d3f73e5..e63202389a 100644 --- a/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/RaftProxySequencerTest.java +++ b/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/RaftProxySequencerTest.java @@ -15,6 +15,7 @@ */ package io.atomix.protocols.raft.proxy.impl; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.session.SessionId; import io.atomix.protocols.raft.protocol.CommandResponse; import io.atomix.protocols.raft.protocol.PublishRequest; @@ -37,13 +38,16 @@ * @author Jordan Halterman */ public class RaftProxySequencerTest { + private static final PrimitiveType TEST_PRIMITIVE_TYPE = PrimitiveType.builder() + .withName("test") + .build(); /** * Tests sequencing an event that arrives before a command response. */ @Test public void testSequenceEventBeforeCommand() throws Throwable { - RaftProxySequencer sequencer = new RaftProxySequencer(new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000)); + RaftProxySequencer sequencer = new RaftProxySequencer(new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), TEST_PRIMITIVE_TYPE, 1000)); long sequence = sequencer.nextRequest(); PublishRequest request = PublishRequest.builder() @@ -70,7 +74,7 @@ public void testSequenceEventBeforeCommand() throws Throwable { */ @Test public void testSequenceEventAfterCommand() throws Throwable { - RaftProxySequencer sequencer = new RaftProxySequencer(new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000)); + RaftProxySequencer sequencer = new RaftProxySequencer(new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), TEST_PRIMITIVE_TYPE, 1000)); long sequence = sequencer.nextRequest(); PublishRequest request = PublishRequest.builder() @@ -97,7 +101,7 @@ public void testSequenceEventAfterCommand() throws Throwable { */ @Test public void testSequenceEventAtCommand() throws Throwable { - RaftProxySequencer sequencer = new RaftProxySequencer(new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000)); + RaftProxySequencer sequencer = new RaftProxySequencer(new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), TEST_PRIMITIVE_TYPE, 1000)); long sequence = sequencer.nextRequest(); PublishRequest request = PublishRequest.builder() @@ -124,7 +128,7 @@ public void testSequenceEventAtCommand() throws Throwable { */ @Test public void testSequenceEventAfterAllCommands() throws Throwable { - RaftProxySequencer sequencer = new RaftProxySequencer(new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000)); + RaftProxySequencer sequencer = new RaftProxySequencer(new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), TEST_PRIMITIVE_TYPE, 1000)); long sequence = sequencer.nextRequest(); PublishRequest request1 = PublishRequest.builder() @@ -159,7 +163,7 @@ public void testSequenceEventAfterAllCommands() throws Throwable { */ @Test public void testSequenceEventAbsentCommand() throws Throwable { - RaftProxySequencer sequencer = new RaftProxySequencer(new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000)); + RaftProxySequencer sequencer = new RaftProxySequencer(new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), TEST_PRIMITIVE_TYPE, 1000)); PublishRequest request1 = PublishRequest.builder() .withSession(1) @@ -186,7 +190,7 @@ public void testSequenceEventAbsentCommand() throws Throwable { */ @Test public void testSequenceResponses() throws Throwable { - RaftProxySequencer sequencer = new RaftProxySequencer(new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000)); + RaftProxySequencer sequencer = new RaftProxySequencer(new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), TEST_PRIMITIVE_TYPE, 1000)); long sequence1 = sequencer.nextRequest(); long sequence2 = sequencer.nextRequest(); assertTrue(sequence2 == sequence1 + 1); diff --git a/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/RaftProxyStateTest.java b/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/RaftProxyStateTest.java index 04cfe01bc2..389c7db8bf 100644 --- a/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/RaftProxyStateTest.java +++ b/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/RaftProxyStateTest.java @@ -15,6 +15,7 @@ */ package io.atomix.protocols.raft.proxy.impl; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.session.SessionId; import org.junit.Test; @@ -28,6 +29,9 @@ * @author Jordan Halterman */ public class RaftProxyStateTest { + private static final PrimitiveType TEST_PRIMITIVE_TYPE = PrimitiveType.builder() + .withName("test") + .build(); /** * Tests session state defaults. @@ -35,10 +39,10 @@ public class RaftProxyStateTest { @Test public void testSessionStateDefaults() { String sessionName = UUID.randomUUID().toString(); - RaftProxyState state = new RaftProxyState("test", SessionId.from(1), sessionName, new TestPrimitiveType(), 1000); + RaftProxyState state = new RaftProxyState("test", SessionId.from(1), sessionName, TEST_PRIMITIVE_TYPE, 1000); assertEquals(state.getSessionId(), SessionId.from(1)); assertEquals(state.getPrimitiveName(), sessionName); - assertEquals(state.getPrimitiveType().id(), "test"); + assertEquals(state.getPrimitiveType().name(), "test"); assertEquals(state.getCommandRequest(), 0); assertEquals(state.getCommandResponse(), 0); assertEquals(state.getResponseIndex(), 1); @@ -50,7 +54,7 @@ public void testSessionStateDefaults() { */ @Test public void testSessionState() { - RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000); + RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), TEST_PRIMITIVE_TYPE, 1000); assertEquals(state.getSessionId(), SessionId.from(1)); assertEquals(state.getResponseIndex(), 1); assertEquals(state.getEventIndex(), 1); diff --git a/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/TestPrimitiveType.java b/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/TestPrimitiveType.java deleted file mode 100644 index 2a4a397339..0000000000 --- a/protocols/raft/src/test/java/io/atomix/protocols/raft/proxy/impl/TestPrimitiveType.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.protocols.raft.proxy.impl; - -import io.atomix.primitive.DistributedPrimitiveBuilder; -import io.atomix.primitive.PrimitiveConfig; -import io.atomix.primitive.PrimitiveManagementService; -import io.atomix.primitive.PrimitiveType; -import io.atomix.primitive.service.PrimitiveService; -import io.atomix.primitive.service.ServiceConfig; - -/** - * Test primitive type. - */ -public class TestPrimitiveType implements PrimitiveType { - @Override - public String id() { - return "test"; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - throw new UnsupportedOperationException(); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveConfig config, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } -} diff --git a/protocols/raft/src/test/java/io/atomix/protocols/raft/session/RaftSessionRegistryTest.java b/protocols/raft/src/test/java/io/atomix/protocols/raft/session/RaftSessionRegistryTest.java index 3a075242dc..a555fb6de2 100644 --- a/protocols/raft/src/test/java/io/atomix/protocols/raft/session/RaftSessionRegistryTest.java +++ b/protocols/raft/src/test/java/io/atomix/protocols/raft/session/RaftSessionRegistryTest.java @@ -17,12 +17,12 @@ import io.atomix.cluster.MemberId; import io.atomix.primitive.PrimitiveId; +import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.session.SessionId; import io.atomix.protocols.raft.ReadConsistency; import io.atomix.protocols.raft.impl.RaftContext; import io.atomix.protocols.raft.impl.RaftServiceManager; import io.atomix.protocols.raft.protocol.RaftServerProtocol; -import io.atomix.protocols.raft.proxy.impl.TestPrimitiveType; import io.atomix.protocols.raft.service.RaftServiceContext; import io.atomix.utils.concurrent.ThreadContext; import io.atomix.utils.concurrent.ThreadContextFactory; @@ -40,6 +40,9 @@ * Raft session manager test. */ public class RaftSessionRegistryTest { + private static final PrimitiveType TEST_PRIMITIVE_TYPE = PrimitiveType.builder() + .withName("test") + .build(); @Test public void testAddRemoveSession() throws Exception { @@ -56,7 +59,7 @@ public void testAddRemoveSession() throws Exception { private RaftSession createSession(long sessionId) { RaftServiceContext context = mock(RaftServiceContext.class); - when(context.serviceType()).thenReturn(new TestPrimitiveType()); + when(context.serviceType()).thenReturn(TEST_PRIMITIVE_TYPE); when(context.serviceName()).thenReturn("test"); when(context.serviceId()).thenReturn(PrimitiveId.from(1)); @@ -70,7 +73,7 @@ private RaftSession createSession(long sessionId) { SessionId.from(sessionId), MemberId.from("1"), "test", - new TestPrimitiveType(), + TEST_PRIMITIVE_TYPE, ReadConsistency.LINEARIZABLE, 100, 5000, diff --git a/config/src/main/java/io/atomix/core/config/jackson/impl/PartitionGroupDeserializer.java b/rest/src/main/java/io/atomix/rest/impl/PartitionGroupDeserializer.java similarity index 77% rename from config/src/main/java/io/atomix/core/config/jackson/impl/PartitionGroupDeserializer.java rename to rest/src/main/java/io/atomix/rest/impl/PartitionGroupDeserializer.java index 889e3129a4..c17fca2e0b 100644 --- a/config/src/main/java/io/atomix/core/config/jackson/impl/PartitionGroupDeserializer.java +++ b/rest/src/main/java/io/atomix/rest/impl/PartitionGroupDeserializer.java @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.atomix.core.config.jackson.impl; +package io.atomix.rest.impl; +import io.atomix.core.registry.RegistryService; import io.atomix.primitive.partition.PartitionGroup; import io.atomix.primitive.partition.PartitionGroupConfig; -import io.atomix.primitive.partition.PartitionGroups; /** * Partition group deserializer. */ public class PartitionGroupDeserializer extends PolymorphicTypeDeserializer { @SuppressWarnings("unchecked") - public PartitionGroupDeserializer(ClassLoader classLoader) { - super(PartitionGroup.class, type -> PartitionGroups.getGroupFactory(type, classLoader).configClass()); + public PartitionGroupDeserializer(RegistryService registry) { + super(PartitionGroup.class, type -> registry.partitionGroupTypes().getGroupType(type).configClass()); } } \ No newline at end of file diff --git a/config/src/main/java/io/atomix/core/config/jackson/impl/PolymorphicTypeDeserializer.java b/rest/src/main/java/io/atomix/rest/impl/PolymorphicTypeDeserializer.java similarity index 98% rename from config/src/main/java/io/atomix/core/config/jackson/impl/PolymorphicTypeDeserializer.java rename to rest/src/main/java/io/atomix/rest/impl/PolymorphicTypeDeserializer.java index b95f56972f..84e5698101 100644 --- a/config/src/main/java/io/atomix/core/config/jackson/impl/PolymorphicTypeDeserializer.java +++ b/rest/src/main/java/io/atomix/rest/impl/PolymorphicTypeDeserializer.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.atomix.core.config.jackson.impl; +package io.atomix.rest.impl; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; diff --git a/config/src/main/java/io/atomix/core/config/jackson/impl/PrimitiveConfigDeserializer.java b/rest/src/main/java/io/atomix/rest/impl/PrimitiveConfigDeserializer.java similarity index 75% rename from config/src/main/java/io/atomix/core/config/jackson/impl/PrimitiveConfigDeserializer.java rename to rest/src/main/java/io/atomix/rest/impl/PrimitiveConfigDeserializer.java index 2abae033c5..dfd237dd0a 100644 --- a/config/src/main/java/io/atomix/core/config/jackson/impl/PrimitiveConfigDeserializer.java +++ b/rest/src/main/java/io/atomix/rest/impl/PrimitiveConfigDeserializer.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.atomix.core.config.jackson.impl; +package io.atomix.rest.impl; +import io.atomix.core.registry.RegistryService; import io.atomix.primitive.PrimitiveConfig; -import io.atomix.primitive.PrimitiveTypes; /** * Primitive configuration deserializer. */ public class PrimitiveConfigDeserializer extends PolymorphicTypeDeserializer { @SuppressWarnings("unchecked") - public PrimitiveConfigDeserializer(ClassLoader classLoader) { - super(PrimitiveConfig.class, type -> PrimitiveTypes.getPrimitiveType(type, classLoader).primitiveConfigClass()); + public PrimitiveConfigDeserializer(RegistryService registry) { + super(PrimitiveConfig.class, type -> registry.primitiveTypes().getPrimitiveType(type).configClass()); } } \ No newline at end of file diff --git a/config/src/main/java/io/atomix/core/config/jackson/impl/PrimitiveProtocolDeserializer.java b/rest/src/main/java/io/atomix/rest/impl/PrimitiveProtocolDeserializer.java similarity index 74% rename from config/src/main/java/io/atomix/core/config/jackson/impl/PrimitiveProtocolDeserializer.java rename to rest/src/main/java/io/atomix/rest/impl/PrimitiveProtocolDeserializer.java index 343f891be0..20068e5d49 100644 --- a/config/src/main/java/io/atomix/core/config/jackson/impl/PrimitiveProtocolDeserializer.java +++ b/rest/src/main/java/io/atomix/rest/impl/PrimitiveProtocolDeserializer.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.atomix.core.config.jackson.impl; +package io.atomix.rest.impl; +import io.atomix.core.registry.RegistryService; import io.atomix.primitive.protocol.PrimitiveProtocolConfig; -import io.atomix.primitive.protocol.PrimitiveProtocols; /** * Primitive protocol deserializer. */ public class PrimitiveProtocolDeserializer extends PolymorphicTypeDeserializer { @SuppressWarnings("unchecked") - public PrimitiveProtocolDeserializer(ClassLoader classLoader) { - super(PrimitiveProtocolConfig.class, type -> PrimitiveProtocols.getProtocolFactory(type, classLoader).configClass()); + public PrimitiveProtocolDeserializer(RegistryService registry) { + super(PrimitiveProtocolConfig.class, type -> registry.protocolTypes().getProtocolType(type).configClass()); } } \ No newline at end of file diff --git a/rest/src/main/java/io/atomix/rest/impl/VertxRestService.java b/rest/src/main/java/io/atomix/rest/impl/VertxRestService.java index ca6eb7b866..a3733a0b3f 100644 --- a/rest/src/main/java/io/atomix/rest/impl/VertxRestService.java +++ b/rest/src/main/java/io/atomix/rest/impl/VertxRestService.java @@ -20,18 +20,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import io.atomix.cluster.ClusterMembershipService; -import io.atomix.cluster.messaging.ClusterEventingService; import io.atomix.cluster.messaging.ClusterCommunicationService; +import io.atomix.cluster.messaging.ClusterEventingService; import io.atomix.core.Atomix; import io.atomix.core.PrimitivesService; -import io.atomix.core.config.jackson.impl.ConfigPropertyNamingStrategy; -import io.atomix.core.config.jackson.impl.PartitionGroupDeserializer; -import io.atomix.core.config.jackson.impl.PrimitiveConfigDeserializer; -import io.atomix.core.config.jackson.impl.PrimitiveProtocolDeserializer; import io.atomix.core.utils.EventManager; import io.atomix.primitive.PrimitiveConfig; -import io.atomix.primitive.protocol.PrimitiveProtocolConfig; import io.atomix.primitive.partition.PartitionGroupConfig; +import io.atomix.primitive.protocol.PrimitiveProtocolConfig; import io.atomix.rest.ManagedRestService; import io.atomix.rest.RestService; import io.atomix.rest.resources.ClusterResource; @@ -144,16 +140,15 @@ public CompletableFuture stop() { private ObjectMapper createObjectMapper() { ObjectMapper mapper = new ObjectMapper(); - mapper.setPropertyNamingStrategy(new ConfigPropertyNamingStrategy()); mapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS); mapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES); mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); mapper.configure(JsonParser.Feature.ALLOW_YAML_COMMENTS, true); SimpleModule module = new SimpleModule("PolymorphicTypes"); - module.addDeserializer(PartitionGroupConfig.class, new PartitionGroupDeserializer(getClass().getClassLoader())); - module.addDeserializer(PrimitiveProtocolConfig.class, new PrimitiveProtocolDeserializer(getClass().getClassLoader())); - module.addDeserializer(PrimitiveConfig.class, new PrimitiveConfigDeserializer(getClass().getClassLoader())); + module.addDeserializer(PartitionGroupConfig.class, new PartitionGroupDeserializer(atomix.registryService())); + module.addDeserializer(PrimitiveProtocolConfig.class, new PrimitiveProtocolDeserializer(atomix.registryService())); + module.addDeserializer(PrimitiveConfig.class, new PrimitiveConfigDeserializer(atomix.registryService())); mapper.registerModule(module); return mapper; diff --git a/tests/src/main/java/io/atomix/protocols/raft/test/RaftFuzzTest.java b/tests/src/main/java/io/atomix/protocols/raft/test/RaftFuzzTest.java index 5abb8e14a4..e0d8a9d355 100644 --- a/tests/src/main/java/io/atomix/protocols/raft/test/RaftFuzzTest.java +++ b/tests/src/main/java/io/atomix/protocols/raft/test/RaftFuzzTest.java @@ -19,9 +19,6 @@ import io.atomix.cluster.MemberId; import io.atomix.cluster.messaging.MessagingService; import io.atomix.cluster.messaging.impl.NettyMessagingService; -import io.atomix.primitive.DistributedPrimitiveBuilder; -import io.atomix.primitive.PrimitiveConfig; -import io.atomix.primitive.PrimitiveManagementService; import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.operation.OperationId; import io.atomix.primitive.operation.OperationType; @@ -32,7 +29,6 @@ import io.atomix.primitive.service.BackupInput; import io.atomix.primitive.service.BackupOutput; import io.atomix.primitive.service.Commit; -import io.atomix.primitive.service.PrimitiveService; import io.atomix.primitive.service.ServiceConfig; import io.atomix.primitive.service.ServiceExecutor; import io.atomix.primitive.session.SessionId; @@ -588,7 +584,7 @@ private RaftServer createServer(RaftMember member) { .withSerializer(storageSerializer) .withMaxSegmentSize(1024 * 1024) .build()) - .addPrimitiveType(TestPrimitiveType.INSTANCE); + .addPrimitiveType(TEST_PRIMITIVE_TYPE); RaftServer server = builder.build(); servers.add(server); @@ -625,7 +621,7 @@ private RaftClient createClient() throws Exception { * Creates a test session. */ private PartitionProxy createProxy(RaftClient client, ReadConsistency consistency) { - return client.proxyBuilder("test", TestPrimitiveType.INSTANCE, new ServiceConfig()) + return client.proxyBuilder("test", TEST_PRIMITIVE_TYPE, new ServiceConfig()) .withReadConsistency(consistency) .withCommunicationStrategy(COMMUNICATION_STRATEGY) .build() @@ -638,32 +634,10 @@ private PartitionProxy createProxy(RaftClient client, ReadConsistency consistenc private static final OperationId REMOVE = OperationId.command("remove"); private static final OperationId INDEX = OperationId.command("index"); - /** - * Test primitive type. - */ - private static class TestPrimitiveType implements PrimitiveType { - static final TestPrimitiveType INSTANCE = new TestPrimitiveType(); - - @Override - public String id() { - return "test"; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new FuzzStateMachine(config); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveConfig config, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } - } + private static final PrimitiveType TEST_PRIMITIVE_TYPE = PrimitiveType.builder() + .withName("test") + .withServiceClass(FuzzStateMachine.class) + .build(); /** * Fuzz test state machine. diff --git a/tests/src/main/java/io/atomix/protocols/raft/test/RaftPerformanceTest.java b/tests/src/main/java/io/atomix/protocols/raft/test/RaftPerformanceTest.java index 8fcec05f67..076a99cb0f 100644 --- a/tests/src/main/java/io/atomix/protocols/raft/test/RaftPerformanceTest.java +++ b/tests/src/main/java/io/atomix/protocols/raft/test/RaftPerformanceTest.java @@ -24,9 +24,6 @@ import io.atomix.cluster.messaging.ManagedMessagingService; import io.atomix.cluster.messaging.MessagingService; import io.atomix.cluster.messaging.impl.NettyMessagingService; -import io.atomix.primitive.DistributedPrimitiveBuilder; -import io.atomix.primitive.PrimitiveConfig; -import io.atomix.primitive.PrimitiveManagementService; import io.atomix.primitive.PrimitiveType; import io.atomix.primitive.operation.OperationId; import io.atomix.primitive.operation.OperationType; @@ -37,7 +34,6 @@ import io.atomix.primitive.service.BackupInput; import io.atomix.primitive.service.BackupOutput; import io.atomix.primitive.service.Commit; -import io.atomix.primitive.service.PrimitiveService; import io.atomix.primitive.service.ServiceConfig; import io.atomix.primitive.service.ServiceExecutor; import io.atomix.primitive.session.SessionId; @@ -499,7 +495,7 @@ private RaftServer createServer(Member member, List members) throws Unkn .withMaxEntriesPerSegment(32768) .withMaxSegmentSize(1024 * 1024) .build()) - .addPrimitiveType(TestPrimitiveType.INSTANCE); + .addPrimitiveType(TEST_PRIMITIVE_TYPE); RaftServer server = builder.build(); servers.add(server); @@ -535,7 +531,7 @@ private RaftClient createClient() throws Exception { * Creates a test session. */ private PartitionProxy createProxy(RaftClient client) { - return client.proxyBuilder("test", TestPrimitiveType.INSTANCE, new ServiceConfig()) + return client.proxyBuilder("test", TEST_PRIMITIVE_TYPE, new ServiceConfig()) .withReadConsistency(READ_CONSISTENCY) .withCommunicationStrategy(COMMUNICATION_STRATEGY) .build(); @@ -546,32 +542,10 @@ private PartitionProxy createProxy(RaftClient client) { private static final OperationId REMOVE = OperationId.command("remove"); private static final OperationId INDEX = OperationId.command("index"); - /** - * Test primitive type. - */ - private static class TestPrimitiveType implements PrimitiveType { - static final TestPrimitiveType INSTANCE = new TestPrimitiveType(); - - @Override - public String id() { - return "test"; - } - - @Override - public PrimitiveService newService(ServiceConfig config) { - return new PerformanceService(config); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } - - @Override - public DistributedPrimitiveBuilder newPrimitiveBuilder(String name, PrimitiveConfig config, PrimitiveManagementService managementService) { - throw new UnsupportedOperationException(); - } - } + private static final PrimitiveType TEST_PRIMITIVE_TYPE = PrimitiveType.builder() + .withName("test") + .withServiceClass(PerformanceService.class) + .build(); /** * Performance test state machine. diff --git a/utils/pom.xml b/utils/pom.xml index ff3454fd27..95b21be0c5 100644 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -47,6 +47,11 @@ kryo ${kryo.version} + + com.typesafe + config + ${config.version} + diff --git a/config/src/main/java/io/atomix/core/config/jackson/impl/ProfileDeserializer.java b/utils/src/main/java/io/atomix/utils/AbstractNamed.java similarity index 62% rename from config/src/main/java/io/atomix/core/config/jackson/impl/ProfileDeserializer.java rename to utils/src/main/java/io/atomix/utils/AbstractNamed.java index 47d32281f4..cc2db37862 100644 --- a/config/src/main/java/io/atomix/core/config/jackson/impl/ProfileDeserializer.java +++ b/utils/src/main/java/io/atomix/utils/AbstractNamed.java @@ -13,17 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.atomix.core.config.jackson.impl; - -import io.atomix.core.profile.Profile; -import io.atomix.core.profile.Profiles; +package io.atomix.utils; /** - * Atomix profile deserializer. + * Abstract named object. */ -public class ProfileDeserializer extends PolymorphicTypeDeserializer { - @SuppressWarnings("unchecked") - public ProfileDeserializer() { - super(Profile.class, name -> Profiles.getNamedProfile(name).getClass()); +public abstract class AbstractNamed implements Named { + private String name; + + protected AbstractNamed() { + this(null); + } + + protected AbstractNamed(String name) { + this.name = name; + } + + @Override + public String name() { + return name; } -} \ No newline at end of file +} diff --git a/core/src/main/java/io/atomix/core/profile/NamedProfile.java b/utils/src/main/java/io/atomix/utils/Named.java similarity index 79% rename from core/src/main/java/io/atomix/core/profile/NamedProfile.java rename to utils/src/main/java/io/atomix/utils/Named.java index 8d7e71ee2b..64cbf998eb 100644 --- a/core/src/main/java/io/atomix/core/profile/NamedProfile.java +++ b/utils/src/main/java/io/atomix/utils/Named.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.atomix.core.profile; +package io.atomix.utils; /** - * Named Atomix profile. + * Named object. */ -public interface NamedProfile extends Profile { +public interface Named { /** - * Returns the profile name. + * Returns the object name. * - * @return the profile name + * @return the object name */ String name(); diff --git a/utils/src/main/java/io/atomix/utils/Services.java b/utils/src/main/java/io/atomix/utils/Services.java deleted file mode 100644 index c72a49b730..0000000000 --- a/utils/src/main/java/io/atomix/utils/Services.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2017-present Open Networking Foundation - * - * 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.atomix.utils; - -import com.google.common.collect.Maps; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; - -/** - * Service utilities. - */ -public final class Services { - private static final Map services = Maps.newConcurrentMap(); - - /** - * Loads the service for the given service class. - * - * @param serviceClass the service class for which to load the service - * @param the service type - * @return the registered service of the given type - */ - @SuppressWarnings("unchecked") - public static T load(Class serviceClass, ClassLoader classLoader) { - return (T) services.computeIfAbsent(serviceClass, s -> ServiceLoader.load(serviceClass, classLoader).iterator().next()); - } - - /** - * Loads all services for the given service class. - * - * @param serviceClass the service class for which to load the services - * @param the service type - * @return the registered services of the given type - */ - public static Collection loadAll(Class serviceClass, ClassLoader classLoader) { - List services = new ArrayList<>(); - Iterator iterator = ServiceLoader.load(serviceClass, classLoader).iterator(); - while (iterator.hasNext()) { - services.add(iterator.next()); - } - return services; - } - - private Services() { - } -} diff --git a/primitive/src/main/java/io/atomix/primitive/service/PrimitiveServiceFactory.java b/utils/src/main/java/io/atomix/utils/Type.java similarity index 71% rename from primitive/src/main/java/io/atomix/primitive/service/PrimitiveServiceFactory.java rename to utils/src/main/java/io/atomix/utils/Type.java index 16d20d404c..e6462201d6 100644 --- a/primitive/src/main/java/io/atomix/primitive/service/PrimitiveServiceFactory.java +++ b/utils/src/main/java/io/atomix/utils/Type.java @@ -13,19 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.atomix.primitive.service; +package io.atomix.utils; /** - * Primitive service factory. + * Identifier interface for types. */ -@FunctionalInterface -public interface PrimitiveServiceFactory { +public interface Type { /** - * Creates a new primitive service instance. + * Returns the type name. * - * @return the primitive service instance + * @return the type name */ - PrimitiveService create(); + String name(); } diff --git a/utils/src/main/java/io/atomix/utils/config/ConfigMapper.java b/utils/src/main/java/io/atomix/utils/config/ConfigMapper.java new file mode 100644 index 0000000000..fc5f86c557 --- /dev/null +++ b/utils/src/main/java/io/atomix/utils/config/ConfigMapper.java @@ -0,0 +1,506 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.utils.config; + +import com.google.common.base.Joiner; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; +import com.typesafe.config.ConfigList; +import com.typesafe.config.ConfigMemorySize; +import com.typesafe.config.ConfigObject; +import com.typesafe.config.ConfigValue; +import com.typesafe.config.ConfigValueType; +import io.atomix.utils.Named; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Utility for applying Typesafe configurations to Atomix configuration objects. + */ +public class ConfigMapper { + private final Map polymorphicTypeMappers = Maps.newHashMap(); + private final ClassLoader classLoader; + + public ConfigMapper(ClassLoader classLoader) { + this(classLoader, Collections.emptyList()); + } + + public ConfigMapper(ClassLoader classLoader, PolymorphicTypeMapper... polymorphicTypeMappers) { + this(classLoader, Arrays.asList(polymorphicTypeMappers)); + } + + public ConfigMapper(ClassLoader classLoader, Collection polymorphicTypeMappers) { + polymorphicTypeMappers.forEach(mapper -> this.polymorphicTypeMappers.put(mapper.getTypedClass(), mapper)); + this.classLoader = classLoader; + } + + /** + * Loads the given resources using the configuration mapper. + * + * @param type the type to load + * @param resources the resources to load + * @param the resulting type + * @return the loaded configuration + */ + public T loadResources(Class type, String... resources) { + Config config = null; + for (String resource : resources) { + if (config == null) { + config = ConfigFactory.load(resource); + } else { + config = config.withFallback(ConfigFactory.load(resource)); + } + } + return map(config, type); + } + + /** + * Loads the given resources using the configuration mapper. + * + * @param type the type to load + * @param configString the initial configuration string + * @param resources the resources to load + * @param the resulting type + * @return the loaded configuration + */ + public T loadStringAndResources(Class type, String configString, String... resources) { + Config config = ConfigFactory.parseString(configString); + for (String resource : resources) { + if (config == null) { + config = ConfigFactory.load(resource); + } else { + config = config.withFallback(ConfigFactory.load(resource)); + } + } + return map(config, type); + } + + /** + * Applies the given configuration to the given type. + * + * @param config the configuration to apply + * @param clazz the class to which to apply the configuration + */ + private T map(Config config, Class clazz) { + return map(config, null, null, clazz, config); + } + + /** + * Applies the given configuration to the given type. + * + * @param config the configuration to apply + * @param clazz the class to which to apply the configuration + * @param rootConfig the root configuration + */ + @SuppressWarnings("unchecked") + private T map(Config config, String path, String name, Class clazz, Config rootConfig) { + T instance; + io.atomix.utils.Type type = null; + if (isPolymorphicType(clazz)) { + PolymorphicTypeMapper typeMapper = polymorphicTypeMappers.get(clazz); + if (typeMapper == null) { + throw new ConfigurationException("Cannot instantiate abstract type " + clazz.getName()); + } + + String typeName = config.getString(typeMapper.getTypedPath()); + String typePath = typeMapper.getTypePath(typeName); + Config typeConfig = rootConfig.getConfig(typePath); + if (typeConfig == null) { + throw new ConfigurationException("Unknown type definition " + typePath); + } + type = (io.atomix.utils.Type) map(typeConfig, typePath, typeName, typeMapper.getTypeClass(), rootConfig); + Class> concreteClass = typeMapper.getConcreteTypedClass(type); + try { + instance = (T) concreteClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new ConfigurationException(concreteClass.getName() + " needs a public no-args constructor to be used as a bean", e); + } + } else { + try { + instance = clazz.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new ConfigurationException(clazz.getName() + " needs a public no-args constructor to be used as a bean", e); + } + } + + Map propertyNames = new HashMap<>(); + for (Map.Entry configProp : config.root().entrySet()) { + String originalName = configProp.getKey(); + String camelName = toCamelCase(originalName); + // if a setting is in there both as some hyphen name and the camel name, + // the camel one wins + if (propertyNames.containsKey(camelName) && !originalName.equals(camelName)) { + // if we aren't a camel name to start with, we lose. + // if we are or we are the first matching key, we win. + } else { + propertyNames.put(camelName, originalName); + } + } + + mapSetters(instance, clazz, type, path, name, propertyNames, config, rootConfig); + mapFields(instance, clazz, type, path, name, propertyNames, config, rootConfig); + + if (path != null && !propertyNames.isEmpty()) { + Set cleanNames = propertyNames.keySet() + .stream() + .filter(propertyName -> !isPolymorphicType(clazz) || !propertyName.equals(polymorphicTypeMappers.get(clazz).getTypedPath())) + .map(propertyName -> toPath(toPath(path, name), propertyName)) + .collect(Collectors.toSet()); + if (!cleanNames.isEmpty()) { + throw new ConfigurationException("Unknown properties present in configuration: " + Joiner.on(", ").join(cleanNames)); + } + } + return instance; + } + + private void mapSetters(T instance, Class clazz, io.atomix.utils.Type type, String path, String name, Map propertyNames, Config config, Config rootConfig) { + try { + for (SetterDescriptor descriptor : getSetterDescriptors(instance.getClass())) { + Method setter = descriptor.setter; + Type parameterType = setter.getGenericParameterTypes()[0]; + Class parameterClass = setter.getParameterTypes()[0]; + + String configPropName = propertyNames.remove(descriptor.name); + if (configPropName == null) { + if ((Named.class.isAssignableFrom(clazz) || NamedConfig.class.isAssignableFrom(clazz)) + && descriptor.setter.getParameterTypes()[0] == String.class && name != null && descriptor.name.equals("name")) { + setter.invoke(instance, name); + } + continue; + } + + Object value = getValue(instance.getClass(), parameterType, parameterClass, config, toPath(path, name), configPropName, rootConfig); + if (value != null) { + setter.invoke(instance, value); + } + } + } catch (IllegalAccessException e) { + throw new ConfigurationException(instance.getClass().getName() + " getters and setters are not accessible, they must be for use as a bean", e); + } catch (InvocationTargetException e) { + throw new ConfigurationException("Calling bean method on " + instance.getClass().getName() + " caused an exception", e); + } + } + + private void mapFields(T instance, Class clazz, io.atomix.utils.Type type, String path, String name, Map propertyNames, Config config, Config rootConfig) { + try { + for (FieldDescriptor descriptor : getFieldDescriptors(instance.getClass())) { + Field field = descriptor.field; + field.setAccessible(true); + + Type genericType = field.getGenericType(); + Class fieldClass = field.getType(); + + String configPropName = propertyNames.remove(descriptor.name); + if (configPropName == null) { + if (Named.class.isAssignableFrom(clazz) && field.getType() == String.class && name != null && descriptor.name.equals("name")) { + field.set(instance, name); + } + continue; + } + + Object value = getValue(instance.getClass(), genericType, fieldClass, config, toPath(path, name), configPropName, rootConfig); + if (value != null) { + field.set(instance, value); + } + } + } catch (IllegalAccessException e) { + throw new ConfigurationException(instance.getClass().getName() + " fields are not accessible, they must be for use as a bean", e); + } + } + + // we could magically make this work in many cases by doing + // getAnyRef() (or getValue().unwrapped()), but anytime we + // rely on that, we aren't doing the type conversions Config + // usually does, and we will throw ClassCastException instead + // of a nicer error message giving the name of the bad + // setting. So, instead, we only support a limited number of + // types plus you can always use Object, ConfigValue, Config, + // ConfigObject, etc. as an escape hatch. + private Object getValue(Class beanClass, Type parameterType, Class parameterClass, Config config, String configPath, String configPropName, Config rootConfig) { + if (parameterClass == Boolean.class || parameterClass == boolean.class) { + return config.getBoolean(configPropName); + } else if (parameterClass == Integer.class || parameterClass == int.class) { + return config.getInt(configPropName); + } else if (parameterClass == Double.class || parameterClass == double.class) { + return config.getDouble(configPropName); + } else if (parameterClass == Long.class || parameterClass == long.class) { + return config.getLong(configPropName); + } else if (parameterClass == String.class) { + return config.getString(configPropName); + } else if (parameterClass == Duration.class) { + return config.getDuration(configPropName); + } else if (parameterClass == ConfigMemorySize.class) { + return config.getMemorySize(configPropName); + } else if (parameterClass == Object.class) { + return config.getAnyRef(configPropName); + } else if (parameterClass == List.class) { + return getListValue(beanClass, parameterType, parameterClass, config, configPath, configPropName, rootConfig); + } else if (parameterClass == Set.class) { + return getSetValue(beanClass, parameterType, parameterClass, config, configPath, configPropName, rootConfig); + } else if (parameterClass == Map.class) { + return getMapValue(beanClass, parameterType, parameterClass, config, configPath, configPropName, rootConfig); + } else if (parameterClass == Config.class) { + return config.getConfig(configPropName); + } else if (parameterClass == ConfigObject.class) { + return config.getObject(configPropName); + } else if (parameterClass == ConfigValue.class) { + return config.getValue(configPropName); + } else if (parameterClass == ConfigList.class) { + return config.getList(configPropName); + } else if (parameterClass == Class.class) { + String className = config.getString(configPropName); + try { + return classLoader.loadClass(className); + } catch (ClassNotFoundException e) { + throw new ConfigurationException("Failed to load class: " + className); + } + } else if (parameterClass.isEnum()) { + @SuppressWarnings("unchecked") + Enum enumValue = config.getEnum((Class) parameterClass, configPropName); + return enumValue; + } else { + return map(config.getConfig(configPropName), configPath, configPropName, parameterClass, rootConfig); + } + } + + private Map getMapValue(Class beanClass, Type parameterType, Class parameterClass, Config config, String configPath, String configPropName, Config rootConfig) { + Type[] typeArgs = ((ParameterizedType) parameterType).getActualTypeArguments(); + Type keyType = typeArgs[0]; + Type valueType = typeArgs[1]; + + Map map = new HashMap<>(); + Config childConfig = config.getConfig(configPropName); + for (String key : config.getObject(configPropName).unwrapped().keySet()) { + Object value = getValue(Map.class, valueType, (Class) valueType, childConfig, toPath(configPath, configPropName), key, rootConfig); + map.put(getKeyValue(keyType, key), value); + } + return map; + } + + private Object getKeyValue(Type keyType, String key) { + if (keyType == Boolean.class || keyType == boolean.class) { + return Boolean.parseBoolean(key); + } else if (keyType == Integer.class || keyType == int.class) { + return Integer.parseInt(key); + } else if (keyType == Double.class || keyType == double.class) { + return Double.parseDouble(key); + } else if (keyType == Long.class || keyType == long.class) { + return Long.parseLong(key); + } else if (keyType == String.class) { + return key; + } else { + throw new ConfigurationException("Invalid map key type: " + keyType); + } + } + + private Object getSetValue(Class beanClass, Type parameterType, Class parameterClass, Config config, String configPath, String configPropName, Config rootConfig) { + return new HashSet((List) getListValue(beanClass, parameterType, parameterClass, config, configPath, configPropName, rootConfig)); + } + + private Object getListValue(Class beanClass, Type parameterType, Class parameterClass, Config config, String configPath, String configPropName, Config rootConfig) { + Type elementType = ((ParameterizedType) parameterType).getActualTypeArguments()[0]; + + if (elementType == Boolean.class) { + return config.getBooleanList(configPropName); + } else if (elementType == Integer.class) { + return config.getIntList(configPropName); + } else if (elementType == Double.class) { + return config.getDoubleList(configPropName); + } else if (elementType == Long.class) { + return config.getLongList(configPropName); + } else if (elementType == String.class) { + return config.getStringList(configPropName); + } else if (elementType == Duration.class) { + return config.getDurationList(configPropName); + } else if (elementType == ConfigMemorySize.class) { + return config.getMemorySizeList(configPropName); + } else if (elementType == Object.class) { + return config.getAnyRefList(configPropName); + } else if (elementType == Config.class) { + return config.getConfigList(configPropName); + } else if (elementType == ConfigObject.class) { + return config.getObjectList(configPropName); + } else if (elementType == ConfigValue.class) { + return config.getList(configPropName); + } else if (((Class) elementType).isEnum()) { + @SuppressWarnings("unchecked") + List enumValues = config.getEnumList((Class) elementType, configPropName); + return enumValues; + } else { + List beanList = new ArrayList<>(); + List configList = config.getConfigList(configPropName); + int i = 0; + for (Config listMember : configList) { + beanList.add(map(listMember, toPath(configPath, configPropName), String.valueOf(i), (Class) elementType, rootConfig)); + } + return beanList; + } + } + + private String toPath(String path, String name) { + return path != null ? String.format("%s.%s", path, name) : name; + } + + private boolean isPolymorphicType(Class clazz) { + return polymorphicTypeMappers.containsKey(clazz); + } + + private static ConfigValueType getValueTypeOrNull(Class parameterClass) { + if (parameterClass == Boolean.class || parameterClass == boolean.class) { + return ConfigValueType.BOOLEAN; + } else if (parameterClass == Integer.class || parameterClass == int.class) { + return ConfigValueType.NUMBER; + } else if (parameterClass == Double.class || parameterClass == double.class) { + return ConfigValueType.NUMBER; + } else if (parameterClass == Long.class || parameterClass == long.class) { + return ConfigValueType.NUMBER; + } else if (parameterClass == String.class) { + return ConfigValueType.STRING; + } else if (parameterClass == Duration.class) { + return null; + } else if (parameterClass == ConfigMemorySize.class) { + return null; + } else if (parameterClass == List.class) { + return ConfigValueType.LIST; + } else if (parameterClass == Map.class) { + return ConfigValueType.OBJECT; + } else if (parameterClass == Config.class) { + return ConfigValueType.OBJECT; + } else if (parameterClass == ConfigObject.class) { + return ConfigValueType.OBJECT; + } else if (parameterClass == ConfigList.class) { + return ConfigValueType.LIST; + } else { + return null; + } + } + + private static String toCamelCase(String originalName) { + String[] words = originalName.split("-+"); + StringBuilder nameBuilder = new StringBuilder(originalName.length()); + for (String word : words) { + if (nameBuilder.length() == 0) { + nameBuilder.append(word); + } else { + nameBuilder.append(word.substring(0, 1).toUpperCase()); + nameBuilder.append(word.substring(1)); + } + } + return nameBuilder.toString(); + } + + private static String toSetterName(String name) { + return "set" + name.substring(0, 1).toUpperCase() + name.substring(1); + } + + private static Collection getSetterDescriptors(Class clazz) { + Map descriptors = Maps.newHashMap(); + for (Method method : clazz.getMethods()) { + String name = method.getName(); + if (method.getParameterTypes().length == 1 + && name.length() > 3 + && name.substring(0, 3).equals("set") + && name.charAt(3) >= 'A' + && name.charAt(3) <= 'Z') { + name = method.getName().substring(3); + name = name.length() > 1 + ? name.substring(0, 1).toLowerCase() + name.substring(1) + : name.toLowerCase(); + if (name.endsWith("Config")) { + name = name.substring(0, name.length() - "Config".length()); + } + + SetterDescriptor descriptor = descriptors.get(name); + if (descriptor != null) { + Class type = descriptor.setter.getParameterTypes()[0]; + if (getValueTypeOrNull(type) == null && type != Class.class) { + descriptors.put(name, new SetterDescriptor(name, method)); + } + } else { + descriptors.put(name, new SetterDescriptor(name, method)); + } + } + } + return descriptors.values(); + } + + private static Collection getFieldDescriptors(Class type) { + Class clazz = type; + Map descriptors = Maps.newHashMap(); + while (clazz != Object.class) { + for (Field field : clazz.getDeclaredFields()) { + if (Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) { + continue; + } + + Method method = Stream.of(clazz.getMethods()) + .filter(m -> m.getName().equals(toSetterName(field.getName()))) + .findFirst() + .orElse(null); + if (method != null) { + continue; + } + + String name = field.getName(); + if (name.endsWith("Config")) { + name = name.substring(0, name.length() - "Config".length()); + } + descriptors.putIfAbsent(name, new FieldDescriptor(name, field)); + } + clazz = clazz.getSuperclass(); + } + return Lists.newArrayList(descriptors.values()); + } + + private static class SetterDescriptor { + private final String name; + private final Method setter; + + SetterDescriptor(String name, Method setter) { + this.name = name; + this.setter = setter; + } + } + + private static class FieldDescriptor { + private final String name; + private final Field field; + + FieldDescriptor(String name, Field field) { + this.name = name; + this.field = field; + } + } +} diff --git a/utils/src/main/java/io/atomix/utils/config/ConfigProvider.java b/utils/src/main/java/io/atomix/utils/config/ConfigProvider.java deleted file mode 100644 index a04aaf02ce..0000000000 --- a/utils/src/main/java/io/atomix/utils/config/ConfigProvider.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2018-present Open Networking Foundation - * - * 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.atomix.utils.config; - -import java.io.File; - -/** - * Atomix configuration provider. - */ -public interface ConfigProvider { - - /** - * Returns a boolean indicating whether the given file matches this provider. - * - * @param file the file to check - * @return indicates whether the given file matches this provider - */ - boolean isConfigFile(File file); - - /** - * Loads the given configuration file using the given configuration type. - * - * @param file the file to load - * @param type the type with which to load the configuration - * @param the configuration type - * @return the configuration instance - */ - C load(File file, Class type); - - /** - * Loads the given configuration file using the given configuration type. - * - * @param config the configuration string - * @param type the type with which to load the configuration - * @param the configuration type - * @return the configuration instance - */ - C load(String config, Class type); - -} diff --git a/utils/src/main/java/io/atomix/utils/config/Configs.java b/utils/src/main/java/io/atomix/utils/config/Configs.java deleted file mode 100644 index 90fe8e5b68..0000000000 --- a/utils/src/main/java/io/atomix/utils/config/Configs.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018-present Open Networking Foundation - * - * 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.atomix.utils.config; - -import io.atomix.utils.Services; - -import java.io.File; - -/** - * Configuration utilities. - */ -public final class Configs { - - /** - * Loads the given configuration string using the given configuration type. - * - * @param config the configurations string - * @param type the type with which to load the configuration - * @param the configuration type - * @return the configuration instance - */ - public static C load(String config, Class type, ClassLoader classLoader) { - Exception error = null; - for (ConfigProvider provider : Services.loadAll(ConfigProvider.class, classLoader)) { - try { - return provider.load(config, type); - } catch (Exception e) { - error = e; - } - } - throw new ConfigurationException("Unknown configuration format", error); - } - - /** - * Loads the given configuration file using the given configuration type. - * - * @param file the file to load - * @param type the type with which to load the configuration - * @param the configuration type - * @return the configuration instance - */ - public static C load(File file, Class type, ClassLoader classLoader) { - for (ConfigProvider provider : Services.loadAll(ConfigProvider.class, classLoader)) { - if (provider.isConfigFile(file)) { - return provider.load(file, type); - } - } - throw new ConfigurationException("Unknown configuration type: " + file.getName()); - } - - private Configs() { - } -} diff --git a/utils/src/main/java/io/atomix/utils/config/NamedConfig.java b/utils/src/main/java/io/atomix/utils/config/NamedConfig.java new file mode 100644 index 0000000000..fd9d1a91ef --- /dev/null +++ b/utils/src/main/java/io/atomix/utils/config/NamedConfig.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.utils.config; + +/** + * Named configuration. + */ +public interface NamedConfig> extends Config { + + /** + * Returns the configuration name. + * + * @return the configuration name + */ + String getName(); + + /** + * Sets the configuration name. + * + * @param name the configuration name + * @return the configuration object + */ + C setName(String name); + +} diff --git a/utils/src/main/java/io/atomix/utils/config/PolymorphicTypeMapper.java b/utils/src/main/java/io/atomix/utils/config/PolymorphicTypeMapper.java new file mode 100644 index 0000000000..3dbfd6391c --- /dev/null +++ b/utils/src/main/java/io/atomix/utils/config/PolymorphicTypeMapper.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.utils.config; + +import io.atomix.utils.Type; + +/** + * Polymorphic type mapper. + */ +public abstract class PolymorphicTypeMapper { + private final Class typedClass; + private final Class typeClass; + + protected PolymorphicTypeMapper(Class typedClass, Class typeClass) { + this.typedClass = typedClass; + this.typeClass = typeClass; + } + + /** + * Returns the polymorphic type. + * + * @return the polymorphic type + */ + public Class getTypedClass() { + return typedClass; + } + + /** + * Returns the type class. + * + * @return the type class + */ + public Class getTypeClass() { + return typeClass; + } + + /** + * Returns the type path. + * + * @return the type path + */ + public String getTypedPath() { + return "type"; + } + + /** + * Returns the type path. + * + * @param typeName the type name + * @return the type path + */ + public abstract String getTypePath(String typeName); + + /** + * Returns the concrete configuration class. + * + * @param type the type instance + * @return the concrete configuration class + */ + public abstract Class getConcreteTypedClass(U type); +} diff --git a/utils/src/main/java/io/atomix/utils/config/TypedConfig.java b/utils/src/main/java/io/atomix/utils/config/TypedConfig.java new file mode 100644 index 0000000000..18edb94fad --- /dev/null +++ b/utils/src/main/java/io/atomix/utils/config/TypedConfig.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018-present Open Networking Foundation + * + * 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.atomix.utils.config; + +/** + * Typed configuration. + */ +public interface TypedConfig> extends Config { + + /** + * Returns the type name. + * + * @return the type name + */ + String getType(); + +}