diff --git a/hazelcast-spring/src/main/java/com/hazelcast/spring/HazelcastConfigBeanDefinitionParser.java b/hazelcast-spring/src/main/java/com/hazelcast/spring/HazelcastConfigBeanDefinitionParser.java index d1ba154512a9..241056fadee5 100644 --- a/hazelcast-spring/src/main/java/com/hazelcast/spring/HazelcastConfigBeanDefinitionParser.java +++ b/hazelcast-spring/src/main/java/com/hazelcast/spring/HazelcastConfigBeanDefinitionParser.java @@ -41,6 +41,7 @@ import com.hazelcast.config.JoinConfig; import com.hazelcast.config.ListConfig; import com.hazelcast.config.ListenerConfig; +import com.hazelcast.config.LockConfig; import com.hazelcast.config.LoginModuleConfig; import com.hazelcast.config.ManagementCenterConfig; import com.hazelcast.config.MapAttributeConfig; @@ -150,6 +151,7 @@ private class SpringXmlConfigBuilder extends SpringXmlBuilderHelper { private ManagedMap mapConfigManagedMap; private ManagedMap cacheConfigManagedMap; private ManagedMap queueManagedMap; + private ManagedMap lockManagedMap; private ManagedMap ringbufferManagedMap; private ManagedMap reliableTopicManagedMap; private ManagedMap semaphoreManagedMap; @@ -170,6 +172,7 @@ public SpringXmlConfigBuilder(ParserContext parserContext) { this.mapConfigManagedMap = createManagedMap("mapConfigs"); this.cacheConfigManagedMap = createManagedMap("cacheConfigs"); this.queueManagedMap = createManagedMap("queueConfigs"); + this.lockManagedMap = createManagedMap("lockConfigs"); this.ringbufferManagedMap = createManagedMap("ringbufferConfigs"); this.reliableTopicManagedMap = createManagedMap("reliableTopicConfigs"); this.semaphoreManagedMap = createManagedMap("semaphoreConfigs"); @@ -212,6 +215,8 @@ public void handleConfig(final Element element) { handleDurableExecutor(node); } else if ("queue".equals(nodeName)) { handleQueue(node); + } else if ("lock".equals(nodeName)) { + handleLock(node); } else if ("ringbuffer".equals(nodeName)) { handleRingbuffer(node); } else if ("reliable-topic".equals(nodeName)) { @@ -586,6 +591,18 @@ public void handleSemaphore(Node node) { semaphoreManagedMap.put(getAttribute(node, "name"), builder.getBeanDefinition()); } + public void handleLock(Node node) { + final BeanDefinitionBuilder lockConfigBuilder = createBeanBuilder(LockConfig.class); + fillAttributeValues(node, lockConfigBuilder); + for (Node childNode : childElements(node)) { + final String nodeName = cleanNodeName(childNode); + if ("quorum-ref".equals(nodeName)) { + lockConfigBuilder.addPropertyValue("quorumName", getTextContent(childNode)); + } + } + lockManagedMap.put(getAttribute(node, "name"), lockConfigBuilder.getBeanDefinition()); + } + public void handleRingbuffer(Node node) { final BeanDefinitionBuilder ringbufferConfigBuilder = createBeanBuilder(RingbufferConfig.class); fillAttributeValues(node, ringbufferConfigBuilder); diff --git a/hazelcast-spring/src/main/resources/hazelcast-spring-3.8.xsd b/hazelcast-spring/src/main/resources/hazelcast-spring-3.8.xsd index b09a61ea8a0c..b369c6a4eccd 100644 --- a/hazelcast-spring/src/main/resources/hazelcast-spring-3.8.xsd +++ b/hazelcast-spring/src/main/resources/hazelcast-spring-3.8.xsd @@ -162,6 +162,14 @@ + + + + + + + + diff --git a/hazelcast-spring/src/test/java/com/hazelcast/spring/TestFullApplicationContext.java b/hazelcast-spring/src/test/java/com/hazelcast/spring/TestFullApplicationContext.java index 6d9309d65940..13a362e6808c 100644 --- a/hazelcast-spring/src/test/java/com/hazelcast/spring/TestFullApplicationContext.java +++ b/hazelcast-spring/src/test/java/com/hazelcast/spring/TestFullApplicationContext.java @@ -33,6 +33,7 @@ import com.hazelcast.config.ItemListenerConfig; import com.hazelcast.config.ListConfig; import com.hazelcast.config.ListenerConfig; +import com.hazelcast.config.LockConfig; import com.hazelcast.config.ManagementCenterConfig; import com.hazelcast.config.MapAttributeConfig; import com.hazelcast.config.MapConfig; @@ -389,7 +390,7 @@ public void testMapConfig() { @Test public void testQueueConfig() { - QueueConfig testQConfig = config.getQueueConfig("testQ"); + final QueueConfig testQConfig = config.getQueueConfig("testQ"); assertNotNull(testQConfig); assertEquals("testQ", testQConfig.getName()); assertEquals(1000, testQConfig.getMaxSize()); @@ -398,12 +399,14 @@ public void testQueueConfig() { ItemListenerConfig listenerConfig = testQConfig.getItemListenerConfigs().get(0); assertEquals("com.hazelcast.spring.DummyItemListener", listenerConfig.getClassName()); assertTrue(listenerConfig.isIncludeValue()); - QueueConfig qConfig = config.getQueueConfig("q"); + + final QueueConfig qConfig = config.getQueueConfig("q"); assertNotNull(qConfig); assertEquals("q", qConfig.getName()); assertEquals(2500, qConfig.getMaxSize()); assertFalse(qConfig.isStatisticsEnabled()); assertEquals(100, qConfig.getEmptyQueueTtl()); + assertEquals("my-quorum", qConfig.getQuorumName()); final QueueConfig queueWithStore1 = config.getQueueConfig("queueWithStore1"); assertNotNull(queueWithStore1); @@ -430,6 +433,14 @@ public void testQueueConfig() { assertEquals(dummyQueueStoreFactory, storeConfig4.getFactoryImplementation()); } + @Test + public void testLockConfig() { + final LockConfig lockConfig = config.getLockConfig("lock"); + assertNotNull(lockConfig); + assertEquals("lock", lockConfig.getName()); + assertEquals("my-quorum", lockConfig.getQuorumName()); + } + @Test public void testRingbufferConfig() { final RingbufferConfig testRingbuffer = config.getRingbufferConfig("testRingbuffer"); diff --git a/hazelcast-spring/src/test/resources/com/hazelcast/spring/fullConfig-applicationContext-hazelcast.xml b/hazelcast-spring/src/test/resources/com/hazelcast/spring/fullConfig-applicationContext-hazelcast.xml index a924852d6ac6..af9c6a9c82f8 100644 --- a/hazelcast-spring/src/test/resources/com/hazelcast/spring/fullConfig-applicationContext-hazelcast.xml +++ b/hazelcast-spring/src/test/resources/com/hazelcast/spring/fullConfig-applicationContext-hazelcast.xml @@ -152,10 +152,7 @@ queue-capacity="300" statistics-enabled="false" /> - - + @@ -165,7 +162,9 @@ backup-count="1" async-backup-count="1" statistics-enabled="false" - empty-queue-ttl="100"/> + empty-queue-ttl="100"> + my-quorum + @@ -180,6 +179,10 @@ + + my-quorum + + > constructors = new ConcurrentHashMap>(); - + private final ConcurrentMap quorumConfigCache = new ConcurrentHashMap(); + private final ContextMutexFactory quorumConfigCacheMutexFactory = new ContextMutexFactory(); private final long maxLeaseTimeInMillis; public LockServiceImpl(NodeEngine nodeEngine) { @@ -310,4 +315,17 @@ public void clientDisconnected(String clientUuid) { public static long getMaxLeaseTimeInMillis(HazelcastProperties hazelcastProperties) { return hazelcastProperties.getMillis(GroupProperty.LOCK_MAX_LEASE_TIME_SECONDS); } + + @Override + public String getQuorumName(final String name) { + // we use caching here because lock operations are often and we should avoid lock config lookup + return getOrPutSynchronized(quorumConfigCache, name, quorumConfigCacheMutexFactory, + new ConstructorFunction() { + @Override + public String createNew(String arg) { + final LockConfig lockConfig = nodeEngine.getConfig().findLockConfig(name); + return lockConfig.getQuorumName(); + } + }); + } } diff --git a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/AbstractLockOperation.java b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/AbstractLockOperation.java index 06351989ac7b..afca45d63fed 100644 --- a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/AbstractLockOperation.java +++ b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/AbstractLockOperation.java @@ -23,6 +23,7 @@ import com.hazelcast.nio.ObjectDataOutput; import com.hazelcast.nio.serialization.Data; import com.hazelcast.nio.serialization.IdentifiedDataSerializable; +import com.hazelcast.spi.NamedOperation; import com.hazelcast.spi.ObjectNamespace; import com.hazelcast.spi.Operation; import com.hazelcast.spi.PartitionAwareOperation; @@ -31,7 +32,7 @@ import java.util.concurrent.atomic.AtomicLongFieldUpdater; public abstract class AbstractLockOperation extends Operation - implements PartitionAwareOperation, IdentifiedDataSerializable { + implements PartitionAwareOperation, IdentifiedDataSerializable, NamedOperation { public static final int ANY_THREAD = 0; @@ -123,6 +124,11 @@ public final Data getKey() { return key; } + @Override + public String getName() { + return namespace.getObjectName(); + } + @Override public final int getFactoryId() { return LockDataSerializerHook.F_ID; diff --git a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/AwaitBackupOperation.java b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/AwaitBackupOperation.java index 48cc17f40738..141cddb773a8 100644 --- a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/AwaitBackupOperation.java +++ b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/AwaitBackupOperation.java @@ -24,11 +24,12 @@ import com.hazelcast.nio.serialization.Data; import com.hazelcast.spi.BackupOperation; import com.hazelcast.spi.ObjectNamespace; +import com.hazelcast.spi.impl.MutatingOperation; import java.io.IOException; public class AwaitBackupOperation extends AbstractLockOperation - implements BackupOperation { + implements BackupOperation, MutatingOperation { private String originalCaller; private String conditionId; diff --git a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/AwaitOperation.java b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/AwaitOperation.java index ac801c65367e..d7a177857df8 100644 --- a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/AwaitOperation.java +++ b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/AwaitOperation.java @@ -26,11 +26,12 @@ import com.hazelcast.spi.BlockingOperation; import com.hazelcast.spi.ObjectNamespace; import com.hazelcast.spi.Operation; +import com.hazelcast.spi.impl.MutatingOperation; import java.io.IOException; public class AwaitOperation extends AbstractLockOperation - implements BlockingOperation, BackupAwareOperation { + implements BlockingOperation, BackupAwareOperation, MutatingOperation { private String conditionId; private boolean expired; diff --git a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/BeforeAwaitBackupOperation.java b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/BeforeAwaitBackupOperation.java index 505bf94b5ad5..3c5ebb100b88 100644 --- a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/BeforeAwaitBackupOperation.java +++ b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/BeforeAwaitBackupOperation.java @@ -23,10 +23,11 @@ import com.hazelcast.nio.serialization.Data; import com.hazelcast.spi.BackupOperation; import com.hazelcast.spi.ObjectNamespace; +import com.hazelcast.spi.impl.MutatingOperation; import java.io.IOException; -public class BeforeAwaitBackupOperation extends AbstractLockOperation implements BackupOperation { +public class BeforeAwaitBackupOperation extends AbstractLockOperation implements BackupOperation, MutatingOperation { private String conditionId; private String originalCaller; diff --git a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/BeforeAwaitOperation.java b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/BeforeAwaitOperation.java index 7547fcd1bd12..9771b11327d6 100644 --- a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/BeforeAwaitOperation.java +++ b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/BeforeAwaitOperation.java @@ -26,10 +26,11 @@ import com.hazelcast.spi.ObjectNamespace; import com.hazelcast.spi.Operation; import com.hazelcast.spi.WaitNotifyKey; +import com.hazelcast.spi.impl.MutatingOperation; import java.io.IOException; -public class BeforeAwaitOperation extends AbstractLockOperation implements Notifier, BackupAwareOperation { +public class BeforeAwaitOperation extends AbstractLockOperation implements Notifier, BackupAwareOperation, MutatingOperation { private String conditionId; diff --git a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/GetLockCountOperation.java b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/GetLockCountOperation.java index 740a0b1df972..ab2e5d982802 100644 --- a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/GetLockCountOperation.java +++ b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/GetLockCountOperation.java @@ -20,8 +20,9 @@ import com.hazelcast.concurrent.lock.LockStoreImpl; import com.hazelcast.nio.serialization.Data; import com.hazelcast.spi.ObjectNamespace; +import com.hazelcast.spi.ReadonlyOperation; -public class GetLockCountOperation extends AbstractLockOperation { +public class GetLockCountOperation extends AbstractLockOperation implements ReadonlyOperation { public GetLockCountOperation() { } diff --git a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/GetRemainingLeaseTimeOperation.java b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/GetRemainingLeaseTimeOperation.java index c3b857e227ab..787035483a9e 100644 --- a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/GetRemainingLeaseTimeOperation.java +++ b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/GetRemainingLeaseTimeOperation.java @@ -20,8 +20,9 @@ import com.hazelcast.concurrent.lock.LockStoreImpl; import com.hazelcast.nio.serialization.Data; import com.hazelcast.spi.ObjectNamespace; +import com.hazelcast.spi.ReadonlyOperation; -public class GetRemainingLeaseTimeOperation extends AbstractLockOperation { +public class GetRemainingLeaseTimeOperation extends AbstractLockOperation implements ReadonlyOperation { public GetRemainingLeaseTimeOperation() { } diff --git a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/IsLockedOperation.java b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/IsLockedOperation.java index a198bea4574f..ffd8879d1f51 100644 --- a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/IsLockedOperation.java +++ b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/IsLockedOperation.java @@ -20,8 +20,9 @@ import com.hazelcast.concurrent.lock.LockStoreImpl; import com.hazelcast.nio.serialization.Data; import com.hazelcast.spi.ObjectNamespace; +import com.hazelcast.spi.ReadonlyOperation; -public class IsLockedOperation extends AbstractLockOperation { +public class IsLockedOperation extends AbstractLockOperation implements ReadonlyOperation { public IsLockedOperation() { } diff --git a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/LockBackupOperation.java b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/LockBackupOperation.java index 47b47d2d143e..f5ac0d200aee 100644 --- a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/LockBackupOperation.java +++ b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/LockBackupOperation.java @@ -23,10 +23,11 @@ import com.hazelcast.nio.serialization.Data; import com.hazelcast.spi.BackupOperation; import com.hazelcast.spi.ObjectNamespace; +import com.hazelcast.spi.impl.MutatingOperation; import java.io.IOException; -public class LockBackupOperation extends AbstractLockOperation implements BackupOperation { +public class LockBackupOperation extends AbstractLockOperation implements BackupOperation, MutatingOperation { private String originalCallerUuid; diff --git a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/LockOperation.java b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/LockOperation.java index 2f3aefd66bdd..ad815616a3aa 100644 --- a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/LockOperation.java +++ b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/LockOperation.java @@ -26,8 +26,9 @@ import com.hazelcast.spi.ObjectNamespace; import com.hazelcast.spi.Operation; import com.hazelcast.spi.WaitNotifyKey; +import com.hazelcast.spi.impl.MutatingOperation; -public class LockOperation extends AbstractLockOperation implements BlockingOperation, BackupAwareOperation { +public class LockOperation extends AbstractLockOperation implements BlockingOperation, BackupAwareOperation, MutatingOperation { public LockOperation() { } diff --git a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/SignalBackupOperation.java b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/SignalBackupOperation.java index 46453f2bece1..04e3265d4ae6 100644 --- a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/SignalBackupOperation.java +++ b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/SignalBackupOperation.java @@ -20,8 +20,9 @@ import com.hazelcast.nio.serialization.Data; import com.hazelcast.spi.BackupOperation; import com.hazelcast.spi.ObjectNamespace; +import com.hazelcast.spi.impl.MutatingOperation; -public class SignalBackupOperation extends BaseSignalOperation implements BackupOperation { +public class SignalBackupOperation extends BaseSignalOperation implements BackupOperation, MutatingOperation { public SignalBackupOperation() { } diff --git a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/SignalOperation.java b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/SignalOperation.java index 785580c23255..12ebe4d5eb76 100644 --- a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/SignalOperation.java +++ b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/SignalOperation.java @@ -22,8 +22,9 @@ import com.hazelcast.spi.BackupAwareOperation; import com.hazelcast.spi.ObjectNamespace; import com.hazelcast.spi.Operation; +import com.hazelcast.spi.impl.MutatingOperation; -public class SignalOperation extends BaseSignalOperation implements BackupAwareOperation { +public class SignalOperation extends BaseSignalOperation implements BackupAwareOperation, MutatingOperation { public SignalOperation() { } diff --git a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/UnlockBackupOperation.java b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/UnlockBackupOperation.java index fa65be7263f8..8efff143ae9e 100644 --- a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/UnlockBackupOperation.java +++ b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/UnlockBackupOperation.java @@ -23,10 +23,11 @@ import com.hazelcast.nio.serialization.Data; import com.hazelcast.spi.BackupOperation; import com.hazelcast.spi.ObjectNamespace; +import com.hazelcast.spi.impl.MutatingOperation; import java.io.IOException; -public class UnlockBackupOperation extends AbstractLockOperation implements BackupOperation { +public class UnlockBackupOperation extends AbstractLockOperation implements BackupOperation, MutatingOperation { private boolean force; private String originalCallerUuid; diff --git a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/UnlockOperation.java b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/UnlockOperation.java index d2b739457f91..c11c4d8fc921 100644 --- a/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/UnlockOperation.java +++ b/hazelcast/src/main/java/com/hazelcast/concurrent/lock/operations/UnlockOperation.java @@ -26,12 +26,13 @@ import com.hazelcast.spi.ObjectNamespace; import com.hazelcast.spi.Operation; import com.hazelcast.spi.WaitNotifyKey; +import com.hazelcast.spi.impl.MutatingOperation; import java.io.IOException; import static java.lang.Boolean.TRUE; -public class UnlockOperation extends AbstractLockOperation implements Notifier, BackupAwareOperation { +public class UnlockOperation extends AbstractLockOperation implements Notifier, BackupAwareOperation, MutatingOperation { private boolean force; private boolean shouldNotify; diff --git a/hazelcast/src/main/java/com/hazelcast/config/Config.java b/hazelcast/src/main/java/com/hazelcast/config/Config.java index 552cf11c5ca3..8de564459e39 100644 --- a/hazelcast/src/main/java/com/hazelcast/config/Config.java +++ b/hazelcast/src/main/java/com/hazelcast/config/Config.java @@ -78,6 +78,8 @@ public class Config { private final Map queueConfigs = new ConcurrentHashMap(); + private final Map lockConfigs = new ConcurrentHashMap(); + private final Map multiMapConfigs = new ConcurrentHashMap(); private final Map listConfigs = new ConcurrentHashMap(); @@ -386,6 +388,51 @@ public Config setQueueConfigs(Map queueConfigs) { return this; } + public LockConfig findLockConfig(String name) { + final String baseName = getBaseName(name); + final LockConfig config = lookupByPattern(lockConfigs, baseName); + if (config != null) { + return config.getAsReadOnly(); + } + return getLockConfig("default").getAsReadOnly(); + } + + public LockConfig getLockConfig(String name) { + final String baseName = getBaseName(name); + LockConfig config = lookupByPattern(lockConfigs, baseName); + if (config != null) { + return config; + } + LockConfig defConfig = lockConfigs.get("default"); + if (defConfig == null) { + defConfig = new LockConfig(); + defConfig.setName("default"); + addLockConfig(defConfig); + } + config = new LockConfig(defConfig); + config.setName(name); + addLockConfig(config); + return config; + } + + public Config addLockConfig(LockConfig lockConfig) { + lockConfigs.put(lockConfig.getName(), lockConfig); + return this; + } + + public Map getLockConfigs() { + return lockConfigs; + } + + public Config setLockConfigs(Map lockConfigs) { + this.lockConfigs.clear(); + this.lockConfigs.putAll(lockConfigs); + for (Entry entry : lockConfigs.entrySet()) { + entry.getValue().setName(entry.getKey()); + } + return this; + } + public ListConfig findListConfig(String name) { String baseName = getBaseName(name); ListConfig config = lookupByPattern(listConfigs, baseName); diff --git a/hazelcast/src/main/java/com/hazelcast/config/ConfigXmlGenerator.java b/hazelcast/src/main/java/com/hazelcast/config/ConfigXmlGenerator.java index e43a439266b5..71b7442aef83 100644 --- a/hazelcast/src/main/java/com/hazelcast/config/ConfigXmlGenerator.java +++ b/hazelcast/src/main/java/com/hazelcast/config/ConfigXmlGenerator.java @@ -116,6 +116,8 @@ public String generate(Config config) { semaphoreXmlGenerator(xml, config); + lockXmlGenerator(xml, config); + ringbufferXmlGenerator(xml, config); executorXmlGenerator(xml, config); @@ -298,9 +300,11 @@ private void queueXmlGenerator(StringBuilder xml, Config config) { final Collection qCfgs = config.getQueueConfigs().values(); for (QueueConfig q : qCfgs) { xml.append(""); + xml.append("").append(q.isStatisticsEnabled()).append(""); xml.append("").append(q.getMaxSize()).append(""); xml.append("").append(q.getBackupCount()).append(""); xml.append("").append(q.getAsyncBackupCount()).append(""); + xml.append("").append(q.getEmptyQueueTtl()).append(""); if (!q.getItemListenerConfigs().isEmpty()) { xml.append(""); for (ItemListenerConfig lc : q.getItemListenerConfigs()) { @@ -310,19 +314,57 @@ private void queueXmlGenerator(StringBuilder xml, Config config) { } xml.append(""); } + final QueueStoreConfig storeConfig = q.getQueueStoreConfig(); + if (storeConfig != null) { + xml.append(""); + if (storeConfig.getClassName() != null) { + xml.append("").append(storeConfig.getClassName()).append(""); + } + if (storeConfig.getFactoryClassName() != null) { + xml.append("").append(storeConfig.getFactoryClassName()).append(""); + } + appendProperties(xml, storeConfig.getProperties()); + xml.append(""); + } + if (q.getQuorumName() != null) { + xml.append("").append(q.getQuorumName()).append(""); + } xml.append(""); } } + private void lockXmlGenerator(StringBuilder xml, Config config) { + final Collection configs = config.getLockConfigs().values(); + for (LockConfig c : configs) { + xml.append(""); + if (c.getQuorumName() != null) { + xml.append("").append(c.getQuorumName()).append(""); + } + xml.append(""); + } + } + private void ringbufferXmlGenerator(StringBuilder xml, Config config) { final Collection configs = config.getRingbufferConfigs().values(); for (RingbufferConfig rbConfig : configs) { xml.append(""); xml.append("").append(rbConfig.getCapacity()).append(""); + xml.append("").append(rbConfig.getTimeToLiveSeconds()).append(""); xml.append("").append(rbConfig.getBackupCount()).append(""); xml.append("").append(rbConfig.getAsyncBackupCount()).append(""); - xml.append("").append(rbConfig.getTimeToLiveSeconds()).append(""); xml.append("").append(rbConfig.getInMemoryFormat().toString()).append(""); + final RingbufferStoreConfig storeConfig = rbConfig.getRingbufferStoreConfig(); + if (storeConfig != null) { + xml.append(""); + if (storeConfig.getClassName() != null) { + xml.append("").append(storeConfig.getClassName()).append(""); + } + if (storeConfig.getFactoryClassName() != null) { + xml.append("").append(storeConfig.getFactoryClassName()).append(""); + } + appendProperties(xml, storeConfig.getProperties()); + xml.append(""); + } xml.append(""); } } diff --git a/hazelcast/src/main/java/com/hazelcast/config/LockConfig.java b/hazelcast/src/main/java/com/hazelcast/config/LockConfig.java new file mode 100644 index 000000000000..2f9617bb2d17 --- /dev/null +++ b/hazelcast/src/main/java/com/hazelcast/config/LockConfig.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2008-2016, Hazelcast, Inc. All Rights Reserved. + * + * 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 com.hazelcast.config; + +import static com.hazelcast.util.Preconditions.checkHasText; +import static com.hazelcast.util.Preconditions.checkNotNull; + +/** + * Contains the configuration for the {@link com.hazelcast.core.ILock}. + */ +public class LockConfig { + + + private String name; + private String quorumName; + + public LockConfig() { + } + + /** + * Creates a {@link LockConfig} with the provided name. + * + * @param name the name + * @throws NullPointerException if name is null + */ + public LockConfig(String name) { + this.name = checkNotNull(name, "name can't be null"); + } + + /** + * Clones a {@link LockConfig} + * + * @param config the lock config to clone + * @throws NullPointerException if config is null + */ + public LockConfig(LockConfig config) { + checkNotNull(config, "config can't be null"); + this.name = config.name; + this.quorumName = config.quorumName; + } + + /** + * Creates a new {@link LockConfig} by cloning an existing config and overriding the name. + * + * @param name the new name + * @param config the config. + * @throws NullPointerException if name or config is null. + */ + public LockConfig(String name, LockConfig config) { + this(config); + this.name = checkNotNull(name, "name can't be null"); + } + + /** + * Sets the name of the lock. + * + * @param name the name of the lock + * @return the updated {@link LockConfig} + * @throws IllegalArgumentException if name is null or an empty string. + */ + public LockConfig setName(String name) { + this.name = checkHasText(name, "name must contain text"); + return this; + } + + /** + * Returns the name of the lock. + * + * @return the name of the lock. + */ + public String getName() { + return name; + } + + /** + * Returns the quorum name for lock operations. + * + * @return the quorum name + */ + public String getQuorumName() { + return quorumName; + } + + /** + * Sets the quorum name for lock operations. + * + * @param quorumName the quorum name + * @return the updated lock configuration + */ + public LockConfig setQuorumName(String quorumName) { + this.quorumName = quorumName; + return this; + } + + /** + * Creates a readonly copy of this {@link LockConfig}. + * + * @return the readonly copy. + */ + public LockConfig getAsReadOnly() { + return new LockConfigReadonly(this); + } + + + @Override + public String toString() { + return "LockConfig{" + + "name='" + name + '\'' + + ", quorumName='" + quorumName + '\'' + + '}'; + } + + /** + * A readonly version of the {@link LockConfig}. + */ + private static class LockConfigReadonly extends LockConfig { + + LockConfigReadonly(LockConfig config) { + super(config); + } + + @Override + public LockConfig setName(String name) { + throw new UnsupportedOperationException("This config is read-only"); + } + + + } +} diff --git a/hazelcast/src/main/java/com/hazelcast/config/XmlConfigBuilder.java b/hazelcast/src/main/java/com/hazelcast/config/XmlConfigBuilder.java index e978e6ca6a05..b85d64437088 100644 --- a/hazelcast/src/main/java/com/hazelcast/config/XmlConfigBuilder.java +++ b/hazelcast/src/main/java/com/hazelcast/config/XmlConfigBuilder.java @@ -69,6 +69,7 @@ import static com.hazelcast.config.XmlElements.LIST; import static com.hazelcast.config.XmlElements.LISTENERS; import static com.hazelcast.config.XmlElements.LITE_MEMBER; +import static com.hazelcast.config.XmlElements.LOCK; import static com.hazelcast.config.XmlElements.MANAGEMENT_CENTER; import static com.hazelcast.config.XmlElements.MAP; import static com.hazelcast.config.XmlElements.MEMBER_ATTRIBUTES; @@ -314,6 +315,8 @@ private boolean handleXmlNode(Node node, String nodeName) throws Exception { handleJobTracker(node); } else if (SEMAPHORE.isEqual(nodeName)) { handleSemaphore(node); + } else if (LOCK.isEqual(nodeName)) { + handleLock(node); } else if (RINGBUFFER.isEqual(nodeName)) { handleRingbuffer(node); } else if (LISTENERS.isEqual(nodeName)) { @@ -877,6 +880,20 @@ private void handleOutboundPorts(Node child) { } } + private void handleLock(Node node) { + final String name = getAttribute(node, "name"); + final LockConfig lockConfig = new LockConfig(); + lockConfig.setName(name); + for (Node n : childElements(node)) { + final String nodeName = cleanNodeName(n); + final String value = getTextContent(n).trim(); + if ("quorum-ref".equals(nodeName)) { + lockConfig.setQuorumName(value); + } + } + this.config.addLockConfig(lockConfig); + } + private void handleQueue(Node node) { Node attName = node.getAttributes().getNamedItem("name"); String name = getTextContent(attName); diff --git a/hazelcast/src/main/java/com/hazelcast/config/XmlElements.java b/hazelcast/src/main/java/com/hazelcast/config/XmlElements.java index 6382b660cd1f..c07aebcb88b8 100644 --- a/hazelcast/src/main/java/com/hazelcast/config/XmlElements.java +++ b/hazelcast/src/main/java/com/hazelcast/config/XmlElements.java @@ -39,6 +39,7 @@ enum XmlElements { RELIABLE_TOPIC("reliable-topic", true), JOB_TRACKER("jobtracker", true), SEMAPHORE("semaphore", true), + LOCK("lock", true), RINGBUFFER("ringbuffer", true), LISTENERS("listeners", false), SERIALIZATION("serialization", false), diff --git a/hazelcast/src/main/resources/hazelcast-config-3.8.xsd b/hazelcast/src/main/resources/hazelcast-config-3.8.xsd index cf9346d3439c..60ecacd81623 100644 --- a/hazelcast/src/main/resources/hazelcast-config-3.8.xsd +++ b/hazelcast/src/main/resources/hazelcast-config-3.8.xsd @@ -52,6 +52,7 @@ + @@ -1172,6 +1173,23 @@ + + + + + + + + + Name of the lock. + + + + + + + + diff --git a/hazelcast/src/main/resources/hazelcast-full-example.xml b/hazelcast/src/main/resources/hazelcast-full-example.xml index 116f7ca0a52f..37ccdfa51d56 100644 --- a/hazelcast/src/main/resources/hazelcast-full-example.xml +++ b/hazelcast/src/main/resources/hazelcast-full-example.xml @@ -486,7 +486,10 @@ https://hazelcast.org/documentation/. - bulk-load: Size of the bulks loaded from QueueStore when the queue is initialized. Its default value is 250. ---> + * : + Adds the quorum for this queue which you configure using the element. You should set the 's value + as the 's name. +--> true 0 @@ -494,18 +497,19 @@ https://hazelcast.org/documentation/. 0 -1 - - com.hazelcast.examples.ItemListener - + + com.hazelcast.examples.ItemListener + - com.hazelcast.QueueStoreImpl - - false - 1000 - 500 - - + com.hazelcast.QueueStoreImpl + + false + 1000 + 500 + + + quorumRuleWithThreeNodes + + + quorumRuleWithThreeNodes + + - @@ -175,6 +175,7 @@ com.hazelcast.examples.ItemListener + quorumRuleWithThreeMembers