Return-Path: X-Original-To: apmail-ignite-commits-archive@minotaur.apache.org Delivered-To: apmail-ignite-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 3372E19DDD for ; Thu, 28 Apr 2016 13:01:47 +0000 (UTC) Received: (qmail 74967 invoked by uid 500); 28 Apr 2016 13:01:47 -0000 Delivered-To: apmail-ignite-commits-archive@ignite.apache.org Received: (qmail 74851 invoked by uid 500); 28 Apr 2016 13:01:47 -0000 Mailing-List: contact commits-help@ignite.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.apache.org Delivered-To: mailing list commits@ignite.apache.org Received: (qmail 74136 invoked by uid 99); 28 Apr 2016 13:01:46 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 28 Apr 2016 13:01:46 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 0FC7CDFE04; Thu, 28 Apr 2016 13:01:46 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: sboikov@apache.org To: commits@ignite.apache.org Date: Thu, 28 Apr 2016 13:02:01 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [17/35] ignite git commit: IGNITE-2977: .NET: Added ability to use Java filter in .NET continuous queries. This closes #668. IGNITE-2977: .NET: Added ability to use Java filter in .NET continuous queries. This closes #668. Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/4d99d9ee Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/4d99d9ee Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/4d99d9ee Branch: refs/heads/ignite-db-x-10884 Commit: 4d99d9eef35b4b08e19d38e15718bf8f99d66246 Parents: 3be3d16 Author: Pavel Tupitsyn Authored: Wed Apr 27 11:22:13 2016 +0300 Committer: vozerov-gridgain Committed: Wed Apr 27 11:22:13 2016 +0300 ---------------------------------------------------------------------- .../ignite/internal/binary/BinaryContext.java | 4 + .../internal/binary/GridBinaryMarshaller.java | 3 + .../PlatformDefaultJavaObjectFactory.java | 62 ++++ .../platform/PlatformJavaObjectFactoryEx.java | 36 +++ .../PlatformJavaObjectFactoryProxy.java | 192 +++++++++++ .../PlatformJavaObjectSingletonFactory.java | 48 +++ .../query/PlatformContinuousQueryImpl.java | 50 ++- .../platform/utils/PlatformUtils.java | 69 ++++ .../ignite/internal/util/IgniteUtils.java | 5 +- .../platform/PlatformJavaObjectFactory.java | 36 +++ .../platform/PlatformCacheEntryEventFilter.java | 193 +++++++++++ .../PlatformCacheEntryEventFilterFactory.java | 59 ++++ ...latformDefaultJavaObjectFactorySelfTest.java | 185 +++++++++++ .../PlatformJavaObjectFactoryProxySelfTest.java | 220 +++++++++++++ .../platform/PlatformStartIgniteTask.java | 1 + .../ignite/platform/PlatformStopIgniteTask.java | 1 + .../platform/javaobject/TestJavaObject.java | 271 ++++++++++++++++ .../javaobject/TestJavaObjectNoDefaultCtor.java | 49 +++ .../TestJavaObjectNoDefaultCtorFactory.java | 68 ++++ .../ignite/testsuites/IgniteBasicTestSuite.java | 2 + .../testsuites/IgnitePlatformsTestSuite.java | 41 +++ .../Apache.Ignite.Core.Tests.csproj | 1 + .../Cache/Query/CacheLinqTest.cs | 2 - .../Continuous/ContinuousQueryJavaFilterTest.cs | 323 +++++++++++++++++++ .../Apache.Ignite.Core.csproj | 11 +- .../Continuous/ContinuousQueryExtensions.cs | 42 +++ .../Impl/Binary/BinaryUtils.cs | 3 + .../Impl/Binary/Marshaller.cs | 2 + .../Cache/Event/JavaCacheEntryEventFilter.cs | 49 +++ .../Continuous/ContinuousQueryHandleImpl.cs | 17 +- .../Common/PlatformJavaObjectFactoryProxy.cs | 106 ++++++ .../Apache.Ignite.Core/Interop/JavaObject.cs | 80 +++++ 32 files changed, 2218 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java index 4d8c293..8754795 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java @@ -83,6 +83,7 @@ import org.apache.ignite.internal.processors.igfs.meta.IgfsMetaFileReserveSpaceP import org.apache.ignite.internal.processors.igfs.meta.IgfsMetaFileUnlockProcessor; import org.apache.ignite.internal.processors.igfs.meta.IgfsMetaUpdatePropertiesProcessor; import org.apache.ignite.internal.processors.igfs.meta.IgfsMetaUpdateTimesProcessor; +import org.apache.ignite.internal.processors.platform.PlatformJavaObjectFactoryProxy; import org.apache.ignite.internal.util.IgniteUtils; import org.apache.ignite.internal.util.lang.GridMapEntry; import org.apache.ignite.internal.util.typedef.F; @@ -275,6 +276,9 @@ public class BinaryContext { registerPredefinedType(IgniteBiTuple.class, 61); registerPredefinedType(T2.class, 62); + registerPredefinedType(PlatformJavaObjectFactoryProxy.class, + GridBinaryMarshaller.PLATFORM_JAVA_OBJECT_FACTORY_PROXY); + registerPredefinedType(BinaryObjectImpl.class, 0); registerPredefinedType(BinaryObjectOffheapImpl.class, 0); registerPredefinedType(BinaryMetadataKey.class, 0); http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java index 00d8871..ad63521 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java @@ -181,6 +181,9 @@ public class GridBinaryMarshaller { public static final byte LINKED_HASH_MAP = 2; /** */ + public static final byte PLATFORM_JAVA_OBJECT_FACTORY_PROXY = 99; + + /** */ public static final int OBJECT_TYPE_ID = -1; /** */ http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformDefaultJavaObjectFactory.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformDefaultJavaObjectFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformDefaultJavaObjectFactory.java new file mode 100644 index 0000000..011088c --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformDefaultJavaObjectFactory.java @@ -0,0 +1,62 @@ +/* + * 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; + +import org.apache.ignite.IgniteException; +import org.apache.ignite.internal.processors.platform.utils.PlatformUtils; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +/** + * Default Java object factory implementation. + */ +public class PlatformDefaultJavaObjectFactory implements PlatformJavaObjectFactoryEx { + /** Class name. */ + private String clsName; + + /** Properties. */ + private Map props; + + /** {@inheritDoc} */ + @Override public void initialize(@Nullable Object payload, @Nullable Map props) { + if (payload == null) + throw new IgniteException("Java object class name is not provided."); + + assert payload instanceof String; + + clsName = (String)payload; + + this.props = props; + } + + /** {@inheritDoc} */ + @Override public T create() { + T res = PlatformUtils.createJavaObject(clsName); + + PlatformUtils.initializeJavaObject(res, clsName, props, null); + + return res; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(PlatformDefaultJavaObjectFactory.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformJavaObjectFactoryEx.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformJavaObjectFactoryEx.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformJavaObjectFactoryEx.java new file mode 100644 index 0000000..9c56e34 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformJavaObjectFactoryEx.java @@ -0,0 +1,36 @@ +/* + * 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; + +import org.apache.ignite.platform.PlatformJavaObjectFactory; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +/** + * Extended Java object factory interface to handle special cases. + */ +public interface PlatformJavaObjectFactoryEx extends PlatformJavaObjectFactory { + /** + * Initialize factory. + * + * @param payload Optional payload. + * @param props Optional properties. + */ + public void initialize(@Nullable Object payload, @Nullable Map props); +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformJavaObjectFactoryProxy.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformJavaObjectFactoryProxy.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformJavaObjectFactoryProxy.java new file mode 100644 index 0000000..cdf553b --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformJavaObjectFactoryProxy.java @@ -0,0 +1,192 @@ +/* + * 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; + +import org.apache.ignite.IgniteException; +import org.apache.ignite.binary.BinaryObjectException; +import org.apache.ignite.binary.BinaryReader; +import org.apache.ignite.binary.BinaryWriter; +import org.apache.ignite.binary.Binarylizable; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.binary.BinaryRawReaderEx; +import org.apache.ignite.internal.binary.BinaryRawWriterEx; +import org.apache.ignite.internal.processors.platform.utils.PlatformUtils; +import org.apache.ignite.internal.util.tostring.GridToStringExclude; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.platform.PlatformJavaObjectFactory; +import org.jetbrains.annotations.Nullable; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.HashMap; +import java.util.Map; + +/** + * Wrapper for Java object factory. + */ +public class PlatformJavaObjectFactoryProxy implements Externalizable, Binarylizable { + /** */ + private static final long serialVersionUID = 0L; + + /** User-defined type. */ + public static final int TYP_USER = 0; + + /** Default factory. */ + public static final int TYP_DEFAULT = 1; + + /** Factory type. */ + private int factoryTyp; + + /** Class name. */ + private String clsName; + + /** Optional payload for special factory types. */ + @GridToStringExclude + private Object payload; + + /** Properties. */ + @GridToStringExclude + private Map props; + + /** + * Default constructor. + */ + public PlatformJavaObjectFactoryProxy() { + // No-op. + } + + /** + * Constructor. + * + * @param factoryTyp Factory type. + * @param clsName Class name. + * @param payload Payload. + * @param props Properties. + */ + public PlatformJavaObjectFactoryProxy(int factoryTyp, @Nullable String clsName, @Nullable Object payload, + @Nullable Map props) { + this.factoryTyp = factoryTyp; + this.clsName = clsName; + this.payload = payload; + this.props = props; + } + + /** + * Get factory instance. + * + * @param ctx Kernal context for injections. + * @return Factory instance. + */ + public PlatformJavaObjectFactory factory(GridKernalContext ctx) { + // Create factory. + Object res; + + switch (factoryTyp) { + case TYP_DEFAULT: + res = new PlatformDefaultJavaObjectFactory(); + + break; + + case TYP_USER: + res = PlatformUtils.createJavaObject(clsName); + + break; + + default: + throw new IgniteException("Unsupported Java object factory type: " + factoryTyp); + } + + // Initialize factory. + if (res instanceof PlatformJavaObjectFactoryEx) + ((PlatformJavaObjectFactoryEx)res).initialize(payload, props); + else { + PlatformUtils.initializeJavaObject(res, clsName, props, ctx); + + if (!(res instanceof PlatformJavaObjectFactory)) + res = new PlatformJavaObjectSingletonFactory<>(res); + } + + return (PlatformJavaObjectFactory)res; + } + + /** {@inheritDoc} */ + @Override public void writeBinary(BinaryWriter writer) throws BinaryObjectException { + BinaryRawWriterEx rawWriter = (BinaryRawWriterEx)writer.rawWriter(); + + rawWriter.writeInt(factoryTyp); + rawWriter.writeString(clsName); + rawWriter.writeObjectDetached(payload); + + if (props != null) { + rawWriter.writeInt(props.size()); + + for (Map.Entry prop : props.entrySet()) { + rawWriter.writeString(prop.getKey()); + rawWriter.writeObjectDetached(prop.getValue()); + } + } + else + rawWriter.writeInt(0); + } + + /** {@inheritDoc} */ + @Override public void readBinary(BinaryReader reader) throws BinaryObjectException { + BinaryRawReaderEx rawReader = (BinaryRawReaderEx)reader.rawReader(); + + factoryTyp = rawReader.readInt(); + clsName = rawReader.readString(); + payload = rawReader.readObjectDetached(); + + int propsSize = rawReader.readInt(); + + if (propsSize > 0) { + props = new HashMap<>(propsSize); + + for (int i = 0; i < propsSize; i++) { + String key = rawReader.readString(); + Object val = rawReader.readObjectDetached(); + + props.put(key, val); + } + } + } + + /** {@inheritDoc} */ + @Override public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(factoryTyp); + U.writeString(out, clsName); + out.writeObject(payload); + U.writeMap(out, props); + } + + /** {@inheritDoc} */ + @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + factoryTyp = in.readInt(); + clsName = U.readString(in); + payload = in.readObject(); + props = U.readMap(in); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(PlatformJavaObjectFactoryProxy.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformJavaObjectSingletonFactory.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformJavaObjectSingletonFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformJavaObjectSingletonFactory.java new file mode 100644 index 0000000..165b7d1 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformJavaObjectSingletonFactory.java @@ -0,0 +1,48 @@ +/* + * 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; + +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.platform.PlatformJavaObjectFactory; + +/** + * Singleton factory. + */ +public class PlatformJavaObjectSingletonFactory implements PlatformJavaObjectFactory { + /** Instance. */ + private final T instance; + + /** + * Constructor. + * + * @param instance Instance. + */ + public PlatformJavaObjectSingletonFactory(T instance) { + this.instance = instance; + } + + /** {@inheritDoc} */ + @Override public T create() { + return instance; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(PlatformJavaObjectSingletonFactory.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/query/PlatformContinuousQueryImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/query/PlatformContinuousQueryImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/query/PlatformContinuousQueryImpl.java index 453e233..abe5b76 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/query/PlatformContinuousQueryImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/query/PlatformContinuousQueryImpl.java @@ -24,14 +24,21 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.cache.Cache; import javax.cache.event.CacheEntryEvent; +import javax.cache.event.CacheEntryEventFilter; import javax.cache.event.CacheEntryListenerException; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.IgniteException; +import org.apache.ignite.cache.CacheEntryEventSerializableFilter; import org.apache.ignite.cache.query.ContinuousQuery; import org.apache.ignite.cache.query.Query; import org.apache.ignite.cache.query.QueryCursor; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.binary.BinaryObjectImpl; +import org.apache.ignite.internal.binary.GridBinaryMarshaller; import org.apache.ignite.internal.processors.cache.IgniteCacheProxy; import org.apache.ignite.internal.processors.cache.query.QueryCursorEx; import org.apache.ignite.internal.processors.platform.PlatformContext; +import org.apache.ignite.internal.processors.platform.PlatformJavaObjectFactoryProxy; import org.apache.ignite.internal.processors.platform.PlatformTarget; import org.apache.ignite.internal.processors.platform.utils.PlatformUtils; import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata; @@ -52,6 +59,9 @@ public class PlatformContinuousQueryImpl implements PlatformContinuousQuery { /** Native filter in serialized form. If null, then filter is either not set, or this is local query. */ protected final Object filter; + /** Java filter. */ + protected final CacheEntryEventFilter javaFilter; + /** Pointer to native counterpart; zero if closed. */ private long ptr; @@ -79,6 +89,33 @@ public class PlatformContinuousQueryImpl implements PlatformContinuousQuery { this.ptr = ptr; this.hasFilter = hasFilter; this.filter = filter; + + javaFilter = getJavaFilter(filter, platformCtx.kernalContext()); + + if (javaFilter != null && !(javaFilter instanceof CacheEntryEventSerializableFilter)) + throw new IgniteException("Java event filter must implement " + + CacheEntryEventSerializableFilter.class.getName() + " interface: " + javaFilter.getClass().getName()); + } + + /** + * Gets the Java filter if present. + * + * @param filter Filter object. + * @param ctx Context. + * @return Java filter or null. + */ + private static CacheEntryEventFilter getJavaFilter(Object filter, GridKernalContext ctx) { + if (filter instanceof BinaryObjectImpl) { + BinaryObjectImpl bo = (BinaryObjectImpl)filter; + + if (bo.typeId() == GridBinaryMarshaller.PLATFORM_JAVA_OBJECT_FACTORY_PROXY) { + PlatformJavaObjectFactoryProxy prx = bo.deserialize(); + + return (CacheEntryEventFilter)prx.factory(ctx).create(); + } + } + + return null; } /** @@ -92,10 +129,8 @@ public class PlatformContinuousQueryImpl implements PlatformContinuousQuery { * @param initialQry Initial query. */ @SuppressWarnings("unchecked") - public void start(IgniteCacheProxy cache, boolean loc, int bufSize, long timeInterval, boolean autoUnsubscribe, - Query initialQry) throws IgniteCheckedException { - assert !loc || filter == null; - + @Override public void start(IgniteCacheProxy cache, boolean loc, int bufSize, long timeInterval, + boolean autoUnsubscribe, Query initialQry) throws IgniteCheckedException { lock.writeLock().lock(); try { @@ -170,7 +205,11 @@ public class PlatformContinuousQueryImpl implements PlatformContinuousQuery { } /** {@inheritDoc} */ + @SuppressWarnings("unchecked") @Override public boolean evaluate(CacheEntryEvent evt) throws CacheEntryListenerException { + if (javaFilter != null) + return javaFilter.evaluate(evt); + lock.readLock().lock(); try { @@ -230,6 +269,9 @@ public class PlatformContinuousQueryImpl implements PlatformContinuousQuery { * @throws ObjectStreamException If failed. */ Object writeReplace() throws ObjectStreamException { + if (javaFilter != null) + return javaFilter; + return filter == null ? null : platformCtx.createContinuousQueryFilter(filter); } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java index 04b1a17..b31bbd3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java @@ -55,6 +55,7 @@ import javax.cache.event.CacheEntryEvent; import javax.cache.event.CacheEntryListenerException; import java.math.BigDecimal; import java.security.Timestamp; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -920,6 +921,74 @@ public class PlatformUtils { return map0; } /** + * Create Java object. + * + * @param clsName Class name. + * @return Instance. + */ + public static T createJavaObject(String clsName) { + if (clsName == null) + throw new IgniteException("Java object/factory class name is not set."); + + Class cls = U.classForName(clsName, null); + + if (cls == null) + throw new IgniteException("Java object/factory class is not found (is it in the classpath?): " + + clsName); + + try { + return (T)cls.newInstance(); + } + catch (ReflectiveOperationException e) { + throw new IgniteException("Failed to instantiate Java object/factory class (does it have public " + + "default constructor?): " + clsName, e); + } + } + + /** + * Initialize Java object or object factory. + * + * @param obj Object. + * @param clsName Class name. + * @param props Properties (optional). + * @param ctx Kernal context (optional). + */ + public static void initializeJavaObject(Object obj, String clsName, @Nullable Map props, + @Nullable GridKernalContext ctx) { + if (props != null) { + for (Map.Entry prop : props.entrySet()) { + String fieldName = prop.getKey(); + + if (fieldName == null) + throw new IgniteException("Java object/factory field name cannot be null: " + clsName); + + Field field = U.findField(obj.getClass(), fieldName); + + if (field == null) + throw new IgniteException("Java object/factory class field is not found [" + + "className=" + clsName + ", fieldName=" + fieldName + ']'); + + try { + field.set(obj, prop.getValue()); + } + catch (Exception e) { + throw new IgniteException("Failed to set Java object/factory field [className=" + clsName + + ", fieldName=" + fieldName + ", fieldValue=" + prop.getValue() + ']', e); + } + } + } + + if (ctx != null) { + try { + ctx.resource().injectGeneric(obj); + } + catch (IgniteCheckedException e) { + throw new IgniteException("Failed to inject resources to Java factory: " + clsName, e); + } + } + } + + /** * Private constructor. */ private PlatformUtils() { http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java index 8a313cb..6958b9e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java @@ -9252,12 +9252,13 @@ public abstract class IgniteUtils { * @param name Name of a field to get. * @return Field or {@code null}. */ - @Nullable public static Field findNonPublicField(Class cls, String name) { + @Nullable public static Field findField(Class cls, String name) { while (cls != null) { try { Field fld = cls.getDeclaredField(name); - fld.setAccessible(true); + if (!fld.isAccessible()) + fld.setAccessible(true); return fld; } http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/main/java/org/apache/ignite/platform/PlatformJavaObjectFactory.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/platform/PlatformJavaObjectFactory.java b/modules/core/src/main/java/org/apache/ignite/platform/PlatformJavaObjectFactory.java new file mode 100644 index 0000000..cd97470 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/platform/PlatformJavaObjectFactory.java @@ -0,0 +1,36 @@ +/* + * 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; + +/** + * Object factory used for advanced interop between platform and Java. + *

