You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by is...@apache.org on 2022/08/23 05:33:17 UTC

[ignite] branch master updated: IGNITE-17567 C++: Java remote filters for CQ for thick client (#10210)

This is an automated email from the ASF dual-hosted git repository.

isapego pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new 6c7ed4c8dcf IGNITE-17567 C++: Java remote filters for CQ  for thick client (#10210)
6c7ed4c8dcf is described below

commit 6c7ed4c8dcf9a6cd32b3572cd8f30a200aef71f1
Author: Igor Sapego <is...@apache.org>
AuthorDate: Tue Aug 23 08:33:07 2022 +0300

    IGNITE-17567 C++: Java remote filters for CQ  for thick client (#10210)
---
 .../platform/PlatformCacheEntryEventFilterCpp.java | 122 +++++++++++++
 .../ignite/impl/binary/binary_writer_impl.h        |  57 ++++++
 .../binary/src/impl/binary/binary_writer_impl.cpp  |  87 +++++++--
 .../cpp/core-test/src/continuous_query_test.cpp    | 103 ++++++++++-
 .../cache/event/java_cache_entry_event_filter.h    | 128 +++++++++++++
 .../cache/query/continuous/continuous_query.h      |  30 +++
 .../core/include/ignite/cache/query/query_sql.h    |  14 +-
 .../include/ignite/cache/query/query_sql_fields.h  |  16 +-
 .../cache/event/cache_entry_event_filter_holder.h  |  58 ++++++
 .../cache/query/continuous/continuous_query_impl.h |  17 ++
 .../ignite/impl/cache/query/query_argument.h       | 200 --------------------
 .../impl/platform_java_object_factory_proxy.h      | 201 +++++++++++++++++++++
 .../cpp/core/include/ignite/impl/writable_object.h | 194 ++++++++++++++++++++
 .../cpp/core/src/impl/cache/cache_impl.cpp         |   4 +-
 14 files changed, 998 insertions(+), 233 deletions(-)

diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheEntryEventFilterCpp.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheEntryEventFilterCpp.java
new file mode 100644
index 00000000000..dc78d3575ed
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheEntryEventFilterCpp.java
@@ -0,0 +1,122 @@
+/*
+ * 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.platform;
+
+import java.util.UUID;
+import javax.cache.event.CacheEntryEvent;
+import javax.cache.event.CacheEntryListenerException;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.cache.CacheEntryEventSerializableFilter;
+import org.apache.ignite.resources.IgniteInstanceResource;
+
+/**
+ * Test filter.
+ */
+@SuppressWarnings({"FieldCanBeLocal", "FloatingPointEquality", "MismatchedReadAndWriteOfArray", "unused"
+})
+public class PlatformCacheEntryEventFilterCpp implements CacheEntryEventSerializableFilter {
+    /** Property to be set from platform. */
+    private String startsWith = "-";
+
+    /** Property to be set from platform. */
+    private char charField;
+
+    /** Property to be set from platform. */
+    private byte byteField;
+
+    /** Property to be set from platform. */
+    private short shortField;
+
+    /** Property to be set from platform. */
+    private int intField;
+
+    /** Property to be set from platform. */
+    private long longField;
+
+    /** Property to be set from platform. */
+    private float floatField;
+
+    /** Property to be set from platform. */
+    private double doubleField;
+
+    /** Property to be set from platform. */
+    private boolean boolField;
+
+    /** Property to be set from platform. */
+    private UUID guidField;
+
+    /** Property to be set from platform. */
+    private BinaryObject objField;
+
+    /** Property to be set from platform. */
+    private char[] charArr;
+
+    /** Property to be set from platform. */
+    private byte[] byteArr;
+
+    /** Property to be set from platform. */
+    private short[] shortArr;
+
+    /** Property to be set from platform. */
+    private int[] intArr;
+
+    /** Property to be set from platform. */
+    private long[] longArr;
+
+    /** Injected instance. */
+    @IgniteInstanceResource
+    private Ignite ignite;
+
+    /** {@inheritDoc} */
+    @Override public boolean evaluate(CacheEntryEvent event) throws CacheEntryListenerException {
+        // check injection
+        assert ignite != null;
+
+        // check fields
+        assert charField == 'a';
+        assert byteField == 1;
+        assert shortField == 3;
+        assert intField == 5;
+        assert longField == 7;
+        assert floatField == (float)9.99;
+        assert doubleField == 10.123;
+        assert boolField;
+        assert guidField.equals(UUID.fromString("1c579241-509d-47c6-a1a0-87462ae31e59"));
+
+        // check arrays
+        assert charArr[0] == 'a';
+        assert byteArr[0] == 1;
+        assert shortArr[0] == 3;
+        assert intArr[0] == 5;
+        assert longArr[0] == 7;
+        // check binary object
+        assert objField != null;
+        assert Integer.valueOf(1).equals(objField.field("i32Field"));
+        assert "2".equals(objField.field("strField"));
+
+        Object value = event.getValue();
+
+        if (value instanceof String)
+            return ((String)value).startsWith(startsWith);
+
+        assert value instanceof BinaryObject;
+
+        return ((String)((BinaryObject)value).field("String")).startsWith(startsWith);
+    }
+}
diff --git a/modules/platforms/cpp/binary/include/ignite/impl/binary/binary_writer_impl.h b/modules/platforms/cpp/binary/include/ignite/impl/binary/binary_writer_impl.h
index c9b923a27ff..57428c941ff 100644
--- a/modules/platforms/cpp/binary/include/ignite/impl/binary/binary_writer_impl.h
+++ b/modules/platforms/cpp/binary/include/ignite/impl/binary/binary_writer_impl.h
@@ -919,6 +919,29 @@ namespace ignite
                     void(*func)(interop::InteropOutputStream*, T)
                 );
 
+                /**
+                 * Write an empty array to stream without any checks.
+                 *
+                 * @param hdr Header.
+                 */
+                void WriteArrayEmpty(const int8_t hdr);
+
+                /**
+                 * Write a primitive array to stream without any checks.
+                 *
+                 * @param val Value.
+                 * @param len Array length.
+                 * @param func Stream function.
+                 * @param hdr Header.
+                 */
+                template<typename T>
+                void WritePrimitiveArrayBase(
+                    const T* val,
+                    const int32_t len,
+                    void(*func)(interop::InteropOutputStream*, const T*, const int32_t),
+                    const int8_t hdr
+                );
+
                 /**
                  * Write a primitive array to stream in raw mode.
                  *
@@ -1043,6 +1066,20 @@ namespace ignite
                     stream->WriteInt8(hdr);
                     func(stream, obj);
                 }
+
+                /**
+                 * Write primitive array.
+                 *
+                 * @param obj Array.
+                 * @param func Write function.
+                 * @param hdr Header.
+                 */
+                template<typename T>
+                void WriteTopPrimitiveArray(
+                    const std::vector<T>& obj,
+                    void(*func)(interop::InteropOutputStream*, const T*, const int32_t),
+                    int8_t hdr
+                );
             };
 
             template<>
@@ -1096,6 +1133,26 @@ namespace ignite
             template<>
             void IGNITE_IMPORT_EXPORT
             BinaryWriterImpl::WriteTopObject0<ignite::binary::BinaryWriter, std::string>(const std::string& obj);
+
+            template<>
+            void IGNITE_IMPORT_EXPORT
+            BinaryWriterImpl::WriteTopObject0<ignite::binary::BinaryWriter, std::vector<int8_t> >(const std::vector<int8_t>& obj);
+
+            template<>
+            void IGNITE_IMPORT_EXPORT
+            BinaryWriterImpl::WriteTopObject0<ignite::binary::BinaryWriter, std::vector<int16_t> >(const std::vector<int16_t>& obj);
+
+            template<>
+            void IGNITE_IMPORT_EXPORT
+            BinaryWriterImpl::WriteTopObject0<ignite::binary::BinaryWriter, std::vector<uint16_t> >(const std::vector<uint16_t>& obj);
+
+            template<>
+            void IGNITE_IMPORT_EXPORT
+            BinaryWriterImpl::WriteTopObject0<ignite::binary::BinaryWriter, std::vector<int32_t> >(const std::vector<int32_t>& obj);
+
+            template<>
+            void IGNITE_IMPORT_EXPORT
+            BinaryWriterImpl::WriteTopObject0<ignite::binary::BinaryWriter, std::vector<int64_t> >(const std::vector<int64_t>& obj);
         }
     }
 }
