IGNITE-6336 .NET: Thin client: Create cache
authorPavel Tupitsyn <ptupitsyn@apache.org>
Thu, 16 Nov 2017 08:22:46 +0000 (11:22 +0300)
committerPavel Tupitsyn <ptupitsyn@apache.org>
Thu, 16 Nov 2017 08:22:46 +0000 (11:22 +0300)
This closes #2935

35 files changed:
modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientMessageParser.java
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientStatus.java
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheConfigurationSerializer.java [new file with mode: 0644]
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheCreateWithConfigurationRequest.java [new file with mode: 0644]
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheCreateWithNameRequest.java [new file with mode: 0644]
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheDestroyRequest.java [new file with mode: 0644]
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetConfigurationRequest.java [new file with mode: 0644]
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetConfigurationResponse.java [new file with mode: 0644]
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetNamesRequest.java [new file with mode: 0644]
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetNamesResponse.java [new file with mode: 0644]
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetOrCreateWithConfigurationRequest.java [new file with mode: 0644]
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetOrCreateWithNameRequest.java [new file with mode: 0644]
modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs
modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/ClientCacheConfigurationTest.cs [new file with mode: 0644]
modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs [new file with mode: 0644]
modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientTestBase.cs
modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs
modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/CacheClientConfiguration.cs [new file with mode: 0644]
modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/ICacheClient.cs
modules/platforms/dotnet/Apache.Ignite.Core/Client/IIgniteClient.cs
modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderExtensions.cs
modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/ClientCacheConfigurationSerializer.cs [new file with mode: 0644]
modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs
modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientStatus.cs
modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/IgniteClient.cs
modules/platforms/dotnet/examples/Apache.Ignite.Examples/App.config
modules/platforms/dotnet/examples/Apache.Ignite.Examples/ThinClient/ThinClientPutGetExample.cs
modules/platforms/dotnet/examples/Apache.Ignite.Examples/ThinClient/ThinClientQueryExample.cs

