IGNITE-2979: .NET: Implemented ability to use Java filter in .NET-based continuous queries.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/4e34f58e Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/4e34f58e Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/4e34f58e Branch: refs/heads/ignite-testing-discovery Commit: 4e34f58e3affb6fd73807333808e1b8ede8e8b64 Parents: 18e355b Author: Pavel Tupitsyn <[email protected]> Authored: Wed Apr 13 17:54:46 2016 +0300 Committer: vozerov-gridgain <[email protected]> Committed: Wed Apr 13 18:09:25 2016 +0300 ---------------------------------------------------------------------- .../ignite/internal/binary/BinaryContext.java | 3 + .../internal/binary/GridBinaryMarshaller.java | 3 + .../PlatformDefaultJavaObjectFactory.java | 62 +++++ .../platform/PlatformJavaObjectFactoryEx.java | 36 +++ .../PlatformJavaObjectFactoryProxy.java | 192 +++++++++++++ .../PlatformJavaObjectSingletonFactory.java | 48 ++++ .../query/PlatformContinuousQueryImpl.java | 45 ++- .../platform/utils/PlatformUtils.java | 71 +++++ .../ignite/internal/util/IgniteUtils.java | 25 ++ .../platform/PlatformJavaObjectFactory.java | 36 +++ .../platform/PlatformCacheEntryEventFilter.java | 186 +++++++++++++ .../PlatformCacheEntryEventFilterFactory.java | 51 ++++ ...latformDefaultJavaObjectFactorySelfTest.java | 185 +++++++++++++ .../PlatformJavaObjectFactoryProxySelfTest.java | 220 +++++++++++++++ .../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 + .../Continuous/ContinuousQueryJavaFilterTest.cs | 265 ++++++++++++++++++ .../Apache.Ignite.Core.csproj | 3 + .../Impl/Binary/BinaryUtils.cs | 3 + .../Impl/Binary/Marshaller.cs | 2 + .../Continuous/ContinuousQueryHandleImpl.cs | 17 +- .../JavaObjects/JavaCacheEntryEventFilter.cs | 48 ++++ .../Common/PlatformJavaObjectFactoryProxy.cs | 106 ++++++++ .../Apache.Ignite.Core/Interop/JavaObject.cs | 92 +++++++ 28 files changed, 2124 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/4e34f58e/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 c410596..54cb971 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; @@ -272,6 +273,8 @@ public class BinaryContext { registerPredefinedType(GridMapEntry.class, 60); 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); http://git-wip-us.apache.org/repos/asf/ignite/blob/4e34f58e/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 3a7454a..535207c 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/4e34f58e/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<T> implements PlatformJavaObjectFactoryEx<T> { + /** Class name. */ + private String clsName; + + /** Properties. */ + private Map<String, Object> props; + + /** {@inheritDoc} */ + @Override public void initialize(@Nullable Object payload, @Nullable Map<String, Object> 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/4e34f58e/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<T> extends PlatformJavaObjectFactory<T> { + /** + * Initialize factory. + * + * @param payload Optional payload. + * @param props Optional properties. + */ + public void initialize(@Nullable Object payload, @Nullable Map<String, Object> props); +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4e34f58e/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<String, Object> 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<String, Object> 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<String, Object> 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/4e34f58e/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<T> implements PlatformJavaObjectFactory<T> { + /** 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/4e34f58e/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..f8244a9 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,19 @@ 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.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 +57,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 +87,29 @@ public class PlatformContinuousQueryImpl implements PlatformContinuousQuery { this.ptr = ptr; this.hasFilter = hasFilter; this.filter = filter; + + javaFilter = getJavaFilter(filter, platformCtx.kernalContext()); + } + + /** + * 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,9 +123,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(); @@ -170,7 +200,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 { @@ -229,7 +263,10 @@ public class PlatformContinuousQueryImpl implements PlatformContinuousQuery { * @return Filter to be deployed on remote node. * @throws ObjectStreamException If failed. */ - Object writeReplace() throws ObjectStreamException { + protected 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/4e34f58e/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 4a29637..5f43753 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 @@ -46,6 +46,9 @@ import org.jetbrains.annotations.Nullable; import javax.cache.CacheException; import javax.cache.event.CacheEntryEvent; import javax.cache.event.CacheEntryListenerException; +import java.lang.reflect.Field; +import java.math.BigDecimal; +import java.security.Timestamp; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -802,6 +805,74 @@ public class PlatformUtils { } /** + * Create Java object. + * + * @param clsName Class name. + * @return Instance. + */ + public static <T> 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<String, Object> props, + @Nullable GridKernalContext ctx) { + if (props != null) { + for (Map.Entry<String, Object> 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/4e34f58e/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 60abbb5..6d9f574 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 @@ -9215,6 +9215,31 @@ public abstract class IgniteUtils { } /** + * @param cls The class to search. + * @param name Name of a field to get. + * @return Field or {@code null}. + */ + @Nullable public static Field findField(Class<?> cls, String name) { + while (cls != null) { + try { + Field fld = cls.getDeclaredField(name); + + if (!fld.isAccessible()) + fld.setAccessible(true); + + return fld; + } + catch (NoSuchFieldException e) { + // No-op. + } + + cls = cls.getSuperclass(); + } + + return null; + } + + /** * @param c Collection. * @param p Optional filters. * @return Resulting array list. http://git-wip-us.apache.org/repos/asf/ignite/blob/4e34f58e/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. + * <p> + * Use it when you need Java component for some Ignite feature in platform code. E.g. Java-based continuous + * query filter. + * <p> + * 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<T> { + /** + * 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/4e34f58e/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..ca019f4 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheEntryEventFilter.java @@ -0,0 +1,186 @@ +/* + * 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")); + + return ((String)event.getValue()).startsWith(startsWith); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4e34f58e/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..5410603 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheEntryEventFilterFactory.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.platform; + +import org.apache.ignite.Ignite; +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<CacheEntryEventSerializableFilter> { + /** 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 { + return ((String)event.getValue()).startsWith(startsWith); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4e34f58e/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<String, Object> 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<Object>() { + @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<Object>() { + @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<Object>() { + @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<Void>() { + @Override public Void call() throws Exception { + factory.initialize(null, null); + + return null; + } + }, IgniteException.class, null); + + GridTestUtils.assertThrows(null, new Callable<Void>() { + @Override public Void call() throws Exception { + factory.initialize(null, new HashMap<String, Object>()); + + 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<Object>() { + @Override public Object call() throws Exception { + return factory.create(); + } + }, IgniteException.class, null); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4e34f58e/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<String, Object> 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<String, Object> 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.<String, Object>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<Object>() { + @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<Object>() { + @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<Object>() { + @Override public Object call() throws Exception { + return proxyForCustom(null, null).factory(ctx).create(); + } + }, IgniteException.class, null); + + GridTestUtils.assertThrows(null, new Callable<Object>() { + @Override public Object call() throws Exception { + return proxyForCustom(null, new HashMap<String, Object>()).factory(ctx).create(); + } + }, IgniteException.class, null); + } + + /** + * Test object creation with invalid class name. + */ + public void testCustomFactoryInvalidClassName() { + GridTestUtils.assertThrows(null, new Callable<Object>() { + @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<String, Object> props) { + return new PlatformJavaObjectFactoryProxy(PlatformJavaObjectFactoryProxy.TYP_USER, clsName, null, props); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4e34f58e/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/4e34f58e/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/4e34f58e/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/4e34f58e/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 c904ef4..fede0ab 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 @@ -82,6 +82,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/4e34f58e/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/4e34f58e/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 a247f63..26b4352 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 @@ -99,6 +99,7 @@ <Compile Include="Compute\FailoverTaskSelfTest.cs" /> <Compile Include="Compute\BinarizableClosureTaskTest.cs" /> <Compile Include="Compute\BinarizableTaskTest.cs" /> + <Compile Include="Cache\Query\Continuous\ContinuousQueryJavaFilterTest.cs" /> <Compile Include="Compute\ResourceTaskTest.cs" /> <Compile Include="Compute\SerializableClosureTaskTest.cs" /> <Compile Include="Compute\TaskAdapterTest.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/4e34f58e/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..fa73621 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Continuous/ContinuousQueryJavaFilterTest.cs @@ -0,0 +1,265 @@ +/* + * 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 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; + + /// <summary> + /// Tests query in a cluster with Java-only and .NET nodes. + /// </summary> + 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 IIgnite _ignite; + + /** */ + private string _javaNodeName; + + /** */ + private static volatile ICacheEntryEvent<int, string> _lastEvent; + + /// <summary> + /// Fixture set up. + /// </summary> + [TestFixtureSetUp] + public void FixtureSetUp() + { + // Main .NET nodes + _ignite = Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration()) + { + SpringConfigUrl = SpringConfig, + BinaryConfiguration = new BinaryConfiguration(typeof (TestBinary)) + }); + + // Second .NET node + Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration()) + { + SpringConfigUrl = SpringConfig2, + GridName = "dotNet2" + }); + + + // Java-only node + _javaNodeName = _ignite.GetCompute().ExecuteJavaTask<string>(StartTask, SpringConfig2); + + Assert.IsTrue(_ignite.WaitTopology(3)); + } + + /// <summary> + /// Fixture tear down. + /// </summary> + [TestFixtureTearDown] + public void FixtureTearDown() + { + _ignite.GetCompute().ExecuteJavaTask<object>(StopTask, _javaNodeName); + Ignition.StopAll(true); + } + + /// <summary> + /// Tests the filter. + /// </summary> + [Test] + public void TestFilter() + { + var javaObj = new JavaObject("org.apache.ignite.platform.PlatformCacheEntryEventFilter") + { + 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 + { + Int = 1, + String = "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 + { + Int = 1, + String = "2" + } + } + }, + {"arrayList", new ArrayList {"x"}}, + {"hashTable", new Hashtable {{1, "2"}}} + } + }; + + var filter = javaObj.ToCacheEntryEventFilter<int, string>(); + + TestFilter(filter); + } + + /// <summary> + /// Tests the factory class. + /// </summary> + [Test] + public void TestFactory() + { + var javaObj = new JavaObject("org.apache.ignite.platform.PlatformCacheEntryEventFilterFactory", + new Dictionary<string, object> {{"startsWith", "valid"}}); + + var filter = javaObj.ToCacheEntryEventFilter<int, string>(); + + TestFilter(filter); + } + + /// <summary> + /// Tests the invalid class name + /// </summary> + [Test] + public void TestInvalidClassName() + { + var filter = new JavaObject("blabla").ToCacheEntryEventFilter<int, string>(); + + var ex = Assert.Throws<IgniteException>(() => TestFilter(filter)); + + Assert.IsTrue(ex.Message.StartsWith("Java object/factory class is not found")); + } + + /// <summary> + /// Tests the invalid class name + /// </summary> + [Test] + public void TestInvalidProperty() + { + var javaObject = new JavaObject("org.apache.ignite.platform.PlatformCacheEntryEventFilter") + { + Properties = {{"invalidProp", "123"}} + }; + + var filter = javaObject.ToCacheEntryEventFilter<int, string>(); + + var ex = Assert.Throws<IgniteException>(() => TestFilter(filter)); + + Assert.IsTrue(ex.Message.StartsWith("Java object/factory class field is not found")); + } + + /// <summary> + /// Tests the specified filter. + /// </summary> + private void TestFilter(ICacheEntryEventFilter<int, string> pred) + { + TestFilter(pred, false); + TestFilter(pred, true); + } + + /// <summary> + /// Tests the specified filter. + /// </summary> + private void TestFilter(ICacheEntryEventFilter<int, string> pred, bool local) + { + var cache = _ignite.GetOrCreateCache<int, string>("qry"); + var qry = new ContinuousQuery<int, string>(new QueryListener(), pred, local); + var aff = _ignite.GetAffinity("qry"); + var localNode = _ignite.GetCluster().GetLocalNode(); + + using (cache.QueryContinuous(qry)) + { + // Run on many keys to test all nodes + for (var i = 0; i < 200; i++) + { + if (local && aff.MapKeyToNode(i).Id != localNode.Id) + continue; + + _lastEvent = null; + cache[i] = "validValue"; + // ReSharper disable once PossibleNullReferenceException + Assert.AreEqual(cache[i], _lastEvent.Value); + + _lastEvent = null; + cache[i] = "invalidValue"; + Assert.IsNull(_lastEvent); + } + } + } + + /// <summary> + /// Test listener. + /// </summary> + private class QueryListener : ICacheEntryEventListener<int, string> + { + /** <inheritdoc /> */ + public void OnEvent(IEnumerable<ICacheEntryEvent<int, string>> evts) + { + _lastEvent = evts.FirstOrDefault(); + } + } + + /// <summary> + /// Test binary object. + /// </summary> + private class TestBinary + { + public int Int { get; set; } + public string String { get; set; } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/4e34f58e/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj index 12404be..2b37d2d 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj @@ -107,6 +107,8 @@ <Compile Include="Common\IgniteFutureCancelledException.cs" /> <Compile Include="Common\IgniteGuid.cs" /> <Compile Include="Common\Package-Info.cs" /> + <Compile Include="Impl\Common\PlatformJavaObjectFactoryProxy.cs" /> + <Compile Include="Impl\Common\JavaObjects\JavaCacheEntryEventFilter.cs" /> <Compile Include="Compute\ComputeExecutionRejectedException.cs" /> <Compile Include="Compute\ComputeJobAdapter.cs" /> <Compile Include="Compute\ComputeJobFailoverException.cs" /> @@ -324,6 +326,7 @@ <Compile Include="Impl\Unmanaged\UnmanagedNonReleaseableTarget.cs" /> <Compile Include="Impl\Unmanaged\UnmanagedTarget.cs" /> <Compile Include="Impl\Unmanaged\UnmanagedUtils.cs" /> + <Compile Include="Interop\JavaObject.cs" /> <Compile Include="Lifecycle\Package-Info.cs" /> <Compile Include="Messaging\Package-Info.cs" /> <Compile Include="Package-Info.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/4e34f58e/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs index 1c85e31..80e5b26 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs @@ -187,6 +187,9 @@ namespace Apache.Ignite.Core.Impl.Binary /** Type: stream receiver holder. */ public const byte TypeStreamReceiverHolder = 94; + /** Type: platform object proxy. */ + public const byte TypePlatformJavaObjectFactoryProxy = 99; + /** Collection: custom. */ public const byte CollectionCustom = 0; http://git-wip-us.apache.org/repos/asf/ignite/blob/4e34f58e/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs index 457830f..81fc195 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs @@ -26,6 +26,7 @@ namespace Apache.Ignite.Core.Impl.Binary using Apache.Ignite.Core.Impl.Binary.Metadata; using Apache.Ignite.Core.Impl.Cache; using Apache.Ignite.Core.Impl.Cache.Query.Continuous; + using Apache.Ignite.Core.Impl.Common; using Apache.Ignite.Core.Impl.Compute; using Apache.Ignite.Core.Impl.Compute.Closure; using Apache.Ignite.Core.Impl.Datastream; @@ -534,6 +535,7 @@ namespace Apache.Ignite.Core.Impl.Binary AddSystemType(BinaryUtils.TypeCacheEntryPredicateHolder, w => new CacheEntryFilterHolder(w)); AddSystemType(BinaryUtils.TypeMessageListenerHolder, w => new MessageListenerHolder(w)); AddSystemType(BinaryUtils.TypeStreamReceiverHolder, w => new StreamReceiverHolder(w)); + AddSystemType(BinaryUtils.TypePlatformJavaObjectFactoryProxy, w => new PlatformJavaObjectFactoryProxy()); } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/4e34f58e/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Query/Continuous/ContinuousQueryHandleImpl.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Query/Continuous/ContinuousQueryHandleImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Query/Continuous/ContinuousQueryHandleImpl.cs index fef904b..101ed43 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Query/Continuous/ContinuousQueryHandleImpl.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/Query/Continuous/ContinuousQueryHandleImpl.cs @@ -26,6 +26,7 @@ namespace Apache.Ignite.Core.Impl.Cache.Query.Continuous using Apache.Ignite.Core.Cache.Query.Continuous; using Apache.Ignite.Core.Impl.Binary; using Apache.Ignite.Core.Impl.Binary.IO; + using Apache.Ignite.Core.Impl.Common; using Apache.Ignite.Core.Impl.Resource; using Apache.Ignite.Core.Impl.Unmanaged; using UU = Apache.Ignite.Core.Impl.Unmanaged.UnmanagedUtils; @@ -111,10 +112,20 @@ namespace Apache.Ignite.Core.Impl.Cache.Query.Continuous writer.WriteBoolean(qry.Local); writer.WriteBoolean(_filter != null); - var filterHolder = _filter == null || qry.Local ? null : - new ContinuousQueryFilterHolder(_filter, _keepBinary); + var javaFilter = _filter as PlatformJavaObjectFactoryProxy; - writer.WriteObject(filterHolder); + if (javaFilter != null) + { + writer.WriteObject(javaFilter.GetRawProxy()); + } + else + { + var filterHolder = _filter == null || qry.Local + ? null + : new ContinuousQueryFilterHolder(_filter, _keepBinary); + + writer.WriteObject(filterHolder); + } writer.WriteInt(qry.BufferSize); writer.WriteLong((long)qry.TimeInterval.TotalMilliseconds);