diff --git a/modules/platforms/cpp/binary/src/impl/binary/binary_writer_impl.cpp b/modules/platforms/cpp/binary/src/impl/binary/binary_writer_impl.cpp
index 467a0f9f9d6..5d660ef4372 100644
--- a/modules/platforms/cpp/binary/src/impl/binary/binary_writer_impl.cpp
+++ b/modules/platforms/cpp/binary/src/impl/binary/binary_writer_impl.cpp
@@ -670,17 +670,20 @@ namespace ignite
                 func(stream, val);
             }
 
+            void BinaryWriterImpl::WriteArrayEmpty(const int8_t hdr)
+            {
+                stream->WriteInt8(hdr);
+                stream->WriteInt32(0);
+            }
+
             template<typename T>
-            void BinaryWriterImpl::WritePrimitiveArrayRaw(
+            void BinaryWriterImpl::WritePrimitiveArrayBase(
                 const T* val,
                 const int32_t len,
                 void(*func)(interop::InteropOutputStream*, const T*, const int32_t),
                 const int8_t hdr
             )
             {
-                CheckRawMode(true);
-                CheckSingleMode(true);
-
                 if (val)
                 {
                     stream->WriteInt8(hdr);
@@ -691,6 +694,20 @@ namespace ignite
                     stream->WriteInt8(IGNITE_HDR_NULL);
             }
 
+            template<typename T>
+            void BinaryWriterImpl::WritePrimitiveArrayRaw(
+                const T* val,
+                const int32_t len,
+                void(*func)(interop::InteropOutputStream*, const T*, const int32_t),
+                const int8_t hdr
+            )
+            {
+                CheckRawMode(true);
+                CheckSingleMode(true);
+
+                WritePrimitiveArrayBase(val, len, func, hdr);
+            }
+
             template<typename T>
             void BinaryWriterImpl::WritePrimitive(
                 const char* fieldName,
@@ -725,16 +742,7 @@ namespace ignite
 
                 WriteFieldId(fieldName, hdr);
 
-                if (val)
-                {
-                    stream->WriteInt8(hdr);
-                    stream->WriteInt32(len);
-                    func(stream, val, len);
-                }
-                else
-                {
-                    stream->WriteInt8(IGNITE_HDR_NULL);
-                }
+                WritePrimitiveArrayBase(val, len, func, hdr);
             }
 
             void BinaryWriterImpl::CheckRawMode(bool expected) const
@@ -871,6 +879,36 @@ namespace ignite
                 BinaryUtils::WriteString(stream, obj0, len);
             }
 
+            template<>
+            void BinaryWriterImpl::WriteTopObject0<ignite::binary::BinaryWriter, std::vector<int8_t> >(const std::vector<int8_t>& obj)
+            {
+                WriteTopPrimitiveArray(obj, BinaryUtils::WriteInt8Array, IGNITE_TYPE_ARRAY_BYTE);
+            }
+
+            template<>
+            void BinaryWriterImpl::WriteTopObject0<ignite::binary::BinaryWriter, std::vector<int16_t> >(const std::vector<int16_t>& obj)
+            {
+                WriteTopPrimitiveArray(obj, BinaryUtils::WriteInt16Array, IGNITE_TYPE_ARRAY_SHORT);
+            }
+
+            template<>
+            void BinaryWriterImpl::WriteTopObject0<ignite::binary::BinaryWriter, std::vector<uint16_t> >(const std::vector<uint16_t>& obj)
+            {
+                WriteTopPrimitiveArray(obj, BinaryUtils::WriteUInt16Array, IGNITE_TYPE_ARRAY_CHAR);
+            }
+
+            template<>
+            void BinaryWriterImpl::WriteTopObject0<ignite::binary::BinaryWriter, std::vector<int32_t> >(const std::vector<int32_t>& obj)
+            {
+                WriteTopPrimitiveArray(obj, BinaryUtils::WriteInt32Array, IGNITE_TYPE_ARRAY_INT);
+            }
+
+            template<>
+            void BinaryWriterImpl::WriteTopObject0<ignite::binary::BinaryWriter, std::vector<int64_t> >(const std::vector<int64_t>& obj)
+            {
+                WriteTopPrimitiveArray(obj, BinaryUtils::WriteInt64Array, IGNITE_TYPE_ARRAY_LONG);
+            }
+
             void BinaryWriterImpl::PostWrite()
             {
                 int32_t lenWithoutSchema = stream->Position() - start;
@@ -929,6 +967,27 @@ namespace ignite
             {
                 return stream;
             }
+
+            template<typename T>
+            void BinaryWriterImpl::WriteTopPrimitiveArray(
+                const std::vector<T> &obj,
+                void (*func)(interop::InteropOutputStream *, const T *,
+                const int32_t), int8_t hdr
+            )
+            {
+                if (obj.empty())
+                {
+                    WriteArrayEmpty(hdr);
+
+                    return;
+                }
+
+                const T* obj0 = &obj[0];
+
+                int32_t len = static_cast<int32_t>(obj.size());
+
+                WritePrimitiveArrayBase(obj0, len, func, hdr);
+            }
         }
     }
 }