index aeb1b2f..7d2730c 100644 (file)
@@ -1711,8 +1711,9 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
      * @return {@code this} for chaining.
      */
     public CacheConfiguration<K, V> setSqlSchema(String sqlSchema) {
-        A.ensure((sqlSchema != null), "Schema could not be null.");
-        A.ensure(!sqlSchema.isEmpty(), "Schema could not be empty.");
+        if (sqlSchema != null) {
+            A.ensure(!sqlSchema.isEmpty(), "Schema could not be empty.");
+        }
 
         this.sqlSchema = sqlSchema;
 
index f0f0f4c..4ad6a90 100644 (file)
@@ -37,11 +37,18 @@ import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheCl
 import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheClearRequest;
 import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheContainsKeyRequest;
 import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheContainsKeysRequest;
+import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheCreateWithConfigurationRequest;
+import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheCreateWithNameRequest;
+import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheDestroyRequest;
 import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheGetAllRequest;
 import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheGetAndPutIfAbsentRequest;
 import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheGetAndPutRequest;
 import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheGetAndRemoveRequest;
 import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheGetAndReplaceRequest;
+import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheGetConfigurationRequest;
+import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheGetNamesRequest;
+import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheGetOrCreateWithConfigurationRequest;
+import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheGetOrCreateWithNameRequest;
 import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheGetRequest;
 import org.apache.ignite.internal.processors.platform.client.cache.ClientCacheGetSizeRequest;
 import org.apache.ignite.internal.processors.platform.client.cache.ClientCachePutAllRequest;
@@ -144,6 +151,27 @@ public class ClientMessageParser implements ClientListenerMessageParser {
     /** */
     private static final short OP_CACHE_REMOVE_ALL = 28;
 
+    /** */
+    private static final short OP_CACHE_CREATE_WITH_NAME = 29;
+
+    /** */
+    private static final short OP_CACHE_GET_OR_CREATE_WITH_NAME = 30;
+
+    /** */
+    private static final short OP_CACHE_DESTROY = 31;
+
+    /** */
+    private static final short OP_CACHE_GET_NAMES = 32;
+
+    /** */
+    private static final short OP_CACHE_GET_CONFIGURATION = 33;
+
+    /** */
+    private static final short OP_CACHE_CREATE_WITH_CONFIGURATION = 34;
+
+    /** */
+    private static final short OP_CACHE_GET_OR_CREATE_WITH_CONFIGURATION = 35;
+
     /** Marshaller. */
     private final GridBinaryMarshaller marsh;
 
@@ -262,6 +290,27 @@ public class ClientMessageParser implements ClientListenerMessageParser {
 
             case OP_CACHE_REMOVE_ALL:
                 return new ClientCacheRemoveAllRequest(reader);
+
+            case OP_CACHE_CREATE_WITH_NAME:
+                return new ClientCacheCreateWithNameRequest(reader);
+
+            case OP_CACHE_GET_OR_CREATE_WITH_NAME:
+                return new ClientCacheGetOrCreateWithNameRequest(reader);
+
+            case OP_CACHE_DESTROY:
+                return new ClientCacheDestroyRequest(reader);
+
+            case OP_CACHE_GET_NAMES:
+                return new ClientCacheGetNamesRequest(reader);
+
+            case OP_CACHE_GET_CONFIGURATION:
+                return new ClientCacheGetConfigurationRequest(reader);
+
+            case OP_CACHE_CREATE_WITH_CONFIGURATION:
+                return new ClientCacheCreateWithConfigurationRequest(reader);
+
+            case OP_CACHE_GET_OR_CREATE_WITH_CONFIGURATION:
+                return new ClientCacheGetOrCreateWithConfigurationRequest(reader);
         }
 
         return new ClientRawRequest(reader.readLong(), ClientStatus.INVALID_OP_CODE,
index 0f374ff..4f55072 100644 (file)
@@ -40,6 +40,9 @@ public final class ClientStatus {
     /** Cache does not exist. */
     public static final int CACHE_DOES_NOT_EXIST = 1000;
 
+    /** Cache already exists. */
+    public static final int CACHE_EXISTS = 1001;
+
     /** Too many cursors. */
     public static final int TOO_MANY_CURSORS = 1010;
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheConfigurationSerializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheConfigurationSerializer.java
new file mode 100644 (file)
index 0000000..0f28b81
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.platform.client.cache;
+
+import org.apache.ignite.binary.BinaryRawReader;
+import org.apache.ignite.binary.BinaryRawWriter;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheKeyConfiguration;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cache.CacheRebalanceMode;
+import org.apache.ignite.cache.CacheWriteSynchronizationMode;
+import org.apache.ignite.cache.PartitionLossPolicy;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.binary.BinaryRawWriterEx;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import static org.apache.ignite.internal.processors.platform.utils.PlatformConfigurationUtils.readQueryEntity;
+import static org.apache.ignite.internal.processors.platform.utils.PlatformConfigurationUtils.writeEnumInt;
+import static org.apache.ignite.internal.processors.platform.utils.PlatformConfigurationUtils.writeQueryEntity;
+
+/**
+ * Cache configuration serializer.
+ */
+public class ClientCacheConfigurationSerializer {
+    /**
+     * Writes the cache configuration.
+     * @param writer Writer.
+     * @param cfg Configuration.
+     */
+    static void write(BinaryRawWriterEx writer, CacheConfiguration cfg) {
+        assert writer != null;
+        assert cfg != null;
+
+        // Reserve for length.
+        int pos = writer.reserveInt();
+
+        writeEnumInt(writer, cfg.getAtomicityMode(), CacheConfiguration.DFLT_CACHE_ATOMICITY_MODE);
+        writer.writeInt(cfg.getBackups());
+        writeEnumInt(writer, cfg.getCacheMode(), CacheConfiguration.DFLT_CACHE_MODE);
+        writer.writeBoolean(cfg.isCopyOnRead());
+        writer.writeString(cfg.getDataRegionName());
+        writer.writeBoolean(cfg.isEagerTtl());
+        writer.writeBoolean(cfg.isStatisticsEnabled());
+        writer.writeString(cfg.getGroupName());
+        writer.writeBoolean(cfg.isInvalidate());
+        writer.writeLong(cfg.getDefaultLockTimeout());
+        writer.writeInt(cfg.getMaxConcurrentAsyncOperations());
+        writer.writeInt(cfg.getMaxQueryIteratorsCount());
+        writer.writeString(cfg.getName());
+        writer.writeBoolean(cfg.isOnheapCacheEnabled());
+        writer.writeInt(cfg.getPartitionLossPolicy().ordinal());
+        writer.writeInt(cfg.getQueryDetailMetricsSize());
+        writer.writeInt(cfg.getQueryParallelism());
+        writer.writeBoolean(cfg.isReadFromBackup());
+        writer.writeInt(cfg.getRebalanceBatchSize());
+        writer.writeLong(cfg.getRebalanceBatchesPrefetchCount());
+        writer.writeLong(cfg.getRebalanceDelay());
+        writeEnumInt(writer, cfg.getRebalanceMode(), CacheConfiguration.DFLT_REBALANCE_MODE);
+        writer.writeInt(cfg.getRebalanceOrder());
+        writer.writeLong(cfg.getRebalanceThrottle());
+        writer.writeLong(cfg.getRebalanceTimeout());
+        writer.writeBoolean(cfg.isSqlEscapeAll());
+        writer.writeInt(cfg.getSqlIndexMaxInlineSize());
+        writer.writeString(cfg.getSqlSchema());
+        writeEnumInt(writer, cfg.getWriteSynchronizationMode());
+
+        CacheKeyConfiguration[] keys = cfg.getKeyConfiguration();
+
+        if (keys != null) {
+            writer.writeInt(keys.length);
+
+            for (CacheKeyConfiguration key : keys) {
+                writer.writeString(key.getTypeName());
+                writer.writeString(key.getAffinityKeyFieldName());
+            }
+        } else {
+            writer.writeInt(0);
+        }
+
+        //noinspection unchecked
+        Collection<QueryEntity> qryEntities = cfg.getQueryEntities();
+
+        if (qryEntities != null) {
+            writer.writeInt(qryEntities.size());
+
+            for (QueryEntity e : qryEntities)
+                writeQueryEntity(writer, e);
+        } else
+            writer.writeInt(0);
+
+        // Write length (so that part of the config can be skipped).
+        writer.writeInt(pos, writer.out().position() - pos - 4);
+    }
+
+    /**
+     * Reads the cache configuration.
+     *
+     * @param reader Reader.
+     * @return Configuration.
+     */
+    static CacheConfiguration read(BinaryRawReader reader) {
+        reader.readInt();  // Skip length.
+
+        CacheConfiguration cfg = new CacheConfiguration()
+                .setAtomicityMode(CacheAtomicityMode.fromOrdinal(reader.readInt()))
+                .setBackups(reader.readInt())
+                .setCacheMode(CacheMode.fromOrdinal(reader.readInt()))
+                .setCopyOnRead(reader.readBoolean())
+                .setDataRegionName(reader.readString())
+                .setEagerTtl(reader.readBoolean())
+                .setStatisticsEnabled(reader.readBoolean())
+                .setGroupName(reader.readString())
+                .setInvalidate(reader.readBoolean())
+                .setDefaultLockTimeout(reader.readLong())
+                .setMaxConcurrentAsyncOperations(reader.readInt())
+                .setMaxQueryIteratorsCount(reader.readInt())
+                .setName(reader.readString())
+                .setOnheapCacheEnabled(reader.readBoolean())
+                .setPartitionLossPolicy(PartitionLossPolicy.fromOrdinal((byte)reader.readInt()))
+                .setQueryDetailMetricsSize(reader.readInt())
+                .setQueryParallelism(reader.readInt())
+                .setReadFromBackup(reader.readBoolean())
+                .setRebalanceBatchSize(reader.readInt())
+                .setRebalanceBatchesPrefetchCount(reader.readLong())
+                .setRebalanceDelay(reader.readLong())
+                .setRebalanceMode(CacheRebalanceMode.fromOrdinal(reader.readInt()))
+                .setRebalanceOrder(reader.readInt())
+                .setRebalanceThrottle(reader.readLong())
+                .setRebalanceTimeout(reader.readLong())
+                .setSqlEscapeAll(reader.readBoolean())
+                .setSqlIndexMaxInlineSize(reader.readInt())
+                .setSqlSchema(reader.readString())
+                .setWriteSynchronizationMode(CacheWriteSynchronizationMode.fromOrdinal(reader.readInt()));
+
+        // Key configuration.
+        int keyCnt = reader.readInt();
+
+        if (keyCnt > 0) {
+            CacheKeyConfiguration[] keys = new CacheKeyConfiguration[keyCnt];
+
+            for (int i = 0; i < keyCnt; i++) {
+                keys[i] = new CacheKeyConfiguration(reader.readString(), reader.readString());
+            }
+
+            cfg.setKeyConfiguration(keys);
+        }
+
+        // Query entities.
+        int qryEntCnt = reader.readInt();
+
+        if (qryEntCnt > 0) {
+            Collection<QueryEntity> entities = new ArrayList<>(qryEntCnt);
+
+            for (int i = 0; i < qryEntCnt; i++)
+                entities.add(readQueryEntity(reader));
+
+            cfg.setQueryEntities(entities);
+        }
+
+        return cfg;
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheCreateWithConfigurationRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheCreateWithConfigurationRequest.java
new file mode 100644 (file)
index 0000000..4b4dcec
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.platform.client.cache;
+
+import org.apache.ignite.binary.BinaryRawReader;
+import org.apache.ignite.cache.CacheExistsException;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.processors.platform.client.ClientConnectionContext;
+import org.apache.ignite.internal.processors.platform.client.ClientRequest;
+import org.apache.ignite.internal.processors.platform.client.ClientResponse;
+import org.apache.ignite.internal.processors.platform.client.ClientStatus;
+import org.apache.ignite.internal.processors.platform.client.IgniteClientException;
+
+/**
+ * Cache create with configuration request.
+ */
+@SuppressWarnings("unchecked")
+public class ClientCacheCreateWithConfigurationRequest extends ClientRequest {
+    /** Cache configuration. */
+    private final CacheConfiguration cacheCfg;
+
+    /**
+     * Constructor.
+     *
+     * @param reader Reader.
+     */
+    public ClientCacheCreateWithConfigurationRequest(BinaryRawReader reader) {
+        super(reader);
+
+        cacheCfg = ClientCacheConfigurationSerializer.read(reader);
+    }
+
+    /** {@inheritDoc} */
+    @Override public ClientResponse process(ClientConnectionContext ctx) {
+        try {
+            ctx.kernalContext().grid().createCache(cacheCfg);
+        } catch (CacheExistsException e) {
+            throw new IgniteClientException(ClientStatus.CACHE_EXISTS, e.getMessage());
+        }
+
+        return super.process(ctx);
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheCreateWithNameRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheCreateWithNameRequest.java
new file mode 100644 (file)
index 0000000..9155d76
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.platform.client.cache;
+
+import org.apache.ignite.binary.BinaryRawReader;
+import org.apache.ignite.cache.CacheExistsException;
+import org.apache.ignite.internal.processors.platform.client.ClientConnectionContext;
+import org.apache.ignite.internal.processors.platform.client.ClientRequest;
+import org.apache.ignite.internal.processors.platform.client.ClientResponse;
+import org.apache.ignite.internal.processors.platform.client.ClientStatus;
+import org.apache.ignite.internal.processors.platform.client.IgniteClientException;
+
+/**
+ * Cache create with name request.
+ */
+public class ClientCacheCreateWithNameRequest extends ClientRequest {
+    /** Cache name. */
+    private final String cacheName;
+
+    /**
+     * Constructor.
+     *
+     * @param reader Reader.
+     */
+    public ClientCacheCreateWithNameRequest(BinaryRawReader reader) {
+        super(reader);
+
+        cacheName = reader.readString();
+    }
+
+    /** {@inheritDoc} */
+    @Override public ClientResponse process(ClientConnectionContext ctx) {
+        try {
+            ctx.kernalContext().grid().createCache(cacheName);
+        } catch (CacheExistsException e) {
+            throw new IgniteClientException(ClientStatus.CACHE_EXISTS, e.getMessage());
+        }
+
+        return super.process(ctx);
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheDestroyRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheDestroyRequest.java
new file mode 100644 (file)
index 0000000..032116d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.platform.client.cache;
+
+import org.apache.ignite.binary.BinaryRawReader;
+import org.apache.ignite.internal.processors.platform.client.ClientConnectionContext;
+import org.apache.ignite.internal.processors.platform.client.ClientRequest;
+import org.apache.ignite.internal.processors.platform.client.ClientResponse;
+
+/**
+ * Cache destroy request.
+ */
+public class ClientCacheDestroyRequest extends ClientRequest {
+    /** Cache name. */
+    private final String cacheName;
+
+    /**
+     * Constructor.
+     *
+     * @param reader Reader.
+     */
+    public ClientCacheDestroyRequest(BinaryRawReader reader) {
+        super(reader);
+
+        cacheName = reader.readString();
+    }
+
+    /** {@inheritDoc} */
+    @Override public ClientResponse process(ClientConnectionContext ctx) {
+        ctx.kernalContext().grid().destroyCache(cacheName);
+
+        return super.process(ctx);
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetConfigurationRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetConfigurationRequest.java
new file mode 100644 (file)
index 0000000..3632095
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.platform.client.cache;
+
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.binary.BinaryRawReader;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.processors.platform.client.ClientConnectionContext;
+import org.apache.ignite.internal.processors.platform.client.ClientResponse;
+
+/**
+ * Cache configuration request.
+ */
+public class ClientCacheGetConfigurationRequest extends ClientCacheRequest {
+    /**
+     * Constructor.
+     *
+     * @param reader Reader.
+     */
+    public ClientCacheGetConfigurationRequest(BinaryRawReader reader) {
+        super(reader);
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Override public ClientResponse process(ClientConnectionContext ctx) {
+        CacheConfiguration cfg = ((IgniteCache<Object, Object>) rawCache(ctx))
+                .getConfiguration(CacheConfiguration.class);
+
+        return new ClientCacheGetConfigurationResponse(requestId(), cfg);
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetConfigurationResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetConfigurationResponse.java
new file mode 100644 (file)
index 0000000..2033dfe
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.platform.client.cache;
+
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.binary.BinaryRawWriterEx;
+import org.apache.ignite.internal.processors.platform.client.ClientResponse;
+
+/**
+ * Cache configuration response.
+ */
+public class ClientCacheGetConfigurationResponse extends ClientResponse {
+    /** Cache configuration. */
+    private final CacheConfiguration cfg;
+
+    /**
+     * Constructor.
+     *
+     * @param reqId Request id.
+     * @param cfg Cache configuration.
+     */
+    ClientCacheGetConfigurationResponse(long reqId, CacheConfiguration cfg) {
+        super(reqId);
+
+        assert cfg != null;
+
+        this.cfg = cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void encode(BinaryRawWriterEx writer) {
+        super.encode(writer);
+
+        ClientCacheConfigurationSerializer.write(writer, cfg);
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetNamesRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetNamesRequest.java
new file mode 100644 (file)
index 0000000..376fcc1
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.platform.client.cache;
+
+import org.apache.ignite.binary.BinaryRawReader;
+import org.apache.ignite.internal.processors.platform.client.ClientConnectionContext;
+import org.apache.ignite.internal.processors.platform.client.ClientRequest;
+import org.apache.ignite.internal.processors.platform.client.ClientResponse;
+
+import java.util.Collection;
+
+/**
+ * Cache names request.
+ */
+public class ClientCacheGetNamesRequest extends ClientRequest {
+    /**
+     * Constructor.
+     *
+     * @param reader Reader.
+     */
+    public ClientCacheGetNamesRequest(BinaryRawReader reader) {
+        super(reader);
+    }
+
+    /** {@inheritDoc} */
+    @Override public ClientResponse process(ClientConnectionContext ctx) {
+        Collection<String> names = ctx.kernalContext().grid().cacheNames();
+
+        return new ClientCacheGetNamesResponse(requestId(), names);
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetNamesResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetNamesResponse.java
new file mode 100644 (file)
index 0000000..6266515
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.platform.client.cache;
+
+import org.apache.ignite.internal.binary.BinaryRawWriterEx;
+import org.apache.ignite.internal.processors.platform.client.ClientResponse;
+
+import java.util.Collection;
+
+/**
+ * Cache names response.
+ */
+public class ClientCacheGetNamesResponse extends ClientResponse {
+    /** Cache names. */
+    private final Collection<String> cacheNames;
+
+    /**
+     * Constructor.
+     *
+     * @param reqId Request id.
+     * @param cacheNames Cache names.
+     */
+    ClientCacheGetNamesResponse(long reqId, Collection<String> cacheNames) {
+        super(reqId);
+
+        assert cacheNames != null;
+
+        this.cacheNames = cacheNames;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void encode(BinaryRawWriterEx writer) {
+        super.encode(writer);
+
+        writer.writeInt(cacheNames.size());
+
+        for (String name : cacheNames) {
+            writer.writeString(name);
+        }
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetOrCreateWithConfigurationRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetOrCreateWithConfigurationRequest.java
new file mode 100644 (file)
index 0000000..267318a
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.platform.client.cache;
+
+import org.apache.ignite.binary.BinaryRawReader;
+import org.apache.ignite.cache.CacheExistsException;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.processors.platform.client.ClientConnectionContext;
+import org.apache.ignite.internal.processors.platform.client.ClientRequest;
+import org.apache.ignite.internal.processors.platform.client.ClientResponse;
+import org.apache.ignite.internal.processors.platform.client.ClientStatus;
+import org.apache.ignite.internal.processors.platform.client.IgniteClientException;
+
+/**
+ * Cache get or create with configuration request.
+ */
+@SuppressWarnings("unchecked")
+public class ClientCacheGetOrCreateWithConfigurationRequest extends ClientRequest {
+    /** Cache configuration. */
+    private final CacheConfiguration cacheCfg;
+
+    /**
+     * Constructor.
+     *
+     * @param reader Reader.
+     */
+    public ClientCacheGetOrCreateWithConfigurationRequest(BinaryRawReader reader) {
+        super(reader);
+
+        cacheCfg = ClientCacheConfigurationSerializer.read(reader);
+    }
+
+    /** {@inheritDoc} */
+    @Override public ClientResponse process(ClientConnectionContext ctx) {
+        try {
+            ctx.kernalContext().grid().getOrCreateCache(cacheCfg);
+        } catch (CacheExistsException e) {
+            throw new IgniteClientException(ClientStatus.CACHE_EXISTS, e.getMessage());
+        }
+
+        return super.process(ctx);
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetOrCreateWithNameRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/cache/ClientCacheGetOrCreateWithNameRequest.java
new file mode 100644 (file)
index 0000000..94dd115
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.platform.client.cache;
+
+import org.apache.ignite.binary.BinaryRawReader;
+import org.apache.ignite.internal.processors.platform.client.ClientConnectionContext;
+import org.apache.ignite.internal.processors.platform.client.ClientRequest;
+import org.apache.ignite.internal.processors.platform.client.ClientResponse;
+
+/**
+ * Cache create with name request.
+ */
+public class ClientCacheGetOrCreateWithNameRequest extends ClientRequest {
+    /** Cache name. */
+    private final String cacheName;
+
+    /**
+     * Constructor.
+     *
+     * @param reader Reader.
+     */
+    public ClientCacheGetOrCreateWithNameRequest(BinaryRawReader reader) {
+        super(reader);
+
+        cacheName = reader.readString();
+    }
+
+    /** {@inheritDoc} */
+    @Override public ClientResponse process(ClientConnectionContext ctx) {
+        ctx.kernalContext().grid().getOrCreateCache(cacheName);
+
+        return super.process(ctx);
+    }
+}
index c1a807c..a8df0c6 100644 (file)
@@ -209,11 +209,7 @@ public class PlatformConfigurationUtils {
         ccfg.setMaxQueryIteratorsCount(in.readInt());
         ccfg.setQueryDetailMetricsSize(in.readInt());
         ccfg.setQueryParallelism(in.readInt());
-
-        String sqlSchema = in.readString();
-        if (sqlSchema != null) {
-            ccfg.setSqlSchema(sqlSchema);
-        }
+        ccfg.setSqlSchema(in.readString());
 
         int qryEntCnt = in.readInt();
 
@@ -480,12 +476,14 @@ public class PlatformConfigurationUtils {
      * @param in Stream.
      * @return QueryEntity.
      */
-    private static QueryEntity readQueryEntity(BinaryRawReader in) {
+    public static QueryEntity readQueryEntity(BinaryRawReader in) {
         QueryEntity res = new QueryEntity();
 
         res.setKeyType(in.readString());
         res.setValueType(in.readString());
         res.setTableName(in.readString());
+        res.setKeyFieldName(in.readString());
+        res.setValueFieldName(in.readString());
 
         // Fields
         int cnt = in.readInt();
@@ -541,9 +539,6 @@ public class PlatformConfigurationUtils {
             res.setIndexes(indexes);
         }
 
-        res.setKeyFieldName(in.readString());
-        res.setValueFieldName(in.readString());
-
         return res;
     }
 
@@ -988,12 +983,14 @@ public class PlatformConfigurationUtils {
      * @param writer Writer.
      * @param queryEntity Query entity.
      */
-    private static void writeQueryEntity(BinaryRawWriter writer, QueryEntity queryEntity) {
+    public static void writeQueryEntity(BinaryRawWriter writer, QueryEntity queryEntity) {
         assert queryEntity != null;
 
         writer.writeString(queryEntity.getKeyType());
         writer.writeString(queryEntity.getValueType());
         writer.writeString(queryEntity.getTableName());
+        writer.writeString(queryEntity.getKeyFieldName());
+        writer.writeString(queryEntity.getValueFieldName());
 
         // Fields
         LinkedHashMap<String, String> fields = queryEntity.getFields();
@@ -1039,9 +1036,6 @@ public class PlatformConfigurationUtils {
         }
         else
             writer.writeInt(0);
-
-        writer.writeString(queryEntity.getKeyFieldName());
-        writer.writeString(queryEntity.getValueFieldName());
     }
 
     /**
@@ -1343,7 +1337,7 @@ public class PlatformConfigurationUtils {
      * @param w Writer.
      * @param e Enum.
      */
-    private static void writeEnumInt(BinaryRawWriter w, Enum e) {
+    public static void writeEnumInt(BinaryRawWriter w, Enum e) {
         w.writeInt(e == null ? 0 : e.ordinal());
     }
 
@@ -1353,7 +1347,7 @@ public class PlatformConfigurationUtils {
      * @param w Writer.
      * @param e Enum.
      */
-    private static void writeEnumInt(BinaryRawWriter w, Enum e, Enum def) {
+    public static void writeEnumInt(BinaryRawWriter w, Enum e, Enum def) {
         assert def != null;
 
         w.writeInt(e == null ? def.ordinal() : e.ordinal());
index 2ef6db1..2e34ba2 100644 (file)
     <Compile Include="Cache\Store\CacheStoreSessionTestSharedFactory.cs" />
     <Compile Include="Client\Cache\CacheTest.cs" />
     <Compile Include="Client\Cache\CacheTestNoMeta.cs" />
+    <Compile Include="Client\Cache\ClientCacheConfigurationTest.cs" />
     <Compile Include="Client\Cache\EmptyObject.cs" />
+    <Compile Include="Client\Cache\CreateCacheTest.cs" />
     <Compile Include="Client\Cache\ScanQueryTest.cs" />
     <Compile Include="Client\Cache\Person.cs" />
     <Compile Include="Client\ClientTestBase.cs" />
index 9593777..63f5cd8 100644 (file)
@@ -578,7 +578,7 @@ namespace Apache.Ignite.Core.Tests.Cache
         /// <summary>
         /// Gets the custom cache configuration.
         /// </summary>
-        private static CacheConfiguration GetCustomCacheConfiguration(string name = null)
+        public static CacheConfiguration GetCustomCacheConfiguration(string name = null)
         {
             return new CacheConfiguration
             {
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/ClientCacheConfigurationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/ClientCacheConfigurationTest.cs
new file mode 100644 (file)
index 0000000..381f924
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+namespace Apache.Ignite.Core.Tests.Client.Cache
+{
+    using System;
+    using System.IO;
+    using System.Linq;
+    using Apache.Ignite.Core.Cache.Configuration;
+    using Apache.Ignite.Core.Client.Cache;
+    using Apache.Ignite.Core.Impl.Binary.IO;
+    using Apache.Ignite.Core.Impl.Client.Cache;
+    using Apache.Ignite.Core.Tests.Cache;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests client cache configuration handling.
+    /// </summary>
+    public class ClientCacheConfigurationTest
+    {
+        /// <summary>
+        /// Tests the serialization/deserialization of <see cref="CacheConfiguration"/>.
+        /// </summary>
+        [Test]
+        public void TestSerializeDeserialize()
+        {
+            // Empty.
+            TestSerializeDeserialize(new CacheConfiguration("foo"));
+
+            // Full config: has unsupported properties.
+            var cfg = CacheConfigurationTest.GetCustomCacheConfiguration("bar");
+            cfg.ReadThrough = true;
+            cfg.WriteBehindEnabled = true;
+            
+            TestSerializeDeserializeUnspported(cfg, "AffinityFunction");
+            cfg.AffinityFunction = null;
+
+            TestSerializeDeserializeUnspported(cfg, "EvictionPolicy");
+            cfg.EvictionPolicy = null;
+
+            TestSerializeDeserializeUnspported(cfg, "ExpiryPolicyFactory");
+            cfg.ExpiryPolicyFactory = null;
+
+            TestSerializeDeserializeUnspported(cfg, "PluginConfigurations");
+            cfg.PluginConfigurations = null;
+
+            TestSerializeDeserializeUnspported(cfg, "CacheStoreFactory");
+            cfg.CacheStoreFactory = null;
+
+            TestSerializeDeserializeUnspported(cfg, "NearConfiguration");
+            cfg.NearConfiguration = null;
+
+            // Store-specific properties.
+            TestSerializeDeserializeUnspported(cfg, "KeepBinaryInStore");
+            cfg.KeepBinaryInStore = false;
+
+            TestSerializeDeserializeUnspported(cfg, "LoadPreviousValue");
+            cfg.LoadPreviousValue = false;
+
+            TestSerializeDeserializeUnspported(cfg, "ReadThrough");
+            cfg.ReadThrough = false;
+
+            TestSerializeDeserializeUnspported(cfg, "WriteThrough");
+            cfg.WriteThrough = false;
+
+            TestSerializeDeserializeUnspported(cfg, "StoreConcurrentLoadAllThreshold");
+            cfg.StoreConcurrentLoadAllThreshold = CacheConfiguration.DefaultStoreConcurrentLoadAllThreshold;
+
+            TestSerializeDeserializeUnspported(cfg, "WriteBehindBatchSize");
+            cfg.WriteBehindBatchSize = CacheConfiguration.DefaultWriteBehindBatchSize;
+
+            TestSerializeDeserializeUnspported(cfg, "WriteBehindCoalescing");
+            cfg.WriteBehindCoalescing = CacheConfiguration.DefaultWriteBehindCoalescing;
+
+            TestSerializeDeserializeUnspported(cfg, "WriteBehindEnabled");
+            cfg.WriteBehindEnabled = CacheConfiguration.DefaultWriteBehindEnabled;
+
+            TestSerializeDeserializeUnspported(cfg, "WriteBehindFlushFrequency");
+            cfg.WriteBehindFlushFrequency = CacheConfiguration.DefaultWriteBehindFlushFrequency;
+
+            TestSerializeDeserializeUnspported(cfg, "WriteBehindFlushSize");
+            cfg.WriteBehindFlushSize = CacheConfiguration.DefaultWriteBehindFlushSize;
+
+            TestSerializeDeserializeUnspported(cfg, "WriteBehindFlushThreadCount");
+            cfg.WriteBehindFlushThreadCount = CacheConfiguration.DefaultWriteBehindFlushThreadCount;
+
+            // Full config without unsupported properties.
+            TestSerializeDeserialize(cfg);
+        }
+
+        /// <summary>
+        /// Tests <see cref="CacheConfiguration"/> to <see cref="CacheClientConfiguration"/> and reverse conversion.
+        /// </summary>
+        [Test]
+        public void TestConfigConversion()
+        {
+            // Copy ctor.
+            var clientCfg = new CacheClientConfiguration(
+                CacheConfigurationTest.GetCustomCacheConfiguration("z"), true);
+
+            AssertClientConfigsAreEqual(clientCfg, new CacheClientConfiguration(clientCfg));
+
+            // Convert to server cfg.
+            var serverCfg = clientCfg.ToCacheConfiguration();
+            AssertClientConfigsAreEqual(clientCfg, new CacheClientConfiguration(serverCfg, false));
+        }
+
+        /// <summary>
+        /// Tests the constructors.
+        /// </summary>
+        [Test]
+        public void TestConstructors()
+        {
+            // Default property values.
+            var clientCfg = new CacheClientConfiguration();
+            var defCfg = new CacheClientConfiguration(new CacheConfiguration(), false);
+
+            AssertClientConfigsAreEqual(defCfg, clientCfg);
+
+            // Name.
+            clientCfg = new CacheClientConfiguration("foo");
+            Assert.AreEqual("foo", clientCfg.Name);
+
+            clientCfg.Name = null;
+            AssertClientConfigsAreEqual(defCfg, clientCfg);
+
+            // Query entities.
+            clientCfg = new CacheClientConfiguration("bar", typeof(QueryPerson));
+            Assert.AreEqual("bar", clientCfg.Name);
+            var qe = clientCfg.QueryEntities.Single();
+            Assert.AreEqual(typeof(QueryPerson), qe.ValueType);
+            Assert.AreEqual("Name", qe.Fields.Single().Name);
+
+            clientCfg = new CacheClientConfiguration("baz", new QueryEntity(typeof(QueryPerson)));
+            qe = clientCfg.QueryEntities.Single();
+            Assert.AreEqual(typeof(QueryPerson), qe.ValueType);
+            Assert.AreEqual("Name", qe.Fields.Single().Name);
+        }
+
+        /// <summary>
+        /// Tests the serialization/deserialization of <see cref="CacheConfiguration"/>.
+        /// </summary>
+        private static void TestSerializeDeserializeUnspported(CacheConfiguration cfg, string propName)
+        {
+            var ex = Assert.Throws<NotSupportedException>(() => TestSerializeDeserialize(cfg));
+            Assert.AreEqual(string.Format("{0}.{1} property is not supported in thin client mode.",
+                typeof(CacheConfiguration).Name, propName), ex.Message);
+        }
+
+        /// <summary>
+        /// Tests the serialization/deserialization of <see cref="CacheConfiguration"/>.
+        /// </summary>
+        private static void TestSerializeDeserialize(CacheConfiguration cfg)
+        {
+            var clientCfg = new CacheClientConfiguration(cfg, false);
+
+            AssertClientConfigsAreEqual(clientCfg, SerializeDeserialize(clientCfg));
+        }
+
+        /// <summary>
+        /// Asserts the client configs are equal.
+        /// </summary>
+        public static void AssertClientConfigsAreEqual(CacheClientConfiguration cfg, CacheClientConfiguration cfg2)
+        {
+            if (cfg2.QueryEntities != null)
+            {
+                // Remove identical aliases which are added during config roundtrip.
+                foreach (var e in cfg2.QueryEntities)
+                {
+                    e.Aliases = e.Aliases.Where(x => x.Alias != x.FullName).ToArray();
+                }
+            }
+
+            TestUtils.AssertReflectionEqual(cfg, cfg2);
+        }
+
+        /// <summary>
+        /// Serializes and deserializes the config.
+        /// </summary>
+        private static CacheClientConfiguration SerializeDeserialize(CacheClientConfiguration cfg)
+        {
+            using (var stream = new BinaryHeapStream(128))
+            {
+                ClientCacheConfigurationSerializer.Write(stream, cfg);
+                stream.Seek(0, SeekOrigin.Begin);
+                return new CacheClientConfiguration(stream);
+            }
+        }
+
+        private class QueryPerson
+        {
+            [QuerySqlField]
+            // ReSharper disable once UnusedMember.Local
+            public string Name { get; set; }
+        }
+    }
+}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs
new file mode 100644 (file)
index 0000000..c92fbac
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+namespace Apache.Ignite.Core.Tests.Client.Cache
+{
+    using System.Linq;
+    using Apache.Ignite.Core.Cache.Configuration;
+    using Apache.Ignite.Core.Client;
+    using Apache.Ignite.Core.Client.Cache;
+    using Apache.Ignite.Core.Configuration;
+    using Apache.Ignite.Core.Impl.Client;
+    using Apache.Ignite.Core.Tests.Cache;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests dynamic cache start from client nodes.
+    /// </summary>
+    public class CreateCacheTest : ClientTestBase
+    {
+        /** Template cache name. */
+        private const string TemplateCacheName = "template-cache-*";
+
+        /// <summary>
+        /// Tears down the test.
+        /// </summary>
+        [TearDown]
+        public void TearDown()
+        {
+            DestroyCaches();
+        }
+
+        /// <summary>
+        /// Destroys caches.
+        /// </summary>
+        private void DestroyCaches()
+        {
+            foreach (var cacheName in Client.GetCacheNames())
+            {
+                Client.DestroyCache(cacheName);
+            }
+        }
+
+        /// <summary>
+        /// Tests the GetCacheNames.
+        /// </summary>
+        [Test]
+        public void TestGetCacheNames()
+        {
+            DestroyCaches();
+            Assert.AreEqual(0, Client.GetCacheNames().Count);
+
+            Client.CreateCache<int, int>("a");
+            Assert.AreEqual("a", Client.GetCacheNames().Single());
+
+            Client.CreateCache<int, int>("b");
+            Assert.AreEqual(new[] {"a", "b"}, Client.GetCacheNames().OrderBy(x => x).ToArray());
+
+            Client.DestroyCache("a");
+            Assert.AreEqual("b", Client.GetCacheNames().Single());
+        }
+
+        /// <summary>
+        /// Tests create from template.
+        /// </summary>
+        [Test]
+        public void TestCreateFromTemplate()
+        {
+            // No template: default configuration.
+            var cache = Client.CreateCache<int, int>("foobar");
+            TestUtils.AssertReflectionEqual(new CacheClientConfiguration("foobar"), cache.GetConfiguration());
+
+            // Create when exists.
+            var ex = Assert.Throws<IgniteClientException>(() => Client.CreateCache<int, int>(cache.Name));
+            Assert.AreEqual(
+                "Failed to start cache (a cache with the same name is already started): foobar", ex.Message);
+            Assert.AreEqual((int) ClientStatus.CacheExists, ex.ErrorCode);
+
+            // Template: custom configuration.
+            cache = Client.CreateCache<int, int>(TemplateCacheName.Replace("*", "1"));
+            var cfg = cache.GetConfiguration();
+            Assert.AreEqual(CacheAtomicityMode.Transactional, cfg.AtomicityMode);
+            Assert.AreEqual(3, cfg.Backups);
+            Assert.AreEqual(CacheMode.Partitioned, cfg.CacheMode);
+        }
+
+        /// <summary>
+        /// Tests getOrCreate from template.
+        /// </summary>
+        [Test]
+        public void TestGetOrCreateFromTemplate()
+        {
+            // No template: default configuration.
+            var cache = Client.GetOrCreateCache<int, int>("foobar");
+            TestUtils.AssertReflectionEqual(new CacheClientConfiguration { Name = "foobar"}, cache.GetConfiguration());
+            cache[1] = 1;
+
+            // Create when exists.
+            cache = Client.GetOrCreateCache<int, int>("foobar");
+            Assert.AreEqual(1, cache[1]);
+
+            // Template: custom configuration.
+            cache = Client.GetOrCreateCache<int, int>(TemplateCacheName.Replace("*", "1"));
+            var cfg = cache.GetConfiguration();
+            Assert.AreEqual(CacheAtomicityMode.Transactional, cfg.AtomicityMode);
+            Assert.AreEqual(3, cfg.Backups);
+            Assert.AreEqual(CacheMode.Partitioned, cfg.CacheMode);
+
+            // Create when exists.
+            cache[1] = 1;
+            cache = Client.GetOrCreateCache<int, int>(cache.Name);
+            Assert.AreEqual(1, cache[1]);
+        }
+
+        /// <summary>
+        /// Tests cache creation from configuration.
+        /// </summary>
+        [Test]
+        public void TestCreateFromConfiguration()
+        {
+            // Default config.
+            var cfg = new CacheClientConfiguration("a");
+            var cache = Client.CreateCache<int, int>(cfg);
+            TestUtils.AssertReflectionEqual(cfg, cache.GetConfiguration());
+
+            // Create when exists.
+            var ex = Assert.Throws<IgniteClientException>(() => Client.CreateCache<int, int>(cfg));
+            Assert.AreEqual(
+                "Failed to start cache (a cache with the same name is already started): a", ex.Message);
+            Assert.AreEqual((int) ClientStatus.CacheExists, ex.ErrorCode);
+
+            // Custom config.
+            cfg = GetFullCacheConfiguration("b");
+
+            cache = Client.CreateCache<int, int>(cfg);
+            ClientCacheConfigurationTest.AssertClientConfigsAreEqual(cfg, cache.GetConfiguration());
+        }
+
+        /// <summary>
+        /// Tests cache creation from configuration.
+        /// </summary>
+        [Test]
+        public void TestGetOrCreateFromConfiguration()
+        {
+            // Default configur.
+            var cfg = new CacheClientConfiguration("a");
+            var cache = Client.GetOrCreateCache<int, int>(cfg);
+            TestUtils.AssertReflectionEqual(cfg, cache.GetConfiguration());
+            cache[1] = 1;
+
+            // Create when exists.
+            cache = Client.GetOrCreateCache<int, int>("a");
+            Assert.AreEqual(1, cache[1]);
+
+            // Custom config.
+            cfg = GetFullCacheConfiguration("b");
+
+            cache = Client.GetOrCreateCache<int, int>(cfg);
+            ClientCacheConfigurationTest.AssertClientConfigsAreEqual(cfg, cache.GetConfiguration());
+        }
+
+        /// <summary>
+        /// Gets the full cache configuration.
+        /// </summary>
+        private static CacheClientConfiguration GetFullCacheConfiguration(string name)
+        {
+            return new CacheClientConfiguration(CacheConfigurationTest.GetCustomCacheConfiguration(name), true);
+        }
+
+        /** <inheritdoc /> */
+        protected override IgniteConfiguration GetIgniteConfiguration()
+        {
+            return new IgniteConfiguration(base.GetIgniteConfiguration())
+            {
+                CacheConfiguration = new[]
+                {
+                    new CacheConfiguration(TemplateCacheName)
+                    {
+                        AtomicityMode = CacheAtomicityMode.Transactional,
+                        Backups = 3
+                    }
+                },
+                DataStorageConfiguration = new DataStorageConfiguration
+                {
+                    DataRegionConfigurations = new[]
+                    {
+                        new DataRegionConfiguration
+                        {
+                            Name = "myMemPolicy"
+                        } 
+                    }
+                }
+            };
+        }
+    }
+}
index 408eb73..9b7a566 100644 (file)
@@ -64,6 +64,8 @@ namespace Apache.Ignite.Core.Tests.Client
             {
                 Ignition.Start(cfg);
             }
+
+            Client = GetClient();
         }
 
         /// <summary>
@@ -85,6 +87,11 @@ namespace Apache.Ignite.Core.Tests.Client
         }
 
         /// <summary>
+        /// Gets the client.
+        /// </summary>
+        public IIgniteClient Client { get; set; }
+
+        /// <summary>
         /// Gets the cache.
         /// </summary>
         protected static ICache<int, T> GetCache<T>()
index 6e09704..98c3f11 100644 (file)
@@ -27,6 +27,7 @@ namespace Apache.Ignite.Core.Tests
     using Apache.Ignite.Core.Cache.Configuration;
     using Apache.Ignite.Core.Cache.Eviction;
     using Apache.Ignite.Core.Client;
+    using Apache.Ignite.Core.Client.Cache;
     using Apache.Ignite.Core.Common;
     using Apache.Ignite.Core.Communication.Tcp;
     using Apache.Ignite.Core.Configuration;
@@ -99,6 +100,7 @@ namespace Apache.Ignite.Core.Tests
             CheckDefaultValueAttributes(new QueryIndex());
             CheckDefaultValueAttributes(new DataStorageConfiguration());
             CheckDefaultValueAttributes(new DataRegionConfiguration());
+            CheckDefaultValueAttributes(new CacheClientConfiguration());
         }
 
         /// <summary>
index 8a32583..0076d47 100644 (file)
@@ -96,6 +96,7 @@
     <Compile Include="Binary\TimestampAttribute.cs" />
     <Compile Include="Cache\Configuration\CacheKeyConfiguration.cs" />
     <Compile Include="Cache\Configuration\DataPageEvictionMode.cs" />
+    <Compile Include="Client\Cache\CacheClientConfiguration.cs" />
     <Compile Include="Configuration\CheckpointWriteOrder.cs" />
     <Compile Include="Configuration\DataPageEvictionMode.cs" />
     <Compile Include="Configuration\DataRegionConfiguration.cs" />
     <Compile Include="Impl\Binary\MultidimensionalArrayHolder.cs" />
     <Compile Include="Impl\Binary\MultidimensionalArraySerializer.cs" />
     <Compile Include="Impl\Client\Cache\CacheFlags.cs" />
+    <Compile Include="Impl\Client\Cache\ClientCacheConfigurationSerializer.cs" />
     <Compile Include="Impl\Client\Cache\Query\ClientQueryCursor.cs" />
     <Compile Include="Impl\Cache\Query\PlatformQueryQursorBase.cs" />
     <Compile Include="Impl\Binary\BinaryProcessorClient.cs" />
index eb509a0..4db15eb 100644 (file)
@@ -237,6 +237,8 @@ namespace Apache.Ignite.Core.Cache.Configuration
             KeyTypeName = reader.ReadString();
             ValueTypeName = reader.ReadString();
             TableName = reader.ReadString();
+            KeyFieldName = reader.ReadString();
+            ValueFieldName = reader.ReadString();
 
             var count = reader.ReadInt();
             Fields = count == 0
@@ -249,9 +251,6 @@ namespace Apache.Ignite.Core.Cache.Configuration
 
             count = reader.ReadInt();
             Indexes = count == 0 ? null : Enumerable.Range(0, count).Select(x => new QueryIndex(reader)).ToList();
-
-            KeyFieldName = reader.ReadString();
-            ValueFieldName = reader.ReadString();
         }
 
         /// <summary>
@@ -262,6 +261,8 @@ namespace Apache.Ignite.Core.Cache.Configuration
             writer.WriteString(KeyTypeName);
             writer.WriteString(ValueTypeName);
             writer.WriteString(TableName);
+            writer.WriteString(KeyFieldName);
+            writer.WriteString(ValueFieldName);
 
             if (Fields != null)
             {
@@ -303,9 +304,6 @@ namespace Apache.Ignite.Core.Cache.Configuration
             }
             else
                 writer.WriteInt(0);
-
-            writer.WriteString(KeyFieldName);
-            writer.WriteString(ValueFieldName);
         }
 
         /// <summary>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/CacheClientConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Client/Cache/CacheClientConfiguration.cs
new file mode 100644 (file)
index 0000000..21ca247
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+namespace Apache.Ignite.Core.Client.Cache
+{
+    using System;
+    using System.Collections.Generic;
+    using System.ComponentModel;
+    using System.Diagnostics;
+    using System.Diagnostics.CodeAnalysis;
+    using System.IO;
+    using System.Linq;
+    using Apache.Ignite.Core.Cache;
+    using Apache.Ignite.Core.Cache.Configuration;
+    using Apache.Ignite.Core.Configuration;
+    using Apache.Ignite.Core.Impl;
+    using Apache.Ignite.Core.Impl.Binary.IO;
+    using Apache.Ignite.Core.Impl.Client.Cache;
+    using Apache.Ignite.Core.Impl.Common;
+
+    /// <summary>
+    /// Ignite client cache configuration.
+    /// Same thing as <see cref="CacheConfiguration"/>, but with a subset of properties that can be accessed from
+    /// Ignite thin client (see <see cref="IIgniteClient"/>).
+    /// <para />
+    /// Note that caches created from server nodes can be accessed from thin client, and vice versa.
+    /// The only difference is that thin client can not read or write certain <see cref="CacheConfiguration"/>
+    /// properties, so a separate class exists to make it clear which properties can be used.
+    /// </summary>
+    public class CacheClientConfiguration
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CacheConfiguration"/> class.
+        /// </summary>
+        public CacheClientConfiguration() : this((string) null)
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CacheConfiguration"/> class.
+        /// </summary>
+        /// <param name="name">Cache name.</param>
+        public CacheClientConfiguration(string name)
+        {
+            Name = name;
+
+            Backups = CacheConfiguration.DefaultBackups;
+            AtomicityMode = CacheConfiguration.DefaultAtomicityMode;
+            CacheMode = CacheConfiguration.DefaultCacheMode;
+            CopyOnRead = CacheConfiguration.DefaultCopyOnRead;
+            WriteSynchronizationMode = CacheConfiguration.DefaultWriteSynchronizationMode;
+            EagerTtl = CacheConfiguration.DefaultEagerTtl;
+            Invalidate = CacheConfiguration.DefaultInvalidate;
+            LockTimeout = CacheConfiguration.DefaultLockTimeout;
+            MaxConcurrentAsyncOperations = CacheConfiguration.DefaultMaxConcurrentAsyncOperations;
+            ReadFromBackup = CacheConfiguration.DefaultReadFromBackup;
+            RebalanceBatchSize = CacheConfiguration.DefaultRebalanceBatchSize;
+            RebalanceMode = CacheConfiguration.DefaultRebalanceMode;
+            RebalanceThrottle = CacheConfiguration.DefaultRebalanceThrottle;
+            RebalanceTimeout = CacheConfiguration.DefaultRebalanceTimeout;
+            PartitionLossPolicy = CacheConfiguration.DefaultPartitionLossPolicy;
+            SqlIndexMaxInlineSize = CacheConfiguration.DefaultSqlIndexMaxInlineSize;
+            RebalanceOrder = CacheConfiguration.DefaultRebalanceOrder;
+            RebalanceBatchesPrefetchCount = CacheConfiguration.DefaultRebalanceBatchesPrefetchCount;
+            MaxQueryIteratorsCount = CacheConfiguration.DefaultMaxQueryIteratorsCount;
+            QueryParallelism = CacheConfiguration.DefaultQueryParallelism;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CacheConfiguration"/> class 
+        /// and populates <see cref="QueryEntities"/> according to provided query types.
+        /// </summary>
+        /// <param name="name">Cache name.</param>
+        /// <param name="queryTypes">
+        /// Collection of types to be registered as query entities. These types should use 
+        /// <see cref="QuerySqlFieldAttribute"/> to configure query fields and properties.
+        /// </param>
+        public CacheClientConfiguration(string name, params Type[] queryTypes) : this(name)
+        {
+            QueryEntities = queryTypes.Select(type => new QueryEntity { ValueType = type }).ToArray();
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CacheConfiguration"/> class.
+        /// </summary>
+        /// <param name="name">Cache name.</param>
+        /// <param name="queryEntities">Query entities.</param>
+        public CacheClientConfiguration(string name, params QueryEntity[] queryEntities) : this(name)
+        {
+            QueryEntities = queryEntities;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CacheConfiguration"/> class,
+        /// performing a deep copy of specified cache configuration.
+        /// </summary>
+        /// <param name="other">The other configuration to perfrom deep copy from.</param>
+        public CacheClientConfiguration(CacheClientConfiguration other)
+        {
+            if (other != null)
+            {
+                using (var stream = IgniteManager.Memory.Allocate().GetStream())
+                {
+                    ClientCacheConfigurationSerializer.Write(stream, other);
+
+                    stream.SynchronizeOutput();
+                    stream.Seek(0, SeekOrigin.Begin);
+
+                    ClientCacheConfigurationSerializer.Read(stream, this);
+                }
+
+                CopyLocalProperties(other);
+            }
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CacheClientConfiguration" /> class, copying properties from
+        /// provided server cache configuration. See also <see cref="ToCacheConfiguration"/>.
+        /// </summary>
+        /// <param name="cacheConfiguration">Server cache configuration.</param>
+        /// <param name="ignoreUnsupportedProperties">If set to <c>true</c>,
+        /// ignores unsupported properties instead of throwing an exception.</param>
+        public CacheClientConfiguration(CacheConfiguration cacheConfiguration, bool ignoreUnsupportedProperties)
+        {
+            IgniteArgumentCheck.NotNull(cacheConfiguration, "cacheConfiguration");
+
+            ClientCacheConfigurationSerializer.Copy(cacheConfiguration, this, ignoreUnsupportedProperties);
+        }
+
+        /// <summary>
+        /// Converts this instance to full <see cref="CacheConfiguration"/>.
+        /// </summary>
+        public CacheConfiguration ToCacheConfiguration()
+        {
+            var cfg = new CacheConfiguration();
+
+            ClientCacheConfigurationSerializer.Copy(this, cfg);
+
+            return cfg;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CacheClientConfiguration"/> class.
+        /// </summary>
+        internal CacheClientConfiguration(IBinaryStream stream)
+        {
+            Debug.Assert(stream != null);
+
+            ClientCacheConfigurationSerializer.Read(stream, this);
+        }
+
+        /// <summary>
+        /// Copies the local properties (properties that are not written in Write method).
+        /// </summary>
+        private void CopyLocalProperties(CacheClientConfiguration cfg)
+        {
+            Debug.Assert(cfg != null);
+
+            if (QueryEntities != null && cfg.QueryEntities != null)
+            {
+                var entities = cfg.QueryEntities.Where(x => x != null).ToDictionary(x => GetQueryEntityKey(x), x => x);
+
+                foreach (var entity in QueryEntities.Where(x => x != null))
+                {
+                    QueryEntity src;
+
+                    if (entities.TryGetValue(GetQueryEntityKey(entity), out src))
+                    {
+                        entity.CopyLocalProperties(src);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets the query entity key.
+        /// </summary>
+        private static string GetQueryEntityKey(QueryEntity x)
+        {
+            return x.KeyTypeName + "^" + x.ValueTypeName;
+        }
+
+        /// <summary>
+        /// Gets or sets the cache name.
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Gets or sets write synchronization mode. This mode controls whether the main        
+        /// caller should wait for update on other nodes to complete or not.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultWriteSynchronizationMode)]
+        public CacheWriteSynchronizationMode WriteSynchronizationMode { get; set; }
+
+        /// <summary>
+        /// Gets or sets flag indicating whether expired cache entries will be eagerly removed from cache. 
+        /// When set to false, expired entries will be removed on next entry access.        
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultEagerTtl)]
+        public bool EagerTtl { get; set; }
+
+        /// <summary>
+        /// Gets or sets caching mode to use.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultCacheMode)]
+        public CacheMode CacheMode { get; set; }
+
+        /// <summary>
+        /// Gets or sets cache atomicity mode.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultAtomicityMode)]
+        public CacheAtomicityMode AtomicityMode { get; set; }
+
+        /// <summary>
+        /// Gets or sets number of nodes used to back up single partition for 
+        /// <see cref="Core.Cache.Configuration.CacheMode.Partitioned"/> cache.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultBackups)]
+        public int Backups { get; set; }
+
+        /// <summary>
+        /// Gets or sets default lock acquisition timeout.
+        /// </summary>
+        [DefaultValue(typeof(TimeSpan), "00:00:00")]
+        public TimeSpan LockTimeout { get; set; }
+
+        /// <summary>
+        /// Invalidation flag. If true, values will be invalidated (nullified) upon commit in near cache.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultInvalidate)]
+        public bool Invalidate { get; set; }
+
+        /// <summary>
+        /// Gets or sets cache rebalance mode.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultRebalanceMode)]
+        public CacheRebalanceMode RebalanceMode { get; set; }
+
+        /// <summary>
+        /// Gets or sets size (in number bytes) to be loaded within a single rebalance message.
+        /// Rebalancing algorithm will split total data set on every node into multiple batches prior to sending data.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultRebalanceBatchSize)]
+        public int RebalanceBatchSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets maximum number of allowed concurrent asynchronous operations, 0 for unlimited.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultMaxConcurrentAsyncOperations)]
+        public int MaxConcurrentAsyncOperations { get; set; }
+
+        /// <summary>
+        /// Gets or sets rebalance timeout.
+        /// </summary>
+        [DefaultValue(typeof(TimeSpan), "00:00:10")]
+        public TimeSpan RebalanceTimeout { get; set; }
+
+        /// <summary>
+        /// Gets or sets delay upon a node joining or leaving topology (or crash) 
+        /// after which rebalancing should be started automatically. 
+        /// Rebalancing should be delayed if you plan to restart nodes
+        /// after they leave topology, or if you plan to start multiple nodes at once or one after another
+        /// and don't want to repartition and rebalance until all nodes are started.
+        /// </summary>
+        public TimeSpan RebalanceDelay { get; set; }
+
+        /// <summary>
+        /// Time to wait between rebalance messages to avoid overloading of CPU or network.
+        /// When rebalancing large data sets, the CPU or network can get over-consumed with rebalancing messages,
+        /// which consecutively may slow down the application performance. This parameter helps tune 
+        /// the amount of time to wait between rebalance messages to make sure that rebalancing process
+        /// does not have any negative performance impact. Note that application will continue to work
+        /// properly while rebalancing is still in progress.
+        /// <para/>
+        /// Value of 0 means that throttling is disabled.
+        /// </summary>
+        public TimeSpan RebalanceThrottle { get; set; }
+
+        /// <summary>
+        /// Gets or sets flag indicating whether data can be read from backup.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultReadFromBackup)]
+        public bool ReadFromBackup { get; set; }
+
+        /// <summary>
+        /// Gets or sets flag indicating whether copy of the value stored in cache should be created
+        /// for cache operation implying return value. 
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultCopyOnRead)]
+        public bool CopyOnRead { get; set; }
+
+        /// <summary>
+        /// If true all the SQL table and field names will be escaped with double quotes like 
+        /// ({ "tableName"."fieldsName"}). This enforces case sensitivity for field names and
+        /// also allows having special characters in table and field names.
+        /// </summary>
+        public bool SqlEscapeAll { get; set; }
+
+        /// <summary>
+        /// Gets or sets the query entity configuration.
+        /// </summary>
+        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
+        public ICollection<QueryEntity> QueryEntities { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether statistics gathering is enabled on a cache.
+        /// These statistics can be retrieved via <see cref="ICache{TK,TV}.GetMetrics()"/>.
+        /// </summary>
+        public bool EnableStatistics { get; set; }
+
+        /// <summary>
+        /// Gets or sets the name of the data region, see <see cref="DataRegionConfiguration"/>.
+        /// </summary>
+        public string DataRegionName { get; set; }
+
+        /// <summary>
+        /// Gets or sets the partition loss policy. This policy defines how Ignite will react to
+        /// a situation when all nodes for some partition leave the cluster.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultPartitionLossPolicy)]
+        public PartitionLossPolicy PartitionLossPolicy { get; set; }
+
+        /// <summary>
+        /// Gets or sets the cache group name. Caches with the same group name share single underlying 'physical'
+        /// cache (partition set), but are logically isolated. 
+        /// <para />
+        /// Since underlying cache is shared, the following configuration properties should be the same within group:
+        /// <see cref="CacheMode"/>, <see cref="PartitionLossPolicy"/>, <see cref="DataRegionName"/>.
+        /// <para />
+        /// Grouping caches reduces overall overhead, since internal data structures are shared.
+        /// </summary>
+        public string GroupName { get; set; }
+
+        /// <summary>
+        /// Gets or sets maximum inline size in bytes for sql indexes. See also <see cref="QueryIndex.InlineSize"/>.
+        /// -1 for automatic.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultSqlIndexMaxInlineSize)]
+        public int SqlIndexMaxInlineSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the key configuration.
+        /// </summary>
+        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
+        public ICollection<CacheKeyConfiguration> KeyConfiguration { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether on-heap cache is enabled for the off-heap based page memory.
+        /// </summary>
+        public bool OnheapCacheEnabled { get; set; }
+
+        /// <summary>
+        /// Gets or sets the cache rebalance order. Caches with bigger RebalanceOrder are rebalanced later than caches
+        /// with smaller RebalanceOrder.
+        /// <para />
+        /// Default is 0, which means unordered rebalance. All caches with RebalanceOrder=0 are rebalanced without any
+        /// delay concurrently.
+        /// <para />
+        /// This parameter is applicable only for caches with <see cref="RebalanceMode"/> of
+        /// <see cref="CacheRebalanceMode.Sync"/> and <see cref="CacheRebalanceMode.Async"/>.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultRebalanceOrder)]
+        public int RebalanceOrder { get; set; }
+
+        /// <summary>
+        /// Gets or sets the rebalance batches prefetch count.
+        /// <para />
+        /// Source node can provide more than one batch at rebalance start to improve performance.
+        /// Default is <see cref="CacheConfiguration.DefaultRebalanceBatchesPrefetchCount"/>, minimum is 2.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultRebalanceBatchesPrefetchCount)]
+        public long RebalanceBatchesPrefetchCount { get; set; }
+
+        /// <summary>
+        /// Gets or sets the maximum number of active query iterators.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultMaxQueryIteratorsCount)]
+        public int MaxQueryIteratorsCount { get; set; }
+
+        /// <summary>
+        /// Gets or sets the size of the query detail metrics to be stored in memory.
+        /// <para />
+        /// 0 means disabled metrics.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultQueryDetailMetricsSize)]
+        public int QueryDetailMetricsSize { get; set; }
+
+        /// <summary>
+        /// Gets or sets the SQL schema.
+        /// Non-quoted identifiers are not case sensitive. Quoted identifiers are case sensitive.
+        /// <para />
+        /// Quoted <see cref="Name"/> is used by default.
+        /// </summary>
+        public string SqlSchema { get; set; }
+
+        /// <summary>
+        /// Gets or sets the desired query parallelism within a single node.
+        /// Query executor may or may not use this hint, depending on estimated query cost.
+        /// <para />
+        /// Default is <see cref="CacheConfiguration.DefaultQueryParallelism"/>.
+        /// </summary>
+        [DefaultValue(CacheConfiguration.DefaultQueryParallelism)]
+        public int QueryParallelism { get; set; }
+    }
+}
index d772ba6..a3964c6 100644 (file)
@@ -220,5 +220,10 @@ namespace Apache.Ignite.Core.Client.Cache
         /// <param name="modes">Optional peek modes. If not provided, then total cache size is returned.</param>
         /// <returns>Cache size across all nodes.</returns>
         long GetSize(params CachePeekMode[] modes);
+
+        /// <summary>
+        /// Gets the cache configuration.
+        /// </summary>
+        CacheClientConfiguration GetConfiguration();
     }
 }
index ceb8f26..d5ba835 100644 (file)
@@ -18,6 +18,7 @@
 namespace Apache.Ignite.Core.Client
 {
     using System;
+    using System.Collections.Generic;
     using Apache.Ignite.Core.Client.Cache;
 
     /// <summary>
@@ -40,5 +41,54 @@ namespace Apache.Ignite.Core.Client
         /// <typeparam name="TK">Cache key type.</typeparam>
         /// <typeparam name="TV">Cache value type.</typeparam>
         ICacheClient<TK, TV> GetCache<TK, TV>(string name);
+
+        /// <summary>
+        /// Gets existing cache with the given name or creates new one using template configuration.
+        /// </summary>
+        /// <typeparam name="TK">Cache key type.</typeparam>
+        /// <typeparam name="TV">Cache value type.</typeparam>
+        /// <param name="name">Cache name.</param>
+        /// <returns>Existing or newly created cache.</returns>
+        ICacheClient<TK, TV> GetOrCreateCache<TK, TV>(string name);
+
+        /// <summary>
+        /// Gets existing cache with the given name or creates new one using provided configuration.
+        /// </summary>
+        /// <typeparam name="TK">Cache key type.</typeparam>
+        /// <typeparam name="TV">Cache value type.</typeparam>
+        /// <param name="configuration">Cache configuration.</param>
+        /// <returns>Existing or newly created cache.</returns>
+        ICacheClient<TK, TV> GetOrCreateCache<TK, TV>(CacheClientConfiguration configuration);
+
+        /// <summary>
+        /// Dynamically starts new cache using template configuration.
+        /// </summary>
+        /// <typeparam name="TK">Cache key type.</typeparam>
+        /// <typeparam name="TV">Cache value type.</typeparam>
+        /// <param name="name">Cache name.</param>
+        /// <returns>Existing or newly created cache.</returns>
+        ICacheClient<TK, TV> CreateCache<TK, TV>(string name);
+
+        /// <summary>
+        /// Dynamically starts new cache using provided configuration.
+        /// </summary>
+        /// <typeparam name="TK">Cache key type.</typeparam>
+        /// <typeparam name="TV">Cache value type.</typeparam>
+        /// <param name="configuration">Cache configuration.</param>
+        /// <returns>Existing or newly created cache.</returns>
+        ICacheClient<TK, TV> CreateCache<TK, TV>(CacheClientConfiguration configuration);
+
+        /// <summary>
+        /// Gets the collection of names of currently available caches, or empty collection if there are no caches.
+        /// </summary>
+        /// <returns>Collection of names of currently available caches.</returns>
+        ICollection<string> GetCacheNames();
+
+        /// <summary>
+        /// Destroys dynamically created (with <see cref="CreateCache{TK,TV}(string)"/> or 
+        /// <see cref="GetOrCreateCache{TK,TV}(string)"/>) cache.
+        /// </summary>
+        /// <param name="name">The name of the cache to stop.</param>
+        void DestroyCache(string name);
     }
 }
index f61da06..bf6a227 100644 (file)
@@ -276,7 +276,6 @@ namespace Apache.Ignite.Core
 
         /// <summary>
         /// Gets the collection of names of currently available caches, or empty collection if there are no caches.
-        /// Note that null string is a valid cache name.
         /// </summary>
         /// <returns>Collection of names of currently available caches.</returns>
         ICollection<string> GetCacheNames();
index 9be06c5..de0277b 100644 (file)
@@ -124,5 +124,23 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             return res;
         }
+
+        /// <summary>
+        /// Reads the string collection.
+        /// </summary>
+        public static ICollection<string> ReadStringCollection(this IBinaryRawReader reader)
+        {
+            Debug.Assert(reader != null);
+
+            var cnt = reader.ReadInt();
+            var res = new List<string>(cnt);
+
+            for (var i = 0; i < cnt; i++)
+            {
+                res.Add(reader.ReadString());
+            }
+
+            return res;
+        }
     }
 }
index be6e7da..a3b42b8 100644 (file)
@@ -327,6 +327,12 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
             return DoOutInOp(ClientOp.CacheGetSize, w => WritePeekModes(modes, w), s => s.ReadLong());
         }
 
+        /** <inheritDoc /> */
+        public CacheClientConfiguration GetConfiguration()
+        {
+            return DoOutInOp(ClientOp.CacheGetConfiguration, null, s => new CacheClientConfiguration(s));
+        }
+
         /// <summary>
         /// Does the out in op.
         /// </summary>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/ClientCacheConfigurationSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/ClientCacheConfigurationSerializer.cs
new file mode 100644 (file)
index 0000000..160d09f
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Client.Cache
+{
+    using System;
+    using System.Diagnostics;
+    using Apache.Ignite.Core.Cache.Configuration;
+    using Apache.Ignite.Core.Client.Cache;
+    using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Binary.IO;
+
+    /// <summary>
+    /// Writes and reads <see cref="CacheConfiguration"/> for thin client mode.
+    /// <para />
+    /// Thin client supports a subset of <see cref="CacheConfiguration"/> properties, so
+    /// <see cref="CacheConfiguration.Read"/> is not suitable.
+    /// </summary>
+    internal static class ClientCacheConfigurationSerializer
+    {
+        /// <summary>
+        /// Copies one cache configuration to another.
+        /// </summary>
+        public static void Copy(CacheConfiguration from, CacheClientConfiguration to, bool ignoreUnsupportedProperties)
+        {
+            Debug.Assert(from != null);
+            Debug.Assert(to != null);
+
+            to.AtomicityMode = from.AtomicityMode;
+            to.Backups = from.Backups;
+            to.CacheMode = from.CacheMode;
+            to.CopyOnRead = from.CopyOnRead;
+            to.DataRegionName = from.DataRegionName;
+            to.EagerTtl = from.EagerTtl;
+            to.EnableStatistics = from.EnableStatistics;
+            to.GroupName = from.GroupName;
+            to.Invalidate = from.Invalidate;
+            to.LockTimeout = from.LockTimeout;
+            to.MaxConcurrentAsyncOperations = from.MaxConcurrentAsyncOperations;
+            to.MaxQueryIteratorsCount = from.MaxQueryIteratorsCount;
+            to.Name = from.Name;
+            to.OnheapCacheEnabled = from.OnheapCacheEnabled;
+            to.PartitionLossPolicy = from.PartitionLossPolicy;
+            to.QueryDetailMetricsSize = from.QueryDetailMetricsSize;
+            to.QueryParallelism = from.QueryParallelism;
+            to.ReadFromBackup = from.ReadFromBackup;
+            to.RebalanceBatchSize = from.RebalanceBatchSize;
+            to.RebalanceBatchesPrefetchCount = from.RebalanceBatchesPrefetchCount;
+            to.RebalanceDelay = from.RebalanceDelay;
+            to.RebalanceMode = from.RebalanceMode;
+            to.RebalanceOrder = from.RebalanceOrder;
+            to.RebalanceThrottle = from.RebalanceThrottle;
+            to.RebalanceTimeout = from.RebalanceTimeout;
+            to.SqlEscapeAll = from.SqlEscapeAll;
+            to.SqlIndexMaxInlineSize = from.SqlIndexMaxInlineSize;
+            to.SqlSchema = from.SqlSchema;
+            to.WriteSynchronizationMode = from.WriteSynchronizationMode;
+
+            to.KeyConfiguration = from.KeyConfiguration;
+            to.QueryEntities = from.QueryEntities;
+
+            if (!ignoreUnsupportedProperties)
+            {
+                // Unsupported complex properties.
+                ThrowUnsupportedIfNotDefault(from.AffinityFunction, "AffinityFunction");
+                ThrowUnsupportedIfNotDefault(from.EvictionPolicy, "EvictionPolicy");
+                ThrowUnsupportedIfNotDefault(from.ExpiryPolicyFactory, "ExpiryPolicyFactory");
+                ThrowUnsupportedIfNotDefault(from.PluginConfigurations, "PluginConfigurations");
+                ThrowUnsupportedIfNotDefault(from.CacheStoreFactory, "CacheStoreFactory");
+                ThrowUnsupportedIfNotDefault(from.NearConfiguration, "NearConfiguration");
+
+                // Unsupported store-related properties.
+                ThrowUnsupportedIfNotDefault(from.KeepBinaryInStore, "KeepBinaryInStore");
+                ThrowUnsupportedIfNotDefault(from.LoadPreviousValue, "LoadPreviousValue");
+                ThrowUnsupportedIfNotDefault(from.ReadThrough, "ReadThrough");
+                ThrowUnsupportedIfNotDefault(from.WriteThrough, "WriteThrough");
+                ThrowUnsupportedIfNotDefault(from.StoreConcurrentLoadAllThreshold, "StoreConcurrentLoadAllThreshold",
+                    CacheConfiguration.DefaultStoreConcurrentLoadAllThreshold);
+                ThrowUnsupportedIfNotDefault(from.WriteBehindBatchSize, "WriteBehindBatchSize",
+                    CacheConfiguration.DefaultWriteBehindBatchSize);
+                ThrowUnsupportedIfNotDefault(from.WriteBehindCoalescing, "WriteBehindCoalescing",
+                    CacheConfiguration.DefaultWriteBehindCoalescing);
+                ThrowUnsupportedIfNotDefault(from.WriteBehindEnabled, "WriteBehindEnabled");
+                ThrowUnsupportedIfNotDefault(from.WriteBehindFlushFrequency, "WriteBehindFlushFrequency",
+                    CacheConfiguration.DefaultWriteBehindFlushFrequency);
+                ThrowUnsupportedIfNotDefault(from.WriteBehindFlushSize, "WriteBehindFlushSize",
+                    CacheConfiguration.DefaultWriteBehindFlushSize);
+                ThrowUnsupportedIfNotDefault(from.WriteBehindFlushThreadCount, "WriteBehindFlushThreadCount",
+                    CacheConfiguration.DefaultWriteBehindFlushThreadCount);
+            }
+        }
+        /// <summary>
+        /// Copies one cache configuration to another.
+        /// </summary>
+        public static void Copy(CacheClientConfiguration from, CacheConfiguration to)
+        {
+            Debug.Assert(from != null);
+            Debug.Assert(to != null);
+
+            to.AtomicityMode = from.AtomicityMode;
+            to.Backups = from.Backups;
+            to.CacheMode = from.CacheMode;
+            to.CopyOnRead = from.CopyOnRead;
+            to.DataRegionName = from.DataRegionName;
+            to.EagerTtl = from.EagerTtl;
+            to.EnableStatistics = from.EnableStatistics;
+            to.GroupName = from.GroupName;
+            to.Invalidate = from.Invalidate;
+            to.LockTimeout = from.LockTimeout;
+            to.MaxConcurrentAsyncOperations = from.MaxConcurrentAsyncOperations;
+            to.MaxQueryIteratorsCount = from.MaxQueryIteratorsCount;
+            to.Name = from.Name;
+            to.OnheapCacheEnabled = from.OnheapCacheEnabled;
+            to.PartitionLossPolicy = from.PartitionLossPolicy;
+            to.QueryDetailMetricsSize = from.QueryDetailMetricsSize;
+            to.QueryParallelism = from.QueryParallelism;
+            to.ReadFromBackup = from.ReadFromBackup;
+            to.RebalanceBatchSize = from.RebalanceBatchSize;
+            to.RebalanceBatchesPrefetchCount = from.RebalanceBatchesPrefetchCount;
+            to.RebalanceDelay = from.RebalanceDelay;
+            to.RebalanceMode = from.RebalanceMode;
+            to.RebalanceOrder = from.RebalanceOrder;
+            to.RebalanceThrottle = from.RebalanceThrottle;
+            to.RebalanceTimeout = from.RebalanceTimeout;
+            to.SqlEscapeAll = from.SqlEscapeAll;
+            to.SqlIndexMaxInlineSize = from.SqlIndexMaxInlineSize;
+            to.SqlSchema = from.SqlSchema;
+            to.WriteSynchronizationMode = from.WriteSynchronizationMode;
+
+            to.KeyConfiguration = from.KeyConfiguration;
+            to.QueryEntities = from.QueryEntities;
+        }
+
+        /// <summary>
+        /// Writes the specified config.
+        /// </summary>
+        public static void Write(IBinaryStream stream, CacheClientConfiguration cfg)
+        {
+            Debug.Assert(stream != null);
+            Debug.Assert(cfg != null);
+
+            // Configuration should be written with a system marshaller.
+            var writer = BinaryUtils.Marshaller.StartMarshal(stream);
+            var pos = writer.Stream.Position;
+            writer.WriteInt(0);  // Reserve for length.
+
+            writer.WriteInt((int)cfg.AtomicityMode);
+            writer.WriteInt(cfg.Backups);
+            writer.WriteInt((int)cfg.CacheMode);
+            writer.WriteBoolean(cfg.CopyOnRead);
+            writer.WriteString(cfg.DataRegionName);
+            writer.WriteBoolean(cfg.EagerTtl);
+            writer.WriteBoolean(cfg.EnableStatistics);
+            writer.WriteString(cfg.GroupName);
+            writer.WriteBoolean(cfg.Invalidate);
+            writer.WriteTimeSpanAsLong(cfg.LockTimeout);
+            writer.WriteInt(cfg.MaxConcurrentAsyncOperations);
+            writer.WriteInt(cfg.MaxQueryIteratorsCount);
+            writer.WriteString(cfg.Name);
+            writer.WriteBoolean(cfg.OnheapCacheEnabled);
+            writer.WriteInt((int)cfg.PartitionLossPolicy);
+            writer.WriteInt(cfg.QueryDetailMetricsSize);
+            writer.WriteInt(cfg.QueryParallelism);
+            writer.WriteBoolean(cfg.ReadFromBackup);
+            writer.WriteInt(cfg.RebalanceBatchSize);
+            writer.WriteLong(cfg.RebalanceBatchesPrefetchCount);
+            writer.WriteTimeSpanAsLong(cfg.RebalanceDelay);
+            writer.WriteInt((int)cfg.RebalanceMode);
+            writer.WriteInt(cfg.RebalanceOrder);
+            writer.WriteTimeSpanAsLong(cfg.RebalanceThrottle);
+            writer.WriteTimeSpanAsLong(cfg.RebalanceTimeout);
+            writer.WriteBoolean(cfg.SqlEscapeAll);
+            writer.WriteInt(cfg.SqlIndexMaxInlineSize);
+            writer.WriteString(cfg.SqlSchema);
+            writer.WriteInt((int)cfg.WriteSynchronizationMode);
+
+            writer.WriteCollectionRaw(cfg.KeyConfiguration);
+            writer.WriteCollectionRaw(cfg.QueryEntities);
+
+            // Write length (so that part of the config can be skipped).
+            var len = writer.Stream.Position - pos - 4;
+            writer.Stream.WriteInt(pos, len);
+        }
+        /// <summary>
+        /// Reads the config.
+        /// </summary>
+        public static void Read(IBinaryStream stream, CacheClientConfiguration cfg)
+        {
+            Debug.Assert(stream != null);
+
+            // Configuration should be read with system marshaller.
+            var reader = BinaryUtils.Marshaller.StartUnmarshal(stream);
+
+            var len = reader.ReadInt();
+            var pos = reader.Stream.Position;
+
+            cfg.AtomicityMode = (CacheAtomicityMode)reader.ReadInt();
+            cfg.Backups = reader.ReadInt();
+            cfg.CacheMode = (CacheMode)reader.ReadInt();
+            cfg.CopyOnRead = reader.ReadBoolean();
+            cfg.DataRegionName = reader.ReadString();
+            cfg.EagerTtl = reader.ReadBoolean();
+            cfg.EnableStatistics = reader.ReadBoolean();
+            cfg.GroupName = reader.ReadString();
+            cfg.Invalidate = reader.ReadBoolean();
+            cfg.LockTimeout = reader.ReadLongAsTimespan();
+            cfg.MaxConcurrentAsyncOperations = reader.ReadInt();
+            cfg.MaxQueryIteratorsCount = reader.ReadInt();
+            cfg.Name = reader.ReadString();
+            cfg.OnheapCacheEnabled = reader.ReadBoolean();
+            cfg.PartitionLossPolicy = (PartitionLossPolicy)reader.ReadInt();
+            cfg.QueryDetailMetricsSize = reader.ReadInt();
+            cfg.QueryParallelism = reader.ReadInt();
+            cfg.ReadFromBackup = reader.ReadBoolean();
+            cfg.RebalanceBatchSize = reader.ReadInt();
+            cfg.RebalanceBatchesPrefetchCount = reader.ReadLong();
+            cfg.RebalanceDelay = reader.ReadLongAsTimespan();
+            cfg.RebalanceMode = (CacheRebalanceMode)reader.ReadInt();
+            cfg.RebalanceOrder = reader.ReadInt();
+            cfg.RebalanceThrottle = reader.ReadLongAsTimespan();
+            cfg.RebalanceTimeout = reader.ReadLongAsTimespan();
+            cfg.SqlEscapeAll = reader.ReadBoolean();
+            cfg.SqlIndexMaxInlineSize = reader.ReadInt();
+            cfg.SqlSchema = reader.ReadString();
+            cfg.WriteSynchronizationMode = (CacheWriteSynchronizationMode)reader.ReadInt();
+            cfg.KeyConfiguration = reader.ReadCollectionRaw(r => new CacheKeyConfiguration(r));
+            cfg.QueryEntities = reader.ReadCollectionRaw(r => new QueryEntity(r));
+
+            Debug.Assert(len == reader.Stream.Position - pos);
+        }
+
+        /// <summary>
+        /// Throws the unsupported exception if property is not default.
+        /// </summary>
+        // ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local
+        // ReSharper disable UnusedParameter.Local
+        private static void ThrowUnsupportedIfNotDefault<T>(T obj, string propertyName, T defaultValue = default(T))
+        {
+            if (!Equals(obj, defaultValue))
+            {
+                throw new NotSupportedException(
+                    string.Format("{0}.{1} property is not supported in thin client mode.",
+                        typeof(CacheConfiguration).Name, propertyName));
+            }
+        }
+    }
+}
index 3511a79..779b73e 100644 (file)
@@ -49,6 +49,13 @@ namespace Apache.Ignite.Core.Impl.Client
         CacheRemoveIfEquals = 25,
         CacheGetSize = 26,
         CacheRemoveKeys = 27,
-        CacheRemoveAll = 28
+        CacheRemoveAll = 28,
+        CacheCreateWithName = 29,
+        CacheGetOrCreateWithName = 30,
+        CacheDestroy = 31,
+        CacheGetNames = 32,
+        CacheGetConfiguration = 33,
+        CacheCreateWithConfiguration = 34,
+        CacheGetOrCreateWithConfiguration = 35
     }
 }
index a2e66e8..294a202 100644 (file)
@@ -26,6 +26,7 @@ namespace Apache.Ignite.Core.Impl.Client
         Fail = 1,
         InvalidOpCode = 2,
         CacheDoesNotExist = 1000,
+        CacheExists = 1001,
         TooManyCursors = 1010
     }
 }
index d05355a..13a3a83 100644 (file)
@@ -18,6 +18,7 @@
 namespace Apache.Ignite.Core.Impl.Client
 {
     using System;
+    using System.Collections.Generic;
     using System.Diagnostics;
     using System.Diagnostics.CodeAnalysis;
     using Apache.Ignite.Core.Binary;
@@ -25,6 +26,7 @@ namespace Apache.Ignite.Core.Impl.Client
     using Apache.Ignite.Core.Client.Cache;
     using Apache.Ignite.Core.Datastream;
     using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Binary.IO;
     using Apache.Ignite.Core.Impl.Client.Cache;
     using Apache.Ignite.Core.Impl.Cluster;
     using Apache.Ignite.Core.Impl.Common;
@@ -88,6 +90,62 @@ namespace Apache.Ignite.Core.Impl.Client
         }
 
         /** <inheritDoc /> */
+        public ICacheClient<TK, TV> GetOrCreateCache<TK, TV>(string name)
+        {
+            IgniteArgumentCheck.NotNull(name, "name");
+
+            DoOutOp(ClientOp.CacheGetOrCreateWithName, w => w.WriteString(name));
+
+            return GetCache<TK, TV>(name);
+        }
+
+        /** <inheritDoc /> */
+        public ICacheClient<TK, TV> GetOrCreateCache<TK, TV>(CacheClientConfiguration configuration)
+        {
+            IgniteArgumentCheck.NotNull(configuration, "configuration");
+
+            DoOutOp(ClientOp.CacheGetOrCreateWithConfiguration,
+                w => ClientCacheConfigurationSerializer.Write(w.Stream, configuration));
+
+            return GetCache<TK, TV>(configuration.Name);
+        }
+
+        /** <inheritDoc /> */
+        public ICacheClient<TK, TV> CreateCache<TK, TV>(string name)
+        {
+            IgniteArgumentCheck.NotNull(name, "name");
+
+            DoOutOp(ClientOp.CacheCreateWithName, w => w.WriteString(name));
+
+            return GetCache<TK, TV>(name);
+        }
+
+        /** <inheritDoc /> */
+        public ICacheClient<TK, TV> CreateCache<TK, TV>(CacheClientConfiguration configuration)
+        {
+            IgniteArgumentCheck.NotNull(configuration, "configuration");
+
+            DoOutOp(ClientOp.CacheCreateWithConfiguration,
+                w => ClientCacheConfigurationSerializer.Write(w.Stream, configuration));
+
+            return GetCache<TK, TV>(configuration.Name);
+        }
+
+        /** <inheritDoc /> */
+        public ICollection<string> GetCacheNames()
+        {
+            return DoOutInOp(ClientOp.CacheGetNames, null, s => Marshaller.StartUnmarshal(s).ReadStringCollection());
+        }
+
+        /** <inheritDoc /> */
+        public void DestroyCache(string name)
+        {
+            IgniteArgumentCheck.NotNull(name, "name");
+
+            DoOutOp(ClientOp.CacheDestroy, w => w.WriteString(name));
+        }
+
+        /** <inheritDoc /> */
         public IIgnite GetIgnite()
         {
             throw GetClientNotSupportedException();
@@ -155,5 +213,32 @@ namespace Apache.Ignite.Core.Impl.Client
 
             return new NotSupportedException(msg);
         }
+
+        /// <summary>
+        /// Does the out in op.
+        /// </summary>
+        private T DoOutInOp<T>(ClientOp opId, Action<BinaryWriter> writeAction,
+            Func<IBinaryStream, T> readFunc)
+        {
+            return _socket.DoOutInOp(opId, stream =>
+            {
+                if (writeAction != null)
+                {
+                    var writer = _marsh.StartMarshal(stream);
+
+                    writeAction(writer);
+
+                    _marsh.FinishMarshal(writer);
+                }
+            }, readFunc);
+        }
+
+        /// <summary>
+        /// Does the out op.
+        /// </summary>
+        private void DoOutOp(ClientOp opId, Action<BinaryWriter> writeAction = null)
+        {
+            DoOutInOp<object>(opId, writeAction, null);
+        }
     }
 }
index 1249ed8..8f78382 100644 (file)
                          localhost="127.0.0.1" peerAssemblyLoadingMode="CurrentAppDomain">
         <atomicConfiguration atomicSequenceReserveSize="10" />
 
-        <cacheConfiguration>
-            <cacheConfiguration name="default-cache" />
-        </cacheConfiguration>
-
         <discoverySpi type="TcpDiscoverySpi">
             <ipFinder type="TcpDiscoveryMulticastIpFinder">
                 <endpoints>
index 9158b09..cc35840 100644 (file)
@@ -36,12 +36,11 @@ namespace Apache.Ignite.Examples.ThinClient
     /// 2) Start example.
     /// <para />
     /// This example can also work via pure Java node started with ignite.bat/ignite.sh.
-    /// The only requirement is that the nodes have to create the cache named "default-cache" in advance.
     /// </summary>
     public static class ThinClientPutGetExample
     {
         /// <summary> Cache name. </summary>
-        private const string CacheName = "default-cache";
+        private const string CacheName = "thinClientCache";
 
         [STAThread]
         public static void Main()
@@ -56,7 +55,7 @@ namespace Apache.Ignite.Examples.ThinClient
                 Console.WriteLine();
                 Console.WriteLine(">>> Cache put-get client example started.");
 
-                ICacheClient<int, Organization> cache = igniteClient.GetCache<int, Organization>(CacheName);
+                ICacheClient<int, Organization> cache = igniteClient.GetOrCreateCache<int, Organization>(CacheName);
 
                 PutGet(cache);
             }
index 49c87b7..61b3a8b 100644 (file)
@@ -40,7 +40,7 @@ namespace Apache.Ignite.Examples.ThinClient
     public class ThinClientQueryExample
     {
         /// <summary> Cache name. </summary>
-        private const string CacheName = "default-cache";
+        private const string CacheName = "thinClientCache";
 
         [STAThread]
         public static void Main()
@@ -55,7 +55,7 @@ namespace Apache.Ignite.Examples.ThinClient
                 Console.WriteLine();
                 Console.WriteLine(">>> Cache query client example started.");
 
-                ICacheClient<int, Employee> cache = igniteClient.GetCache<int, Employee>(CacheName);
+                ICacheClient<int, Employee> cache = igniteClient.GetOrCreateCache<int, Employee>(CacheName);
 
                 // Populate cache with sample data entries.
                 PopulateCache(cache);