+ * Use it when you need Java component for some Ignite feature in platform code. E.g. Java-based continuous + * query filter. + *

+ * You should implement the factory, compile it and then place it into node's classpath. Then you can reference + * the factory form platform code using it's fully-qualified Java class name. + */ +public interface PlatformJavaObjectFactory { + /** + * Constructs and returns a fully configured instance of T. + * + * @return An instance of T. + */ + public T create(); +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheEntryEventFilter.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheEntryEventFilter.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheEntryEventFilter.java new file mode 100644 index 0000000..36c22e6 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheEntryEventFilter.java @@ -0,0 +1,193 @@ +/* + * 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 org.apache.ignite.Ignite; +import org.apache.ignite.binary.BinaryObject; +import org.apache.ignite.cache.CacheEntryEventSerializableFilter; +import org.apache.ignite.resources.IgniteInstanceResource; + +import javax.cache.event.CacheEntryEvent; +import javax.cache.event.CacheEntryListenerException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.UUID; + +/** + * Test filter. + */ +@SuppressWarnings({"FieldCanBeLocal", "FloatingPointEquality", "MismatchedReadAndWriteOfArray", "unused", + "SpellCheckingInspection"}) +public class PlatformCacheEntryEventFilter 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 byte sbyteField; + + /** Property to be set from platform. */ + private short shortField; + + /** Property to be set from platform. */ + private short ushortField; + + /** Property to be set from platform. */ + private int intField; + + /** Property to be set from platform. */ + private int uintField; + + /** Property to be set from platform. */ + private long longField; + + /** Property to be set from platform. */ + private long ulongField; + + /** 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 BigDecimal decimalField; + + /** 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 byte[] sbyteArr; + + /** Property to be set from platform. */ + private short[] shortArr; + + /** Property to be set from platform. */ + private short[] ushortArr; + + /** Property to be set from platform. */ + private int[] intArr; + + /** Property to be set from platform. */ + private int[] uintArr; + + /** Property to be set from platform. */ + private long[] longArr; + + /** Property to be set from platform. */ + private long[] ulongArr; + + /** Property to be set from platform. */ + private float[] floatArr; + + /** Property to be set from platform. */ + private double[] doubleArr; + + /** Property to be set from platform. */ + private boolean[] boolArr; + + /** Property to be set from platform. */ + private Object[] objArr; + + /** Property to be set from platform. */ + private ArrayList arrayList; + + /** Property to be set from platform. */ + private HashMap hashTable; + + /** 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 sbyteField == 2; + assert shortField == 3; + assert ushortField == 4; + assert intField == 5; + assert uintField == 6; + assert longField == 7; + assert ulongField == 8; + assert floatField == (float)9.99; + assert doubleField == 10.123; + assert "11.245".equals(decimalField.toString()); + assert boolField; + assert guidField.equals(UUID.fromString("1c579241-509d-47c6-a1a0-87462ae31e59")); + + // check arrays + assert charArr[0] == 'a'; + assert byteArr[0] == 1; + assert sbyteArr[0] == 2; + assert shortArr[0] == 3; + assert ushortArr[0] == 4; + assert intArr[0] == 5; + assert uintArr[0] == 6; + assert longArr[0] == 7; + assert ulongArr[0] == 8; + assert floatArr[0] == (float)9.99; + assert doubleArr[0] == 10.123; + assert boolArr[0]; + + // check collections + assert "x".equals(arrayList.get(0)); + assert "2".equals(hashTable.get(1)); + + // check binary object + assert objField != null; + assert Integer.valueOf(1).equals(objField.field("Int")); + assert "2".equals(objField.field("String")); + + assert objArr != null; + assert objArr.length == 1; + assert Integer.valueOf(1).equals(((BinaryObject)objArr[0]).field("Int")); + assert "2".equals(((BinaryObject)objArr[0]).field("String")); + + 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); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheEntryEventFilterFactory.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheEntryEventFilterFactory.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheEntryEventFilterFactory.java new file mode 100644 index 0000000..14f2931 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheEntryEventFilterFactory.java @@ -0,0 +1,59 @@ +/* + * 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 org.apache.ignite.Ignite; +import org.apache.ignite.binary.BinaryObject; +import org.apache.ignite.cache.CacheEntryEventSerializableFilter; +import org.apache.ignite.resources.IgniteInstanceResource; + +import javax.cache.event.CacheEntryEvent; +import javax.cache.event.CacheEntryListenerException; +import java.io.Serializable; + +/** + * Test filter factory + */ +public class PlatformCacheEntryEventFilterFactory implements Serializable, + PlatformJavaObjectFactory { + /** Property to be set from platform. */ + @SuppressWarnings("FieldCanBeLocal") + private String startsWith = "-"; + + /** Injected instance. */ + @IgniteInstanceResource + private Ignite ignite; + + /** {@inheritDoc} */ + @Override public CacheEntryEventSerializableFilter create() { + assert ignite != null; + + return new CacheEntryEventSerializableFilter() { + @Override public boolean evaluate(CacheEntryEvent event) throws CacheEntryListenerException { + 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); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/test/java/org/apache/ignite/platform/PlatformDefaultJavaObjectFactorySelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformDefaultJavaObjectFactorySelfTest.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformDefaultJavaObjectFactorySelfTest.java new file mode 100644 index 0000000..45fda4f --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformDefaultJavaObjectFactorySelfTest.java @@ -0,0 +1,185 @@ +/* + * 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 org.apache.ignite.IgniteException; +import org.apache.ignite.internal.processors.platform.PlatformDefaultJavaObjectFactory; +import org.apache.ignite.platform.javaobject.TestJavaObject; +import org.apache.ignite.platform.javaobject.TestJavaObjectNoDefaultCtor; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Callable; + +/** + * Dedicated tests for {@link PlatformDefaultJavaObjectFactory}. + */ +@SuppressWarnings("ThrowableResultOfMethodCallIgnored") +public class PlatformDefaultJavaObjectFactorySelfTest extends GridCommonAbstractTest { + /** Name of the class. */ + private static final String CLS_NAME = TestJavaObject.class.getName(); + + /** Name of the class without default constructor. */ + private static final String NO_DFLT_CTOR_CLS_NAME = TestJavaObjectNoDefaultCtor.class.getName(); + + /** + * Test normal object creation. + */ + public void testNormal() { + final PlatformDefaultJavaObjectFactory factory = new PlatformDefaultJavaObjectFactory(); + + Map props = new HashMap<>(); + + props.put("fBoolean", true); + props.put("fByte", (byte)1); + props.put("fShort", (short)2); + props.put("fChar", '3'); + props.put("fInt", 4); + props.put("fLong", 5L); + props.put("fFloat", 6.6f); + props.put("fDouble", 7.7d); + + UUID obj = UUID.randomUUID(); + + props.put("fObj", obj); + + props.put("fIntBoxed", 10); + + factory.initialize(CLS_NAME, props); + + Object val = factory.create(); + + TestJavaObject expVal = new TestJavaObject().setBoolean(true).setByte((byte)1).setShort((short)2).setChar('3') + .setInt(4).setLong(5L).setFloat(6.6f).setDouble(7.7d).setObject(obj).setIntBoxed(10); + + assertEquals(expVal, val); + } + + /** + * Test object creation with boxed property. + */ + public void testBoxedProperty() { + final PlatformDefaultJavaObjectFactory factory = new PlatformDefaultJavaObjectFactory(); + + factory.initialize(CLS_NAME, Collections.singletonMap("fIntBoxed", 1)); + + Object val = factory.create(); + + assertEquals(val, new TestJavaObject().setIntBoxed(1)); + } + + /** + * Test object creation without properties. + */ + public void testNoProperties() { + final PlatformDefaultJavaObjectFactory factory = new PlatformDefaultJavaObjectFactory(); + + factory.initialize(CLS_NAME, Collections.emptyMap()); + + Object val = factory.create(); + + assertEquals(val, new TestJavaObject()); + } + + /** + * Test object creation with invalid property name. + */ + public void testInvalidPropertyName() { + final PlatformDefaultJavaObjectFactory factory = new PlatformDefaultJavaObjectFactory(); + + factory.initialize(CLS_NAME, Collections.singletonMap("invalid", 1)); + + GridTestUtils.assertThrows(null, new Callable() { + @Override public Object call() throws Exception { + return factory.create(); + } + }, IgniteException.class, null); + } + + /** + * Test object creation with invalid property value. + */ + public void testInvalidPropertyValue() { + final PlatformDefaultJavaObjectFactory factory = new PlatformDefaultJavaObjectFactory(); + + factory.initialize(CLS_NAME, Collections.singletonMap("fInt", 1L)); + + GridTestUtils.assertThrows(null, new Callable() { + @Override public Object call() throws Exception { + return factory.create(); + } + }, IgniteException.class, null); + } + + /** + * Test object creation without default constructor. + */ + public void testNoDefaultConstructor() { + final PlatformDefaultJavaObjectFactory factory = new PlatformDefaultJavaObjectFactory(); + + factory.initialize(NO_DFLT_CTOR_CLS_NAME, null); + + GridTestUtils.assertThrows(null, new Callable() { + @Override public Object call() throws Exception { + return factory.create(); + } + }, IgniteException.class, null); + } + + /** + * Test object creation with null class name. + */ + public void testNullClassName() { + final PlatformDefaultJavaObjectFactory factory = new PlatformDefaultJavaObjectFactory(); + + GridTestUtils.assertThrows(null, new Callable() { + @Override public Void call() throws Exception { + factory.initialize(null, null); + + return null; + } + }, IgniteException.class, null); + + GridTestUtils.assertThrows(null, new Callable() { + @Override public Void call() throws Exception { + factory.initialize(null, new HashMap()); + + return null; + } + }, IgniteException.class, null); + } + + /** + * Test object creation with invalid class name. + */ + public void testInvalidClassName() { + final PlatformDefaultJavaObjectFactory factory = new PlatformDefaultJavaObjectFactory(); + + factory.initialize("invalid", null); + + GridTestUtils.assertThrows(null, new Callable() { + @Override public Object call() throws Exception { + return factory.create(); + } + }, IgniteException.class, null); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/test/java/org/apache/ignite/platform/PlatformJavaObjectFactoryProxySelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformJavaObjectFactoryProxySelfTest.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformJavaObjectFactoryProxySelfTest.java new file mode 100644 index 0000000..18fb806 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformJavaObjectFactoryProxySelfTest.java @@ -0,0 +1,220 @@ +/* + * 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 org.apache.ignite.IgniteException; +import org.apache.ignite.Ignition; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.IgniteKernal; +import org.apache.ignite.internal.processors.platform.PlatformJavaObjectFactoryProxy; +import org.apache.ignite.platform.javaobject.TestJavaObject; +import org.apache.ignite.platform.javaobject.TestJavaObjectNoDefaultCtor; +import org.apache.ignite.platform.javaobject.TestJavaObjectNoDefaultCtorFactory; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Callable; + +/** + * Dedicated tests for {@link PlatformJavaObjectFactoryProxy}. + */ +@SuppressWarnings("ThrowableResultOfMethodCallIgnored") +public class PlatformJavaObjectFactoryProxySelfTest extends GridCommonAbstractTest { + /** Name of the class. */ + private static final String CLS_NAME = TestJavaObject.class.getName(); + + /** Name of the factory class to create object without default constructor. */ + private static final String NO_DFLT_CTOR_FACTORY_CLS_NAME = TestJavaObjectNoDefaultCtorFactory.class.getName(); + + /** Kernal context. */ + private GridKernalContext ctx; + + /** {@inheritDoc} */ + @Override protected void beforeTest() throws Exception { + ctx = ((IgniteKernal)Ignition.start(getConfiguration(PlatformJavaObjectFactoryProxySelfTest.class.getName()))) + .context(); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + ctx = null; + + Ignition.stopAll(true); + } + + /** + * Test normal object creation using default factory. + */ + public void testDefaultFactoryNormal() { + Map props = new HashMap<>(); + + props.put("fBoolean", true); + props.put("fByte", (byte)1); + props.put("fShort", (short)2); + props.put("fChar", '3'); + props.put("fInt", 4); + props.put("fLong", 5L); + props.put("fFloat", 6.6f); + props.put("fDouble", 7.7d); + + UUID obj = UUID.randomUUID(); + + props.put("fObj", obj); + + props.put("fIntBoxed", 10); + + PlatformJavaObjectFactoryProxy proxy = + new PlatformJavaObjectFactoryProxy(PlatformJavaObjectFactoryProxy.TYP_DEFAULT, null, CLS_NAME, props); + + TestJavaObject val = (TestJavaObject)proxy.factory(ctx).create(); + + TestJavaObject expVal = new TestJavaObject().setBoolean(true).setByte((byte)1).setShort((short)2).setChar('3') + .setInt(4).setLong(5L).setFloat(6.6f).setDouble(7.7d).setObject(obj).setIntBoxed(10); + + assertEquals(expVal, val); + } + + /** + * Test normal object creation using custom factory. + */ + public void testCustomFactoryNormal() { + Map props = new HashMap<>(); + + props.put("fBoolean", true); + props.put("fByte", (byte)1); + props.put("fShort", (short)2); + props.put("fChar", '3'); + props.put("fInt", 4); + props.put("fLong", 5L); + props.put("fFloat", 6.6f); + props.put("fDouble", 7.7d); + + UUID obj = UUID.randomUUID(); + + props.put("fObj", obj); + + props.put("fIntBoxed", 10); + + PlatformJavaObjectFactoryProxy proxy = proxyForCustom(NO_DFLT_CTOR_FACTORY_CLS_NAME, props); + + TestJavaObjectNoDefaultCtor val = (TestJavaObjectNoDefaultCtor)proxy.factory(ctx).create(); + + TestJavaObject expVal = new TestJavaObject().setBoolean(true).setByte((byte)1).setShort((short)2).setChar('3') + .setInt(4).setLong(5L).setFloat(6.6f).setDouble(7.7d).setObject(obj).setIntBoxed(10); + + assertEquals(expVal, val); + + assertNotNull(val.node); + assertEquals(val.node.name(), ctx.gridName()); + } + + /** + * Test object creation with boxed property. + */ + public void testCustomFactoryBoxedProperty() { + PlatformJavaObjectFactoryProxy proxy = proxyForCustom(NO_DFLT_CTOR_FACTORY_CLS_NAME, + Collections.singletonMap("fIntBoxed", (Object)1)); + + Object val = proxy.factory(ctx).create(); + + assertEquals(val, new TestJavaObject().setIntBoxed(1)); + } + + /** + * Test object creation without properties. + */ + public void testCustomFactoryNoProperties() { + PlatformJavaObjectFactoryProxy proxy = proxyForCustom(NO_DFLT_CTOR_FACTORY_CLS_NAME, + Collections.emptyMap()); + + Object val = proxy.factory(ctx).create(); + + assertEquals(val, new TestJavaObject()); + } + + /** + * Test object creation with invalid property name. + */ + public void testCustomFactoryInvalidPropertyName() { + final PlatformJavaObjectFactoryProxy proxy = proxyForCustom(NO_DFLT_CTOR_FACTORY_CLS_NAME, + Collections.singletonMap("invalid", (Object)1)); + + GridTestUtils.assertThrows(null, new Callable() { + @Override public Object call() throws Exception { + return proxy.factory(ctx).create(); + } + }, IgniteException.class, null); + } + + /** + * Test object creation with invalid property value. + */ + public void testCustomFactoryInvalidPropertyValue() { + final PlatformJavaObjectFactoryProxy proxy = proxyForCustom(NO_DFLT_CTOR_FACTORY_CLS_NAME, + Collections.singletonMap("fInt", (Object)1L)); + + GridTestUtils.assertThrows(null, new Callable() { + @Override public Object call() throws Exception { + return proxy.factory(ctx).create(); + } + }, IgniteException.class, null); + } + + /** + * Test object creation with null class name. + */ + public void testCustomFactoryNullClassName() { + GridTestUtils.assertThrows(null, new Callable() { + @Override public Object call() throws Exception { + return proxyForCustom(null, null).factory(ctx).create(); + } + }, IgniteException.class, null); + + GridTestUtils.assertThrows(null, new Callable() { + @Override public Object call() throws Exception { + return proxyForCustom(null, new HashMap()).factory(ctx).create(); + } + }, IgniteException.class, null); + } + + /** + * Test object creation with invalid class name. + */ + public void testCustomFactoryInvalidClassName() { + GridTestUtils.assertThrows(null, new Callable() { + @Override public Object call() throws Exception { + return proxyForCustom("invalid", null).factory(ctx).create(); + } + }, IgniteException.class, null); + } + + /** + * Create proxy for user-defined factory. + * + * @param clsName Class name. + * @param props Properties. + * @return Proxy. + */ + private static PlatformJavaObjectFactoryProxy proxyForCustom(String clsName, Map props) { + return new PlatformJavaObjectFactoryProxy(PlatformJavaObjectFactoryProxy.TYP_USER, clsName, null, props); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/test/java/org/apache/ignite/platform/PlatformStartIgniteTask.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformStartIgniteTask.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformStartIgniteTask.java index c8eb13f..e703431 100644 --- a/modules/core/src/test/java/org/apache/ignite/platform/PlatformStartIgniteTask.java +++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformStartIgniteTask.java @@ -61,6 +61,7 @@ public class PlatformStartIgniteTask extends ComputeTaskAdapter /** * Ctor. + * * @param springConfig Config. */ private PlatformStartIgniteJob(String springConfig) { http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/test/java/org/apache/ignite/platform/PlatformStopIgniteTask.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformStopIgniteTask.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformStopIgniteTask.java index c0319ab..238f058 100644 --- a/modules/core/src/test/java/org/apache/ignite/platform/PlatformStopIgniteTask.java +++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformStopIgniteTask.java @@ -60,6 +60,7 @@ public class PlatformStopIgniteTask extends ComputeTaskAdapter /** * Ctor. + * * @param gridName Name. */ private PlatformStopIgniteJob(String gridName) { http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/test/java/org/apache/ignite/platform/javaobject/TestJavaObject.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/platform/javaobject/TestJavaObject.java b/modules/core/src/test/java/org/apache/ignite/platform/javaobject/TestJavaObject.java new file mode 100644 index 0000000..3c76798 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/javaobject/TestJavaObject.java @@ -0,0 +1,271 @@ +/* + * 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.javaobject; + +/** + * Test object. + */ +public class TestJavaObject { + /** */ + protected boolean fBoolean; + + /** */ + protected byte fByte; + + /** */ + protected short fShort; + + /** */ + protected char fChar; + + /** */ + protected int fInt; + + /** */ + protected long fLong; + + /** */ + protected float fFloat; + + /** */ + protected double fDouble; + + /** */ + protected Object fObj; + + /** Integer field. */ + protected Integer fIntBoxed; + + /** + * Default constructor. + */ + public TestJavaObject() { + // No-op. + } + + /** + * Constructor. + * + * @param fBoolean Boolean field. + * @param fByte Byte field. + * @param fShort Short field. + * @param fChar Char field. + * @param fInt Integer field. + * @param fLong Long field. + * @param fDouble Double field. + * @param fFloat Float field. + * @param fObj Object field. + * @param fIntBoxed Integer boxed field. + */ + public TestJavaObject(boolean fBoolean, byte fByte, short fShort, char fChar, int fInt, long fLong, float fFloat, + double fDouble, Object fObj, Integer fIntBoxed) { + this.fBoolean = fBoolean; + this.fByte = fByte; + this.fShort = fShort; + this.fChar = fChar; + this.fInt = fInt; + this.fLong = fLong; + this.fDouble = fDouble; + this.fFloat = fFloat; + this.fObj = fObj; + this.fIntBoxed = fIntBoxed; + } + + /** + * Set boolean field. + * + * @param fBoolean Value. + * @return This instance for chaining. + */ + public TestJavaObject setBoolean(boolean fBoolean) { + this.fBoolean = fBoolean; + + return this; + } + + /** + * Set byte field. + * + * @param fByte Value. + * @return This instance for chaining. + */ + public TestJavaObject setByte(byte fByte) { + this.fByte = fByte; + + return this; + } + + /** + * Set short field. + * + * @param fShort Value. + * @return This instance for chaining. + */ + public TestJavaObject setShort(short fShort) { + this.fShort = fShort; + + return this; + } + + /** + * Set char field. + * + * @param fChar Value. + * @return This instance for chaining. + */ + public TestJavaObject setChar(char fChar) { + this.fChar = fChar; + + return this; + } + + /** + * Set int field. + * + * @param fInt Value. + * @return This instance for chaining. + */ + public TestJavaObject setInt(int fInt) { + this.fInt = fInt; + + return this; + } + + /** + * Set long field. + * + * @param fLong Value. + * @return This instance for chaining. + */ + public TestJavaObject setLong(long fLong) { + this.fLong = fLong; + + return this; + } + + /** + * Set float field. + * + * @param fFloat Value. + * @return This instance for chaining. + */ + public TestJavaObject setFloat(float fFloat) { + this.fFloat = fFloat; + + return this; + } + + /** + * Set double field. + * + * @param fDouble Value. + * @return This instance for chaining. + */ + public TestJavaObject setDouble(double fDouble) { + this.fDouble = fDouble; + + return this; + } + + /** + * Set object field. + * + * @param fObj Value. + * @return This instance for chaining. + */ + public TestJavaObject setObject(Object fObj) { + this.fObj = fObj; + + return this; + } + + /** + * Set wrapped integer field. + * + * @param fInteger Value. + * @return This instance for chaining. + */ + public TestJavaObject setIntBoxed(Integer fInteger) { + this.fIntBoxed = fInteger; + + return this; + } + + /** {@inheritDoc} */ + @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass", "SimplifiableIfStatement"}) + @Override public boolean equals(Object o) { + if (this == o) + return true; + + if (o == null) + return false; + + TestJavaObject that = (TestJavaObject) o; + + if (fBoolean != that.fBoolean) + return false; + + if (fByte != that.fByte) + return false; + + if (fShort != that.fShort) + return false; + + if (fChar != that.fChar) + return false; + + if (fInt != that.fInt) + return false; + + if (fLong != that.fLong) + return false; + + if (Double.compare(that.fDouble, fDouble) != 0) + return false; + + if (Float.compare(that.fFloat, fFloat) != 0) + return false; + + if (fObj != null ? !fObj.equals(that.fObj) : that.fObj != null) + return false; + + return fIntBoxed != null ? fIntBoxed.equals(that.fIntBoxed) : that.fIntBoxed == null; + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + int res; + long tmp; + + res = (fBoolean ? 1 : 0); + res = 31 * res + (int) fByte; + res = 31 * res + (int) fShort; + res = 31 * res + (int) fChar; + res = 31 * res + fInt; + res = 31 * res + (int) (fLong ^ (fLong >>> 32)); + + tmp = Double.doubleToLongBits(fDouble); + + res = 31 * res + (int) (tmp ^ (tmp >>> 32)); + res = 31 * res + (fFloat != +0.0f ? Float.floatToIntBits(fFloat) : 0); + res = 31 * res + (fObj != null ? fObj.hashCode() : 0); + res = 31 * res + (fIntBoxed != null ? fIntBoxed.hashCode() : 0); + + return res; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/test/java/org/apache/ignite/platform/javaobject/TestJavaObjectNoDefaultCtor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/platform/javaobject/TestJavaObjectNoDefaultCtor.java b/modules/core/src/test/java/org/apache/ignite/platform/javaobject/TestJavaObjectNoDefaultCtor.java new file mode 100644 index 0000000..1d7ed07 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/javaobject/TestJavaObjectNoDefaultCtor.java @@ -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.platform.javaobject; + +import org.apache.ignite.Ignite; + +/** + * Test Java object without default constructor. + */ +public class TestJavaObjectNoDefaultCtor extends TestJavaObject { + /** Node. */ + public Ignite node; + + /** + * Constructor. + * + * @param fBoolean Boolean field. + * @param fByte Byte field. + * @param fShort Short field. + * @param fChar Char field. + * @param fInt Integer field. + * @param fLong Long field. + * @param fDouble Double field. + * @param fFloat Float field. + * @param fObj Object field. + * @param fIntBoxed Integer boxed field. + */ + public TestJavaObjectNoDefaultCtor(boolean fBoolean, byte fByte, short fShort, char fChar, int fInt, long fLong, + float fFloat, double fDouble, Object fObj, Integer fIntBoxed, Ignite node) { + super(fBoolean, fByte, fShort, fChar, fInt, fLong, fFloat, fDouble, fObj, fIntBoxed); + + this.node = node; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/test/java/org/apache/ignite/platform/javaobject/TestJavaObjectNoDefaultCtorFactory.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/platform/javaobject/TestJavaObjectNoDefaultCtorFactory.java b/modules/core/src/test/java/org/apache/ignite/platform/javaobject/TestJavaObjectNoDefaultCtorFactory.java new file mode 100644 index 0000000..0e6dd99 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/javaobject/TestJavaObjectNoDefaultCtorFactory.java @@ -0,0 +1,68 @@ +/* + * 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.javaobject; + +import org.apache.ignite.Ignite; +import org.apache.ignite.platform.PlatformJavaObjectFactory; +import org.apache.ignite.resources.IgniteInstanceResource; + +/** + * Test factory. + */ +@SuppressWarnings("unused") +public class TestJavaObjectNoDefaultCtorFactory implements PlatformJavaObjectFactory { + /** Injected node. */ + @IgniteInstanceResource + public Ignite node; + + /** */ + private boolean fBoolean; + + /** */ + private byte fByte; + + /** */ + private short fShort; + + /** */ + private char fChar; + + /** */ + private int fInt; + + /** */ + private long fLong; + + /** */ + private float fFloat; + + /** */ + private double fDouble; + + /** */ + private Object fObj; + + /** Integer field. */ + private Integer fIntBoxed; + + /** {@inheritDoc} */ + @Override public Object create() { + return new TestJavaObjectNoDefaultCtor(fBoolean, fByte, fShort, fChar, fInt, fLong, fFloat, fDouble, fObj, + fIntBoxed, node); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java index 9e2324c..c67a07d 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java @@ -86,6 +86,8 @@ public class IgniteBasicTestSuite extends TestSuite { suite.addTest(IgniteCacheP2pUnmarshallingErrorTestSuite.suite(ignoredTests)); suite.addTest(IgniteStreamSelfTestSuite.suite()); + suite.addTest(IgnitePlatformsTestSuite.suite()); + suite.addTest(new TestSuite(GridSelfTest.class)); suite.addTest(new TestSuite(ClusterGroupHostsSelfTest.class)); suite.addTest(new TestSuite(IgniteMessagingWithClientTest.class)); http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePlatformsTestSuite.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePlatformsTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePlatformsTestSuite.java new file mode 100644 index 0000000..f7021d8 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePlatformsTestSuite.java @@ -0,0 +1,41 @@ +/* + * 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.testsuites; + +import junit.framework.TestSuite; +import org.apache.ignite.platform.PlatformDefaultJavaObjectFactorySelfTest; +import org.apache.ignite.platform.PlatformJavaObjectFactoryProxySelfTest; + +/** + * Suite for platform tests. + */ +public class IgnitePlatformsTestSuite extends TestSuite { + /** + * @return Test suite. + * @throws Exception If failed. + */ + public static TestSuite suite() throws Exception { + TestSuite suite = new TestSuite("Ignite Deployment SPI Test Suite"); + + // LocalDeploymentSpi tests + suite.addTest(new TestSuite(PlatformDefaultJavaObjectFactorySelfTest.class)); + suite.addTest(new TestSuite(PlatformJavaObjectFactoryProxySelfTest.class)); + + return suite; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj index cba7d9e..de21765 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj @@ -101,6 +101,7 @@ + http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs index 218ebef..a47f3f0 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs @@ -35,8 +35,6 @@ namespace Apache.Ignite.Core.Tests.Cache.Query using Apache.Ignite.Core.Binary; using Apache.Ignite.Core.Cache; using Apache.Ignite.Core.Cache.Configuration; - using Apache.Ignite.Core.Discovery.Tcp; - using Apache.Ignite.Core.Discovery.Tcp.Static; using Apache.Ignite.Linq; using NUnit.Framework; http://git-wip-us.apache.org/repos/asf/ignite/blob/4d99d9ee/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Continuous/ContinuousQueryJavaFilterTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Continuous/ContinuousQueryJavaFilterTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Continuous/ContinuousQueryJavaFilterTest.cs new file mode 100644 index 0000000..ed9d2ad --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Continuous/ContinuousQueryJavaFilterTest.cs @@ -0,0 +1,323 @@ +/* + * 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. + */ + +// ReSharper disable UnusedAutoPropertyAccessor.Local +#pragma warning disable 618 // SpringConfigUrl +namespace Apache.Ignite.Core.Tests.Cache.Query.Continuous +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + using System.Threading; + using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Cache.Event; + using Apache.Ignite.Core.Cache.Query.Continuous; + using Apache.Ignite.Core.Common; + using Apache.Ignite.Core.Interop; + using NUnit.Framework; + + /// + /// Tests query in a cluster with Java-only and .NET nodes. + /// + public class ContinuousQueryJavaFilterTest + { + /** */ + private const string SpringConfig = @"Config\Compute\compute-grid1.xml"; + + /** */ + private const string SpringConfig2 = @"Config\Compute\compute-grid2.xml"; + + /** */ + private const string StartTask = "org.apache.ignite.platform.PlatformStartIgniteTask"; + + /** */ + private const string StopTask = "org.apache.ignite.platform.PlatformStopIgniteTask"; + + /** */ + private const string PlatformFilter = "org.apache.ignite.platform.PlatformCacheEntryEventFilter"; + + /** */ + private const string PlatformFilterFactory = "org.apache.ignite.platform.PlatformCacheEntryEventFilterFactory"; + + /** */ + private IIgnite _ignite; + + /** */ + private string _javaNodeName; + + /** */ + private static volatile Tuple _lastEvent; + + /// + /// Fixture set up. + /// + [TestFixtureSetUp] + public void FixtureSetUp() + { + // Main .NET nodes + var jvmOpts = TestUtils.TestJavaOptions(); + + _ignite = Ignition.Start(new IgniteConfiguration + { + JvmClasspath = TestUtils.CreateTestClasspath(), + JvmOptions = jvmOpts, + SpringConfigUrl = SpringConfig, + BinaryConfiguration = new BinaryConfiguration + { + TypeConfigurations = new List + { + new BinaryTypeConfiguration(typeof(TestBinary)) + } + } + }); + + // Second .NET node + Ignition.Start(new IgniteConfiguration + { + JvmClasspath = TestUtils.CreateTestClasspath(), + JvmOptions = jvmOpts, + SpringConfigUrl = SpringConfig2, + GridName = "dotNet2" + }); + + // Java-only node + _javaNodeName = _ignite.GetCompute().ExecuteJavaTask(StartTask, SpringConfig2); + + Assert.IsTrue(_ignite.WaitTopology(3, 5000)); + } + + /// + /// Fixture tear down. + /// + [TestFixtureTearDown] + public void FixtureTearDown() + { + _ignite.GetCompute().ExecuteJavaTask(StopTask, _javaNodeName); + Ignition.StopAll(true); + } + + /// + /// Tests the filter. + /// + [Test] + public void TestFilter() + { + var javaObj = new JavaObject(PlatformFilter) + { + Properties = + { + {"startsWith", "valid"}, + {"charField", 'a'}, + {"byteField", (byte) 1}, + {"sbyteField", (sbyte) 2}, + {"shortField", (short) 3}, + {"ushortField", (ushort) 4}, + {"intField", 5}, + {"uintField", (uint) 6}, + {"longField", (long) 7}, + {"ulongField", (ulong) 8}, + {"floatField", (float) 9.99}, + {"doubleField", 10.123}, + {"decimalField", (decimal) 11.245}, + {"boolField", true}, + {"guidField", Guid.Parse("1c579241-509d-47c6-a1a0-87462ae31e59")}, + { + "objField", new TestBinary(1, "2") + + }, + {"charArr", new[] {'a'}}, + {"byteArr", new[] {(byte) 1}}, + {"sbyteArr", new[] {(sbyte) 2}}, + {"shortArr", new[] {(short) 3}}, + {"ushortArr", new[] {(ushort) 4}}, + {"intArr", new[] {5}}, + {"uintArr", new[] {(uint) 6}}, + {"longArr", new[] {(long) 7}}, + {"ulongArr", new[] {(ulong) 8}}, + {"floatArr", new[] {(float) 9.99}}, + {"doubleArr", new[] {10.123}}, + {"boolArr", new[] {true}}, + { + "objArr", new object[] + { + new TestBinary(1, "2") + } + }, + {"arrayList", new ArrayList {"x"}}, + {"hashTable", new Hashtable {{1, "2"}}} + } + }; + + TestFilter(javaObj); + } + + /// + /// Tests the factory class. + /// + [Test] + public void TestFactory() + { + var javaObj = new JavaObject(PlatformFilterFactory, + new Dictionary {{"startsWith", "valid"}}); + + TestFilter(javaObj); + } + + /// + /// Tests the invalid class name + /// + [Test] + public void TestInvalidClassName() + { + var javaObj = new JavaObject("blabla"); + + var ex = Assert.Throws(() => TestFilter(javaObj)); + + Assert.IsTrue(ex.Message.StartsWith("Java object/factory class is not found")); + } + + /// + /// Tests the invalid class name + /// + [Test] + public void TestInvalidProperty() + { + var javaObject = new JavaObject(PlatformFilter) + { + Properties = {{"invalidProp", "123"}} + }; + + var ex = Assert.Throws(() => TestFilter(javaObject)); + + Assert.IsTrue(ex.Message.StartsWith("Java object/factory class field is not found")); + } + + /// + /// Tests the specified filter. + /// + private void TestFilter(JavaObject obj) + { + TestFilter(obj, true); + TestFilter(obj, false); + } + + /// + /// Tests the specified filter. + /// + private void TestFilter(JavaObject obj, bool local) + { + // Test with cache of strings + var pred = obj.ToCacheEntryEventFilter(); + + TestFilter(pred, local, "validValue", "invalidValue"); + + // Test with cache of binary objects + var objPred = obj.ToCacheEntryEventFilter(); + + TestFilter(objPred, local, new TestBinary(1, "validValue"), new TestBinary(2, "invalidValue")); + } + + /// + /// Tests the specified filter. + /// + private void TestFilter(ICacheEntryEventFilter pred, bool local, T validVal, T invalidVal) + { + var cache = _ignite.GetOrCreateCache("qry"); + cache.Clear(); + + var qry = new ContinuousQuery(new QueryListener(), pred, local); + var aff = _ignite.GetAffinity("qry"); + var localNode = _ignite.GetCluster().GetLocalNode(); + + // Get one key per node + var keyMap = aff.MapKeysToNodes(Enumerable.Range(1, 100)); + Assert.AreEqual(3, keyMap.Count); + var keys = local + ? keyMap[localNode].Take(1) + : keyMap.Select(x => x.Value.First()); + + using (cache.QueryContinuous(qry)) + { + // Run on many keys to test all nodes + foreach (var key in keys) + { + _lastEvent = null; + cache[key] = validVal; + + TestUtils.WaitForCondition(() => _lastEvent != null, 2000); + Assert.IsNotNull(_lastEvent); + Assert.AreEqual(cache[key], _lastEvent.Item2); + + _lastEvent = null; + cache[key] = invalidVal; + + Thread.Sleep(2000); + Assert.IsNull(_lastEvent); + } + } + } + + /// + /// Test listener. + /// + private class QueryListener : ICacheEntryEventListener + { + /** */ + public void OnEvent(IEnumerable> evts) + { + _lastEvent = evts.Select(e => Tuple.Create(e.Key, (object) e.Value)).FirstOrDefault(); + } + } + + /// + /// Test binary object. + /// + private class TestBinary + { + public TestBinary(int i, string s) + { + Int = i; + String = s; + } + + private int Int { get; } + private string String { get; } + + private bool Equals(TestBinary other) + { + return Int == other.Int && string.Equals(String, other.String); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((TestBinary) obj); + } + + public override int GetHashCode() + { + unchecked + { + return (Int*397) ^ (String != null ? String.GetHashCode() : 0); + } + } + } + } +}