diff --git a/modules/platforms/cpp/core-test/src/continuous_query_test.cpp b/modules/platforms/cpp/core-test/src/continuous_query_test.cpp
index a6715b99ddc..5e9d351e874 100644
--- a/modules/platforms/cpp/core-test/src/continuous_query_test.cpp
+++ b/modules/platforms/cpp/core-test/src/continuous_query_test.cpp
@@ -25,6 +25,7 @@
 #include "ignite/ignition.h"
 #include "ignite/cache/cache.h"
 #include "ignite/test_utils.h"
+#include "ignite/test_type.h"
 
 using namespace ignite;
 using namespace ignite::cache;
@@ -148,10 +149,10 @@ public:
         BOOST_CHECK_EQUAL(event.GetEventType(), eType);
 
         if (oldVal && event.HasOldValue())
-            BOOST_CHECK_EQUAL(event.GetOldValue().value, oldVal->value);
+            BOOST_CHECK_EQUAL(event.GetOldValue(), *oldVal);
 
         if (val && event.HasValue())
-            BOOST_CHECK_EQUAL(event.GetValue().value, val->value);
+            BOOST_CHECK_EQUAL(event.GetValue(), *val);
     }
 
     /*
@@ -249,6 +250,14 @@ struct TestEntry
         // No-op.
     }
 
+    /**
+     * Converting to int32_t.
+     */
+    operator int32_t() const
+    {
+        return value;
+    }
+
     /* Value */
     int32_t value;
 };
@@ -746,4 +755,94 @@ BOOST_AUTO_TEST_CASE(TestFilterMultipleNodes)
     lsnr.CheckNextEvent(149, boost::none, TestEntry(1490), CacheEntryEventType::CREATE);
 }
 
+BOOST_AUTO_TEST_CASE(TestJavaFilterFactory)
+{
+    Cache<int, std::string> cacheStr = node.GetCache<int, std::string>("transactional_no_backup");
+
+    Listener<int, std::string> lsnr;
+
+    JavaCacheEntryEventFilter filter("org.apache.ignite.platform.PlatformCacheEntryEventFilterFactory");
+    filter.SetProperty<std::string>("startsWith", "valid");
+
+    ContinuousQuery<int, std::string> qry(MakeReference(lsnr), filter);
+    ContinuousQueryHandle<int, std::string> handle = cacheStr.QueryContinuous(qry);
+
+    cacheStr.Put(1, "notValid");
+    cacheStr.Put(2, "validValue");
+    cacheStr.Put(3, "alsoNotValid");
+    cacheStr.Put(3, "validReplacement");
+
+    cacheStr.Remove(2);
+    cacheStr.Remove(1);
+    cacheStr.Remove(3);
+
+    lsnr.CheckNextEvent(2, boost::none, std::string("validValue"), CacheEntryEventType::CREATE);
+    lsnr.CheckNextEvent(3, std::string("alsoNotValid"), std::string("validReplacement"), CacheEntryEventType::UPDATE);
+
+    lsnr.CheckNextEvent(2, std::string("validValue"), std::string("validValue"), CacheEntryEventType::REMOVE);
+    lsnr.CheckNextEvent(3, std::string("validReplacement"), std::string("validReplacement"), CacheEntryEventType::REMOVE);
+}
+
+BOOST_AUTO_TEST_CASE(TestJavaFilter)
+{
+    Cache<int, std::string> cacheStr = node.GetCache<int, std::string>("transactional_no_backup");
+
+    Listener<int, std::string> lsnr;
+
+    JavaCacheEntryEventFilter filter("org.apache.ignite.platform.PlatformCacheEntryEventFilter");
+    filter.SetProperty<std::string>("startsWith", "valid");
+    filter.SetProperty<uint16_t>("charField", static_cast<uint16_t>('a'));
+    filter.SetProperty<int8_t>("byteField", 1);
+    filter.SetProperty<int16_t>("shortField", 3);
+    filter.SetProperty<int32_t>("intField", 5);
+    filter.SetProperty<int64_t>("longField", 7);
+    filter.SetProperty<float>("floatField", 9.99f);
+    filter.SetProperty<double>("doubleField", 10.123);
+    filter.SetProperty<bool>("boolField", true);
+    filter.SetProperty<ignite::Guid>("guidField", ignite::Guid(0x1c579241509d47c6, 0xa1a087462ae31e59));
+
+    TestType objField;
+    objField.i32Field = 1;
+    objField.strField = "2";
+    filter.SetProperty("objField", objField);
+
+    std::vector<uint16_t> charArr;
+    charArr.push_back(static_cast<uint16_t>('a'));
+    filter.SetProperty("charArr", charArr);
+
+    std::vector<int8_t> byteArr;
+    charArr.push_back(1);
+    filter.SetProperty("byteArr", byteArr);
+
+    std::vector<int16_t> shortArr;
+    charArr.push_back(3);
+    filter.SetProperty("shortArr", shortArr);
+
+    std::vector<int32_t> intArr;
+    charArr.push_back(5);
+    filter.SetProperty("intArr", intArr);
+
+    std::vector<int64_t> longArr;
+    charArr.push_back(7);
+    filter.SetProperty("longArr", longArr);
+
+    ContinuousQuery<int, std::string> qry(MakeReference(lsnr), filter);
+    ContinuousQueryHandle<int, std::string> handle = cacheStr.QueryContinuous(qry);
+
+    cacheStr.Put(1, "notValid");
+    cacheStr.Put(2, "validValue");
+    cacheStr.Put(3, "alsoNotValid");
+    cacheStr.Put(3, "validReplacement");
+
+    cacheStr.Remove(2);
+    cacheStr.Remove(1);
+    cacheStr.Remove(3);
+
+    lsnr.CheckNextEvent(2, boost::none, std::string("validValue"), CacheEntryEventType::CREATE);
+    lsnr.CheckNextEvent(3, std::string("alsoNotValid"), std::string("validReplacement"), CacheEntryEventType::UPDATE);
+
+    lsnr.CheckNextEvent(2, std::string("validValue"), std::string("validValue"), CacheEntryEventType::REMOVE);
+    lsnr.CheckNextEvent(3, std::string("validReplacement"), std::string("validReplacement"), CacheEntryEventType::REMOVE);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/platforms/cpp/core/include/ignite/cache/event/java_cache_entry_event_filter.h b/modules/platforms/cpp/core/include/ignite/cache/event/java_cache_entry_event_filter.h
new file mode 100644
index 00000000000..efc24bee2c8
--- /dev/null
+++ b/modules/platforms/cpp/core/include/ignite/cache/event/java_cache_entry_event_filter.h
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * Declares ignite::cache::event::JavaCacheEntryEventFilter class.
+ */
+
+#ifndef _IGNITE_CACHE_EVENT_JAVA_CACHE_ENTRY_EVENT_FILTER
+#define _IGNITE_CACHE_EVENT_JAVA_CACHE_ENTRY_EVENT_FILTER
+
+#include <ignite/cache/event/cache_entry_event.h>
+
+#include <ignite/impl/platform_java_object_factory_proxy.h>
+#include <ignite/impl/writable_object.h>
+#include <ignite/impl/cache/event/cache_entry_event_filter_base.h>
+
+namespace ignite
+{
+    namespace impl
+    {
+        namespace cache
+        {
+            namespace event
+            {
+                class JavaCacheEntryEventFilterHolder;
+            }
+        }
+    }
+
+    namespace cache
+    {
+        namespace event
+        {
+            /**
+             * Java cache entry event filter.
+             *
+             * All templated types should be default-constructable,
+             * copy-constructable and assignable.
+             */
+            class JavaCacheEntryEventFilter
+            {
+                friend class ignite::impl::cache::event::JavaCacheEntryEventFilterHolder;
+            public:
+                /**
+                 * Default constructor.
+                 */
+                JavaCacheEntryEventFilter()
+                {
+                    // No-op.
+                }
+
+                /**
+                 * Constructor.
+                 *
+                 * @param factoryClassName Name of the Java factory class.
+                 */
+                JavaCacheEntryEventFilter(const std::string& factoryClassName) :
+                    factory(new impl::PlatformJavaObjectFactoryProxy(impl::FactoryType::USER, factoryClassName))
+                {
+                    // No-op.
+                }
+
+                /**
+                 * Destructor.
+                 */
+                virtual ~JavaCacheEntryEventFilter()
+                {
+                    // No-op.
+                }
+
+                /**
+                 * Get Java remote filter factory class name.
+                 *
+                 * @return Java factory class name.
+                 */
+                const std::string& GetFactoryClassName() const
+                {
+                    return factory.Get()->GetFactoryClassName();
+                }
+
+                /**
+                 * Add property.
+                 *
+                 * Template argument type should be copy-constructable and assignable. Also BinaryType class template
+                 * should be specialized for this type.
+                 *
+                 * @param name Property name.
+                 * @param value Property value.
+                 */
+                template<typename T>
+                void SetProperty(const std::string& name, const T& value)
+                {
+                    factory.Get()->template SetProperty<T>(name, value);
+                }
+
+                /**
+                 * Clear set properties.
+                 * Set properties for the filter to empty set.
+                 */
+                void ClearProperties()
+                {
+                    factory.Get()->ClearProperties();
+                }
+
+            private:
+                /** Java object factory proxy. */
+                impl::SP_PlatformJavaObjectFactoryProxy factory;
+            };
+        }
+    }
+}
+
+#endif //_IGNITE_CACHE_EVENT_JAVA_CACHE_ENTRY_EVENT_FILTER
\ No newline at end of file
diff --git a/modules/platforms/cpp/core/include/ignite/cache/query/continuous/continuous_query.h b/modules/platforms/cpp/core/include/ignite/cache/query/continuous/continuous_query.h
index 0c1146b423e..c18180c88cf 100644
--- a/modules/platforms/cpp/core/include/ignite/cache/query/continuous/continuous_query.h
+++ b/modules/platforms/cpp/core/include/ignite/cache/query/continuous/continuous_query.h
@@ -27,6 +27,7 @@
 
 #include <ignite/cache/event/cache_entry_event_listener.h>
 #include <ignite/cache/event/cache_entry_event_filter.h>
+#include <ignite/cache/event/java_cache_entry_event_filter.h>
 
 namespace ignite
 {
@@ -134,6 +135,35 @@ namespace ignite
                         // No-op.
                     }
 
+                    /**
+                     * Constructor.
+                     *
+                     * @param lsnr Event listener. Invoked on the node where
+                     *     continuous query execution has been started.
+                     * @param remoteFilter Java remote filter.
+                     */
+                    ContinuousQuery(Reference<event::CacheEntryEventListener<K, V> > lsnr,
+                                    const event::JavaCacheEntryEventFilter& remoteFilter) :
+                            impl(new impl::cache::query::continuous::ContinuousQueryImpl<K, V>(lsnr, false, remoteFilter))
+                    {
+                        // No-op.
+                    }
+
+                    /**
+                     * Constructor.
+                     *
+                     * @param lsnr Event listener Invoked on the node where
+                     *     continuous query execution has been started.
+                     * @param remoteFilter Java remote filter.
+                     * @param loc Whether query should be executed locally.
+                     */
+                    ContinuousQuery(Reference<event::CacheEntryEventListener<K, V> > lsnr,
+                                    const event::JavaCacheEntryEventFilter& remoteFilter, bool loc) :
+                            impl(new impl::cache::query::continuous::ContinuousQueryImpl<K, V>(lsnr, loc, remoteFilter))
+                    {
+                        // No-op.
+                    }
+
                     /**
                      * Set local flag.
                      *
diff --git a/modules/platforms/cpp/core/include/ignite/cache/query/query_sql.h b/modules/platforms/cpp/core/include/ignite/cache/query/query_sql.h
index 46c0a98a2a0..2dbd0a0fd1c 100644
--- a/modules/platforms/cpp/core/include/ignite/cache/query/query_sql.h
+++ b/modules/platforms/cpp/core/include/ignite/cache/query/query_sql.h
@@ -27,7 +27,7 @@
 #include <string>
 #include <vector>
 
-#include <ignite/impl/cache/query/query_argument.h>
+#include <ignite/impl/writable_object.h>
 #include <ignite/binary/binary_raw_writer.h>
 
 namespace ignite
@@ -76,7 +76,7 @@ namespace ignite
                 {
                     args.reserve(other.args.size());
 
-                    typedef std::vector<impl::cache::query::QueryArgumentBase*>::const_iterator Iter;
+                    typedef std::vector<impl::WritableObjectBase*>::const_iterator Iter;
 
                     for (Iter i = other.args.begin(); i != other.args.end(); ++i)
                         args.push_back((*i)->Copy());
@@ -104,7 +104,7 @@ namespace ignite
                  */
                 ~SqlQuery()
                 {
-                    typedef std::vector<impl::cache::query::QueryArgumentBase*>::const_iterator Iter;
+                    typedef std::vector<impl::WritableObjectBase*>::const_iterator Iter;
 
                     for (Iter it = args.begin(); it != args.end(); ++it)
                         delete *it;
@@ -245,7 +245,7 @@ namespace ignite
                 template<typename T>
                 void AddArgument(const T& arg)
                 {
-                    args.push_back(new impl::cache::query::QueryArgument<T>(arg));
+                    args.push_back(new impl::WritableObject<T>(arg));
                 }
 
                 /**
@@ -253,7 +253,7 @@ namespace ignite
                  */
                 void ClearArguments()
                 {
-                    std::vector<impl::cache::query::QueryArgumentBase*>::iterator iter;
+                    std::vector<impl::WritableObjectBase*>::iterator iter;
                     for (iter = args.begin(); iter != args.end(); ++iter)
                         delete *iter;
 
@@ -274,7 +274,7 @@ namespace ignite
 
                     writer.WriteInt32(static_cast<int32_t>(args.size()));
 
-                    std::vector<impl::cache::query::QueryArgumentBase*>::const_iterator it;
+                    std::vector<impl::WritableObjectBase*>::const_iterator it;
 
                     for (it = args.begin(); it != args.end(); ++it)
                         (*it)->Write(writer);
@@ -301,7 +301,7 @@ namespace ignite
                 bool distributedJoins;
 
                 /** Arguments. */
-                std::vector<impl::cache::query::QueryArgumentBase*> args;
+                std::vector<impl::WritableObjectBase*> args;
             };
         }
     }    
diff --git a/modules/platforms/cpp/core/include/ignite/cache/query/query_sql_fields.h b/modules/platforms/cpp/core/include/ignite/cache/query/query_sql_fields.h
index 8da9bedaa7b..0f90efb8194 100644
--- a/modules/platforms/cpp/core/include/ignite/cache/query/query_sql_fields.h
+++ b/modules/platforms/cpp/core/include/ignite/cache/query/query_sql_fields.h
@@ -27,7 +27,7 @@
 #include <string>
 #include <vector>
 
-#include <ignite/impl/cache/query/query_argument.h>
+#include <ignite/impl/writable_object.h>
 #include <ignite/binary/binary_raw_writer.h>
 
 namespace ignite
@@ -96,7 +96,7 @@ namespace ignite
                 {
                     args.reserve(other.args.size());
 
-                    typedef std::vector<impl::cache::query::QueryArgumentBase*>::const_iterator Iter;
+                    typedef std::vector<impl::WritableObjectBase*>::const_iterator Iter;
 
                     for (Iter i = other.args.begin(); i != other.args.end(); ++i)
                         args.push_back((*i)->Copy());
@@ -124,7 +124,7 @@ namespace ignite
                  */
                 ~SqlFieldsQuery()
                 {
-                    typedef std::vector<impl::cache::query::QueryArgumentBase*>::const_iterator Iter;
+                    typedef std::vector<impl::WritableObjectBase*>::const_iterator Iter;
 
                     for (Iter it = args.begin(); it != args.end(); ++it)
                         delete *it;
@@ -305,7 +305,7 @@ namespace ignite
                 template<typename T>
                 void AddArgument(const T& arg)
                 {
-                    args.push_back(new impl::cache::query::QueryArgument<T>(arg));
+                    args.push_back(new impl::WritableObject<T>(arg));
                 }
 
                 /**
@@ -316,7 +316,7 @@ namespace ignite
                  */
                 void AddInt8ArrayArgument(const int8_t* src, int32_t len)
                 {
-                    args.push_back(new impl::cache::query::QueryInt8ArrayArgument(src, len));
+                    args.push_back(new impl::WritableObjectInt8Array(src, len));
                 }
 
                 /**
@@ -324,7 +324,7 @@ namespace ignite
                  */
                 void ClearArguments()
                 {
-                    std::vector<impl::cache::query::QueryArgumentBase*>::iterator iter;
+                    std::vector<impl::WritableObjectBase*>::iterator iter;
                     for (iter = args.begin(); iter != args.end(); ++iter)
                         delete *iter;
 
@@ -369,7 +369,7 @@ namespace ignite
 
                     writer.WriteInt32(static_cast<int32_t>(args.size()));
 
-                    std::vector<impl::cache::query::QueryArgumentBase*>::const_iterator it;
+                    std::vector<impl::WritableObjectBase*>::const_iterator it;
 
                     for (it = args.begin(); it != args.end(); ++it)
                         (*it)->Write(writer);
@@ -413,7 +413,7 @@ namespace ignite
                 bool lazy;
 
                 /** Arguments. */
-                std::vector<impl::cache::query::QueryArgumentBase*> args;
+                std::vector<impl::WritableObjectBase*> args;
             };
         }
     }    
diff --git a/modules/platforms/cpp/core/include/ignite/impl/cache/event/cache_entry_event_filter_holder.h b/modules/platforms/cpp/core/include/ignite/impl/cache/event/cache_entry_event_filter_holder.h
index 4256f2bd761..6ed1693083c 100644
--- a/modules/platforms/cpp/core/include/ignite/impl/cache/event/cache_entry_event_filter_holder.h
+++ b/modules/platforms/cpp/core/include/ignite/impl/cache/event/cache_entry_event_filter_holder.h
@@ -20,6 +20,8 @@
 
 #include <ignite/reference.h>
 
+#include <ignite/cache/event/java_cache_entry_event_filter.h>
+
 namespace ignite
 {
     namespace impl
@@ -177,6 +179,62 @@ namespace ignite
                         return 0;
                     }
                 };
+
+                class JavaCacheEntryEventFilterHolder : public CacheEntryEventFilterHolderBase
+                {
+                public:
+                    /**
+                     * Default constructor.
+                     */
+                    JavaCacheEntryEventFilterHolder()
+                    {
+                        // No-op.
+                    }
+
+                    /**
+                     * Constructor.
+                     */
+                    JavaCacheEntryEventFilterHolder(const ignite::cache::event::JavaCacheEntryEventFilter& filter) :
+                        filter(filter)
+                    {
+                        // No-op.
+                    }
+
+                    /**
+                     * Destructor.
+                     */
+                    virtual ~JavaCacheEntryEventFilterHolder()
+                    {
+                        // No-op.
+                    }
+
+                    /**
+                     * Process input.
+                     *
+                     * @param writer Writer.
+                     */
+                    virtual void Write(binary::BinaryWriterImpl& writer)
+                    {
+                        writer.WriteBool(true);
+                        writer.WriteObject<impl::PlatformJavaObjectFactoryProxy>(*filter.factory.Get());
+                    }
+
+                    /**
+                     * Get filter pointer.
+                     *
+                     * @return Filter.
+                     */
+                    virtual CacheEntryEventFilterBase* GetFilter()
+                    {
+                        // We can not return Java object to C++ code.
+                        // This call should never be called on C++ side.
+                        return 0;
+                    }
+
+                private:
+                    /** Remote Java filter. */
+                    ignite::cache::event::JavaCacheEntryEventFilter filter;
+                };
             }
         }
     }
diff --git a/modules/platforms/cpp/core/include/ignite/impl/cache/query/continuous/continuous_query_impl.h b/modules/platforms/cpp/core/include/ignite/impl/cache/query/continuous/continuous_query_impl.h
index ce1a46e080d..16678276e80 100644
--- a/modules/platforms/cpp/core/include/ignite/impl/cache/query/continuous/continuous_query_impl.h
+++ b/modules/platforms/cpp/core/include/ignite/impl/cache/query/continuous/continuous_query_impl.h
@@ -286,6 +286,7 @@ namespace ignite
                          * @param lsnr Event listener Invoked on the node where
                          *     continuous query execution has been started.
                          * @param loc Whether query should be executed locally.
+                         * @param filter Remote filter.
                          */
                         template<typename F>
                         ContinuousQueryImpl(Reference<ignite::cache::event::CacheEntryEventListener<K, V> >& lsnr,
@@ -296,6 +297,22 @@ namespace ignite
                             // No-op.
                         }
 
+                        /**
+                         * Constructor.
+                         *
+                         * @param lsnr Event listener Invoked on the node where
+                         *     continuous query execution has been started.
+                         * @param loc Whether query should be executed locally.
+                         * @param filter Remote Java filter.
+                         */
+                        ContinuousQueryImpl(Reference<ignite::cache::event::CacheEntryEventListener<K, V> >& lsnr,
+                            bool loc, const ignite::cache::event::JavaCacheEntryEventFilter& filter) :
+                            ContinuousQueryImplBase(loc, new event::JavaCacheEntryEventFilterHolder(filter)),
+                            lsnr(lsnr)
+                        {
+                            // No-op.
+                        }
+
                         /**
                          * Set cache entry event listener.
                          *
diff --git a/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_argument.h b/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_argument.h
deleted file mode 100644
index e9e7e516016..00000000000
--- a/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_argument.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * @file
- * Declares ignite::cache::query::QueryArgument class template and
- * ignite::cache::query::QueryArgumentBase interface.
- */
-
-#ifndef _IGNITE_IMPL_CACHE_QUERY_QUERY_ARGUMENT
-#define _IGNITE_IMPL_CACHE_QUERY_QUERY_ARGUMENT
-
-#include <ignite/binary/binary_raw_writer.h>
-
-namespace ignite
-{
-    namespace impl
-    {
-        namespace cache
-        {
-            namespace query
-            {
-                /**
-                 * Base class for all query arguments.
-                 */
-                class QueryArgumentBase
-                {
-                public:
-                    /**
-                     * Destructor.
-                     */
-                    virtual ~QueryArgumentBase()
-                    {
-                        // No-op.
-                    }
-
-                    /**
-                     * Copy argument.
-                     *
-                     * @return Copy of this argument instance.
-                     */
-                    virtual QueryArgumentBase* Copy() const = 0;
-
-                    /**
-                     * Write argument using provided writer.
-                     *
-                     * @param writer Writer to use to write this argument.
-                     */
-                    virtual void Write(ignite::binary::BinaryRawWriter& writer) = 0;
-                };
-
-                /**
-                 * Query argument class template.
-                 *
-                 * Template argument type should be copy-constructable and
-                 * assignable. Also BinaryType class template should be specialized
-                 * for this type.
-                 */
-                template<typename T>
-                class QueryArgument : public QueryArgumentBase
-                {
-                public:
-                    /**
-                     * Constructor.
-                     *
-                     * @param val Value.
-                     */
-                    QueryArgument(const T& val) :
-                        val(val)
-                    {
-                        // No-op.
-                    }
-
-                    /**
-                     * Copy constructor.
-                     *
-                     * @param other Other instance.
-                     */
-                    QueryArgument(const QueryArgument& other) :
-                        val(other.val)
-                    {
-                        // No-op.
-                    }
-
-                    /**
-                     * Assignment operator.
-                     *
-                     * @param other Other instance.
-                     * @return *this.
-                     */
-                    QueryArgument& operator=(const QueryArgument& other)
-                    {
-                        if (this != &other)
-                            val = other.val;
-
-                        return *this;
-                    }
-
-                    virtual ~QueryArgument()
-                    {
-                        // No-op.
-                    }
-
-                    virtual QueryArgumentBase* Copy() const
-                    {
-                        return new QueryArgument(val);
-                    }
-
-                    virtual void Write(ignite::binary::BinaryRawWriter& writer)
-                    {
-                        writer.WriteObject<T>(val);
-                    }
-
-                private:
-                    /** Value. */
-                    T val;
-                };
-
-                /**
-                 * Query bytes array argument class.
-                 */
-                class QueryInt8ArrayArgument : public QueryArgumentBase
-                {
-                public:
-                    /**
-                     * Constructor.
-                     *
-                     * @param src Array.
-                     * @param len Array length.
-                     */
-                    QueryInt8ArrayArgument(const int8_t* src, int32_t len) :
-                        val(src, src + len)
-                    {
-                        // No-op.
-                    }
-
-                    /**
-                     * Copy constructor.
-                     *
-                     * @param other Other instance.
-                     */
-                    QueryInt8ArrayArgument(const QueryInt8ArrayArgument& other) :
-                        val(other.val)
-                    {
-                        // No-op.
-                    }
-
-                    /**
-                     * Assignment operator.
-                     *
-                     * @param other Other instance.
-                     * @return *this.
-                     */
-                    QueryInt8ArrayArgument& operator=(const QueryInt8ArrayArgument& other)
-                    {
-                        if (this != &other)
-                            val = other.val;
-
-                        return *this;
-                    }
-
-                    virtual ~QueryInt8ArrayArgument()
-                    {
-                        // No-op.
-                    }
-
-                    virtual QueryArgumentBase* Copy() const
-                    {
-                        return new QueryInt8ArrayArgument(*this);
-                    }
-
-                    virtual void Write(ignite::binary::BinaryRawWriter& writer)
-                    {
-                        writer.WriteInt8Array(&val[0], static_cast<int32_t>(val.size()));
-                    }
-
-                private:
-                    /** Value. */
-                    std::vector<int8_t> val;
-                };
-            }
-        }
-    }
-}
-
-#endif //_IGNITE_IMPL_CACHE_QUERY_QUERY_ARGUMENT
\ No newline at end of file
diff --git a/modules/platforms/cpp/core/include/ignite/impl/platform_java_object_factory_proxy.h b/modules/platforms/cpp/core/include/ignite/impl/platform_java_object_factory_proxy.h
new file mode 100644
index 00000000000..83e0d77c0d0
--- /dev/null
+++ b/modules/platforms/cpp/core/include/ignite/impl/platform_java_object_factory_proxy.h
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+#ifndef _IGNITE_IMPL_PLATFORM_JAVA_OBJECT_FACTORY_PROXY
+#define _IGNITE_IMPL_PLATFORM_JAVA_OBJECT_FACTORY_PROXY
+
+#include <string>
+#include <map>
+
+#include <ignite/common/common.h>
+#include <ignite/binary/binary_type.h>
+#include <ignite/binary/binary_writer.h>
+
+#include <ignite/impl/writable_object.h>
+
+namespace ignite
+{
+    namespace impl
+    {
+        /**
+         * Represents the factory type.
+         */
+        struct FactoryType
+        {
+            enum Type
+            {
+                USER = 0,
+
+                DEFAULT = 1,
+            };
+        };
+
+        /**
+         * Maps to PlatformJavaObjectFactoryProxy in Java.
+         */
+        class PlatformJavaObjectFactoryProxy
+        {
+            friend struct ignite::binary::BinaryType<impl::PlatformJavaObjectFactoryProxy>;
+        public:
+            /**
+             * Default constructor.
+             */
+            PlatformJavaObjectFactoryProxy()
+            {
+                // No-op.
+            }
+
+            /**
+             * Constructor.
+             *
+             * @param factoryType Factory type.
+             * @param factoryClassName Name of the Java factory class.
+             */
+            PlatformJavaObjectFactoryProxy(FactoryType::Type factoryType, const std::string& factoryClassName) :
+                factoryType(factoryType),
+                factoryClassName(factoryClassName),
+                properties()
+            {
+                // No-op.
+            }
+
+            /**
+             * Destructor.
+             */
+            virtual ~PlatformJavaObjectFactoryProxy()
+            {
+                ClearProperties();
+            }
+
+            /**
+             * Get Java factory class name.
+             *
+             * @return Java factory class name.
+             */
+            const std::string& GetFactoryClassName() const
+            {
+                return factoryClassName;
+            }
+
+            /**
+             * Add property.
+             *
+             * Template argument type should be copy-constructable and assignable. Also BinaryType class template
+             * should be specialized for this type.
+             *
+             * @param name Property name.
+             * @param value Property value.
+             */
+            template<typename T>
+            void SetProperty(const std::string& name, const T& value)
+            {
+                std::map<std::string, impl::WritableObjectBase*>::iterator it = properties.find(name);
+                std::auto_ptr< impl::WritableObject<T> > newProp(new impl::WritableObject<T>(value));
+                if (it != properties.end())
+                {
+                    delete it->second;
+                    it->second = newProp.release();
+                }
+                else
+                    properties[name] = newProp.release();
+            }
+
+            /**
+             * Clear set properties.
+             * Set properties to empty set.
+             */
+            void ClearProperties()
+            {
+                std::map<std::string, impl::WritableObjectBase*>::iterator it;
+                for (it = properties.begin(); it != properties.end(); ++it)
+                    delete it->second;
+
+                properties.clear();
+            }
+
+        private:
+            IGNITE_NO_COPY_ASSIGNMENT(PlatformJavaObjectFactoryProxy);
+
+            /** Type of the factory. */
+            FactoryType::Type factoryType;
+
+            /** Name of the Java factory class. */
+            std::string factoryClassName;
+
+            /** The properties. */
+            std::map<std::string, impl::WritableObjectBase*> properties;
+        };
+
+        typedef common::concurrent::SharedPointer<PlatformJavaObjectFactoryProxy> SP_PlatformJavaObjectFactoryProxy;
+    }
+
+    namespace binary
+    {
+        template<>
+        struct IGNITE_IMPORT_EXPORT BinaryType<impl::PlatformJavaObjectFactoryProxy> :
+            BinaryTypeDefaultAll<impl::PlatformJavaObjectFactoryProxy>
+        {
+            /**
+             * Get binary object type ID.
+             *
+             * @return Type ID.
+             */
+            static int32_t GetTypeId()
+            {
+                enum { PLATFORM_JAVA_OBJECT_FACTORY_PROXY = 99 };
+
+                return PLATFORM_JAVA_OBJECT_FACTORY_PROXY;
+            }
+
+            static void GetTypeName(std::string& dst)
+            {
+                dst = "PlatformJavaObjectFactoryProxy";
+            }
+
+            static void Write(BinaryWriter& writer, const impl::PlatformJavaObjectFactoryProxy& val)
+            {
+                ignite::binary::BinaryRawWriter rawWriter(writer.RawWriter());
+
+                rawWriter.WriteInt32(val.factoryType);
+                rawWriter.WriteString(val.factoryClassName);
+                rawWriter.WriteNull(); // Payload is not implemented for now
+
+                if (val.properties.empty())
+                {
+                    rawWriter.WriteInt32(0);
+                    return;
+                }
+
+                rawWriter.WriteInt32(static_cast<int32_t>(val.properties.size()));
+
+                std::map<std::string, impl::WritableObjectBase*>::const_iterator it;
+                for (it = val.properties.begin(); it != val.properties.end(); ++it)
+                {
+                    rawWriter.WriteString(it->first);
+                    it->second->Write(rawWriter);
+                }
+            }
+
+            static void Read(BinaryReader&, impl::PlatformJavaObjectFactoryProxy&)
+            {
+                throw IgniteError(IgniteError::IGNITE_ERR_GENERIC, "Should never be deserialized on C++ side");
+            }
+        };
+    }
+}
+
+#endif //_IGNITE_IMPL_PLATFORM_JAVA_OBJECT_FACTORY_PROXY
diff --git a/modules/platforms/cpp/core/include/ignite/impl/writable_object.h b/modules/platforms/cpp/core/include/ignite/impl/writable_object.h
new file mode 100644
index 00000000000..542b0cbd322
--- /dev/null
+++ b/modules/platforms/cpp/core/include/ignite/impl/writable_object.h
@@ -0,0 +1,194 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file
+ * Declares ignite::cache::query::WritableObject class template and
+ * ignite::cache::query::WritableObjectBase interface.
+ */
+
+#ifndef _IGNITE_IMPL_WRITABLE_OBJECT
+#define _IGNITE_IMPL_WRITABLE_OBJECT
+
+#include <ignite/binary/binary_raw_writer.h>
+
+namespace ignite
+{
+    namespace impl
+    {
+        /**
+         * Base class for all writable objects.
+         */
+        class WritableObjectBase
+        {
+        public:
+            /**
+             * Destructor.
+             */
+            virtual ~WritableObjectBase()
+            {
+                // No-op.
+            }
+
+            /**
+             * Copy argument.
+             *
+             * @return Copy of this argument instance.
+             */
+            virtual WritableObjectBase* Copy() const = 0;
+
+            /**
+             * Write argument using provided writer.
+             *
+             * @param writer Writer to use to write this argument.
+             */
+            virtual void Write(ignite::binary::BinaryRawWriter& writer) = 0;
+        };
+
+        /**
+         * Writable object class template.
+         *
+         * Template argument type should be copy-constructable and
+         * assignable. Also BinaryType class template should be specialized
+         * for this type.
+         */
+        template<typename T>
+        class WritableObject : public WritableObjectBase
+        {
+        public:
+            /**
+             * Constructor.
+             *
+             * @param val Value.
+             */
+            WritableObject(const T& val) :
+                val(val)
+            {
+                // No-op.
+            }
+
+            /**
+             * Copy constructor.
+             *
+             * @param other Other instance.
+             */
+            WritableObject(const WritableObject& other) :
+                val(other.val)
+            {
+                // No-op.
+            }
+
+            /**
+             * Assignment operator.
+             *
+             * @param other Other instance.
+             * @return *this.
+             */
+            WritableObject& operator=(const WritableObject& other)
+            {
+                if (this != &other)
+                    val = other.val;
+
+                return *this;
+            }
+
+            virtual ~WritableObject()
+            {
+                // No-op.
+            }
+
+            virtual WritableObjectBase* Copy() const
+            {
+                return new WritableObject(val);
+            }
+
+            virtual void Write(ignite::binary::BinaryRawWriter& writer)
+            {
+                writer.WriteObject<T>(val);
+            }
+
+        private:
+            /** Value. */
+            T val;
+        };
+
+        /**
+         * Writable object specialization for the bytes array.
+         */
+        class WritableObjectInt8Array : public WritableObjectBase
+        {
+        public:
+            /**
+             * Constructor.
+             *
+             * @param src Array.
+             * @param len Array length.
+             */
+            WritableObjectInt8Array(const int8_t* src, int32_t len) :
+                val(src, src + len)
+            {
+                // No-op.
+            }
+
+            /**
+             * Copy constructor.
+             *
+             * @param other Other instance.
+             */
+            WritableObjectInt8Array(const WritableObjectInt8Array& other) :
+                val(other.val)
+            {
+                // No-op.
+            }
+
+            /**
+             * Assignment operator.
+             *
+             * @param other Other instance.
+             * @return *this.
+             */
+            WritableObjectInt8Array& operator=(const WritableObjectInt8Array& other)
+            {
+                if (this != &other)
+                    val = other.val;
+
+                return *this;
+            }
+
+            virtual ~WritableObjectInt8Array()
+            {
+                // No-op.
+            }
+
+            virtual WritableObjectBase* Copy() const
+            {
+                return new WritableObjectInt8Array(*this);
+            }
+
+            virtual void Write(ignite::binary::BinaryRawWriter& writer)
+            {
+                writer.WriteInt8Array(&val[0], static_cast<int32_t>(val.size()));
+            }
+
+        private:
+            /** Value. */
+            std::vector<int8_t> val;
+        };
+    }
+}
+
+#endif //_IGNITE_IMPL_WRITABLE_OBJECT
\ No newline at end of file
diff --git a/modules/platforms/cpp/core/src/impl/cache/cache_impl.cpp b/modules/platforms/cpp/core/src/impl/cache/cache_impl.cpp
index 88ab345ebbe..71f0e785e03 100644
--- a/modules/platforms/cpp/core/src/impl/cache/cache_impl.cpp
+++ b/modules/platforms/cpp/core/src/impl/cache/cache_impl.cpp
@@ -467,10 +467,10 @@ namespace ignite
                 rawWriter.WriteInt32(qry0.GetBufferSize());
                 rawWriter.WriteInt64(qry0.GetTimeInterval());
 
-                // Autounsubscribe is a filter feature.
+                // Auto-unsubscribe is a filter feature.
                 rawWriter.WriteBool(false);
 
-                // Writing initial query. When there is not initial query writing -1.
+                // Writing initial query. When there is no initial query writing -1.
                 rawWriter.WriteInt32(typ);
                 if (typ != -1)
                     initialQry.Write(rawWriter);