| /* |
| * 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.utils; |
| |
| import org.apache.ignite.Ignite; |
| import org.apache.ignite.IgniteCheckedException; |
| import org.apache.ignite.IgniteException; |
| import org.apache.ignite.IgniteLogger; |
| import org.apache.ignite.binary.BinaryObject; |
| import org.apache.ignite.binary.BinaryRawWriter; |
| import org.apache.ignite.cache.CachePeekMode; |
| import org.apache.ignite.configuration.IgniteConfiguration; |
| import org.apache.ignite.internal.GridKernalContext; |
| import org.apache.ignite.internal.IgniteKernal; |
| import org.apache.ignite.internal.MarshallerContextImpl; |
| import org.apache.ignite.internal.binary.BinaryContext; |
| import org.apache.ignite.internal.binary.BinaryFieldMetadata; |
| import org.apache.ignite.internal.binary.BinaryMarshaller; |
| import org.apache.ignite.internal.binary.BinaryMetadata; |
| import org.apache.ignite.internal.binary.BinaryNoopMetadataHandler; |
| import org.apache.ignite.internal.binary.BinaryRawReaderEx; |
| import org.apache.ignite.internal.binary.BinaryRawWriterEx; |
| import org.apache.ignite.internal.binary.BinarySchema; |
| import org.apache.ignite.internal.binary.BinarySchemaRegistry; |
| import org.apache.ignite.internal.binary.BinaryTypeImpl; |
| import org.apache.ignite.internal.binary.BinaryUtils; |
| import org.apache.ignite.internal.binary.GridBinaryMarshaller; |
| import org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl; |
| import org.apache.ignite.internal.processors.platform.PlatformContext; |
| import org.apache.ignite.internal.processors.platform.PlatformExtendedException; |
| import org.apache.ignite.internal.processors.platform.PlatformNativeException; |
| import org.apache.ignite.internal.processors.platform.PlatformProcessor; |
| import org.apache.ignite.internal.processors.platform.memory.PlatformInputStream; |
| import org.apache.ignite.internal.processors.platform.memory.PlatformMemory; |
| import org.apache.ignite.internal.processors.platform.memory.PlatformMemoryUtils; |
| import org.apache.ignite.internal.processors.platform.memory.PlatformOutputStream; |
| import org.apache.ignite.internal.util.MutableSingletonList; |
| import org.apache.ignite.internal.util.typedef.F; |
| import org.apache.ignite.internal.util.typedef.X; |
| import org.apache.ignite.internal.util.typedef.internal.U; |
| import org.apache.ignite.lang.IgniteBiTuple; |
| import org.apache.ignite.lang.IgnitePredicate; |
| import org.apache.ignite.lang.IgniteUuid; |
| import org.apache.ignite.logger.NullLogger; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.cache.CacheException; |
| import javax.cache.event.CacheEntryEvent; |
| import javax.cache.event.CacheEntryListenerException; |
| import javax.cache.event.EventType; |
| import java.lang.reflect.Field; |
| import java.math.BigDecimal; |
| import java.security.Timestamp; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedHashMap; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.UUID; |
| |
| import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_PREFIX; |
| |
| /** |
| * Platform utility methods. |
| */ |
| @SuppressWarnings({"UnusedDeclaration", "unchecked"}) |
| public class PlatformUtils { |
| /** Node attribute: platform. */ |
| public static final String ATTR_PLATFORM = ATTR_PREFIX + ".platform"; |
| |
| /** Platform: CPP. */ |
| public static final String PLATFORM_CPP = "cpp"; |
| |
| /** Platform: .Net. */ |
| public static final String PLATFORM_DOTNET = "dotnet"; |
| |
| /** Operation: prepare .Net platform. */ |
| public static final int OP_PREPARE_DOT_NET = 1; |
| |
| /** Amount of peek modes available. */ |
| private static final int CACHE_PEEK_MODES_CNT = CachePeekMode.values().length; |
| |
| /** Cache peek modes. */ |
| private static volatile CachePeekMode[][] CACHE_PEEK_MODES; |
| |
| /** |
| * Static initializer. |
| */ |
| static { |
| int len = 1 << CACHE_PEEK_MODES_CNT; |
| |
| synchronized (PlatformUtils.class) { |
| CACHE_PEEK_MODES = new CachePeekMode[len][]; |
| |
| CACHE_PEEK_MODES[0] = new CachePeekMode[0]; |
| } |
| } |
| |
| /** |
| * Write nullable collection to the writer. |
| * |
| * @param writer Writer. |
| * @param col Collection to write. |
| */ |
| public static <T> void writeNullableCollection(BinaryRawWriterEx writer, @Nullable Collection<T> col) { |
| writeNullableCollection(writer, col, null, null); |
| } |
| |
| /** |
| * Write nullable collection to the writer. |
| * |
| * @param writer Writer. |
| * @param col Collection to write. |
| * @param writeClo Writer closure. |
| */ |
| public static <T> void writeNullableCollection(BinaryRawWriterEx writer, @Nullable Collection<T> col, |
| @Nullable PlatformWriterClosure<T> writeClo) { |
| writeNullableCollection(writer, col, writeClo, null); |
| } |
| |
| /** |
| * Write collection to the writer. |
| * |
| * @param writer Writer. |
| * @param col Collection to write. |
| * @param writeClo Optional writer closure. |
| * @param filter Optional filter. |
| */ |
| public static <T> void writeNullableCollection(BinaryRawWriterEx writer, @Nullable Collection<T> col, |
| @Nullable PlatformWriterClosure<T> writeClo, @Nullable IgnitePredicate<T> filter) { |
| if (col != null) { |
| writer.writeBoolean(true); |
| |
| writeCollection(writer, col, writeClo, filter); |
| } |
| else |
| writer.writeBoolean(false); |
| } |
| |
| /** |
| * Write collection to the writer. |
| * |
| * @param writer Writer. |
| * @param col Collection to write. |
| */ |
| public static <T> void writeCollection(BinaryRawWriterEx writer, Collection<T> col) { |
| writeCollection(writer, col, null, null); |
| } |
| |
| /** |
| * Write collection to the writer. |
| * |
| * @param writer Writer. |
| * @param col Collection to write. |
| * @param writeClo Writer closure. |
| */ |
| public static <T> void writeCollection(BinaryRawWriterEx writer, Collection<T> col, |
| @Nullable PlatformWriterClosure<T> writeClo) { |
| writeCollection(writer, col, writeClo, null); |
| } |
| |
| /** |
| * Write collection to the writer. |
| * |
| * @param writer Writer. |
| * @param col Collection to write. |
| * @param writeClo Optional writer closure. |
| * @param filter Optional filter. |
| */ |
| public static <T> void writeCollection(BinaryRawWriterEx writer, Collection<T> col, |
| @Nullable PlatformWriterClosure<T> writeClo, @Nullable IgnitePredicate<T> filter) { |
| assert col != null; |
| |
| if (filter == null) { |
| writer.writeInt(col.size()); |
| |
| if (writeClo == null) { |
| for (T entry : col) |
| writer.writeObject(entry); |
| } |
| else { |
| for (T entry : col) |
| writeClo.write(writer, entry); |
| } |
| } |
| else { |
| int pos = writer.reserveInt(); |
| int cnt = 0; |
| |
| for (T entry : col) { |
| if (filter.apply(entry)) { |
| cnt++; |
| |
| if (writeClo == null) |
| writer.writeObject(entry); |
| else |
| writeClo.write(writer, entry); |
| } |
| } |
| |
| writer.writeInt(pos, cnt); |
| } |
| } |
| |
| /** |
| * Write nullable map to the writer. |
| * |
| * @param writer Writer. |
| * @param map Map to write. |
| */ |
| public static <K, V> void writeNullableMap(BinaryRawWriterEx writer, @Nullable Map<K, V> map) { |
| if (map != null) { |
| writer.writeBoolean(true); |
| |
| writeMap(writer, map); |
| } |
| else |
| writer.writeBoolean(false); |
| } |
| |
| /** |
| * Write nullable map to the writer. |
| * |
| * @param writer Writer. |
| * @param map Map to write. |
| */ |
| public static <K, V> void writeMap(BinaryRawWriterEx writer, Map<K, V> map) { |
| assert map != null; |
| |
| writeMap(writer, map, null); |
| } |
| |
| /** |
| * Write nullable map to the writer. |
| * |
| * @param writer Writer. |
| * @param map Map to write. |
| * @param writeClo Writer closure. |
| */ |
| public static <K, V> void writeMap(BinaryRawWriterEx writer, Map<K, V> map, |
| @Nullable PlatformWriterBiClosure<K, V> writeClo) { |
| assert map != null; |
| |
| writer.writeInt(map.size()); |
| |
| if (writeClo == null) { |
| for (Map.Entry<K, V> entry : map.entrySet()) { |
| writer.writeObject(entry.getKey()); |
| writer.writeObject(entry.getValue()); |
| } |
| } |
| else { |
| for (Map.Entry<K, V> entry : map.entrySet()) |
| writeClo.write(writer, entry.getKey(), entry.getValue()); |
| } |
| } |
| |
| /** |
| * Read collection. |
| * |
| * @param reader Reader. |
| * @return List. |
| */ |
| public static <T> List<T> readCollection(BinaryRawReaderEx reader) { |
| return readCollection(reader, null); |
| } |
| |
| /** |
| * Read collection. |
| * |
| * @param reader Reader. |
| * @param readClo Optional reader closure. |
| * @return List. |
| */ |
| public static <T> List<T> readCollection(BinaryRawReaderEx reader, @Nullable PlatformReaderClosure<T> readClo) { |
| int cnt = reader.readInt(); |
| |
| List<T> res = new ArrayList<>(cnt); |
| |
| if (readClo == null) { |
| for (int i = 0; i < cnt; i++) |
| res.add((T)reader.readObjectDetached()); |
| } |
| else { |
| for (int i = 0; i < cnt; i++) |
| res.add(readClo.read(reader)); |
| } |
| |
| return res; |
| } |
| |
| /** |
| * Read nullable collection. |
| * |
| * @param reader Reader. |
| * @return List. |
| */ |
| public static <T> List<T> readNullableCollection(BinaryRawReaderEx reader) { |
| return readNullableCollection(reader, null); |
| } |
| |
| /** |
| * Read nullable collection. |
| * |
| * @param reader Reader. |
| * @return List. |
| */ |
| public static <T> List<T> readNullableCollection(BinaryRawReaderEx reader, |
| @Nullable PlatformReaderClosure<T> readClo) { |
| if (!reader.readBoolean()) |
| return null; |
| |
| return readCollection(reader, readClo); |
| } |
| |
| /** |
| * @param reader Reader. |
| * @return Set. |
| */ |
| public static <T> Set<T> readSet(BinaryRawReaderEx reader) { |
| int cnt = reader.readInt(); |
| |
| Set<T> res = U.newHashSet(cnt); |
| |
| for (int i = 0; i < cnt; i++) |
| res.add((T)reader.readObjectDetached()); |
| |
| return res; |
| } |
| |
| /** |
| * @param reader Reader. |
| * @return Set. |
| */ |
| public static <T> Set<T> readNullableSet(BinaryRawReaderEx reader) { |
| if (!reader.readBoolean()) |
| return null; |
| |
| return readSet(reader); |
| } |
| |
| /** |
| * Read map. |
| * |
| * @param reader Reader. |
| * @return Map. |
| */ |
| public static <K, V> Map<K, V> readMap(BinaryRawReaderEx reader) { |
| return readMap(reader, null); |
| } |
| |
| /** |
| * Read map. |
| * |
| * @param reader Reader. |
| * @param readClo Reader closure. |
| * @return Map. |
| */ |
| public static <K, V> Map<K, V> readMap(BinaryRawReaderEx reader, |
| @Nullable PlatformReaderBiClosure<K, V> readClo) { |
| int cnt = reader.readInt(); |
| |
| Map<K, V> map = U.newHashMap(cnt); |
| |
| if (readClo == null) { |
| for (int i = 0; i < cnt; i++) |
| map.put((K)reader.readObjectDetached(), (V)reader.readObjectDetached()); |
| } |
| else { |
| for (int i = 0; i < cnt; i++) { |
| IgniteBiTuple<K, V> entry = readClo.read(reader); |
| |
| map.put(entry.getKey(), entry.getValue()); |
| } |
| } |
| |
| return map; |
| } |
| |
| /** |
| * Read linked map. |
| * |
| * @param reader Reader. |
| * @param readClo Reader closure. |
| * @return Map. |
| */ |
| public static <K, V> Map<K, V> readLinkedMap(BinaryRawReaderEx reader, |
| @Nullable PlatformReaderBiClosure<K, V> readClo) { |
| int cnt = reader.readInt(); |
| |
| Map<K, V> map = U.newLinkedHashMap(cnt); |
| |
| if (readClo == null) { |
| for (int i = 0; i < cnt; i++) |
| map.put((K)reader.readObjectDetached(), (V)reader.readObjectDetached()); |
| } |
| else { |
| for (int i = 0; i < cnt; i++) { |
| IgniteBiTuple<K, V> entry = readClo.read(reader); |
| |
| map.put(entry.getKey(), entry.getValue()); |
| } |
| } |
| |
| return map; |
| } |
| |
| /** |
| * Read nullable map. |
| * |
| * @param reader Reader. |
| * @return Map. |
| */ |
| public static <K, V> Map<K, V> readNullableMap(BinaryRawReaderEx reader) { |
| if (!reader.readBoolean()) |
| return null; |
| |
| return readMap(reader); |
| } |
| |
| /** |
| * Writes IgniteUuid to a writer. |
| * |
| * @param writer Writer. |
| * @param val Values. |
| */ |
| public static void writeIgniteUuid(BinaryRawWriterEx writer, IgniteUuid val) { |
| if (val == null) |
| writer.writeUuid(null); |
| else { |
| writer.writeUuid(val.globalId()); |
| writer.writeLong(val.localId()); |
| } |
| } |
| |
| /** |
| * Convert native cache peek modes to Java cache peek modes. |
| * |
| * @param modes Encoded peek modes. |
| * @return Cache peek modes. |
| */ |
| public static CachePeekMode[] decodeCachePeekModes(int modes) { |
| // 1. Try getting cache value. |
| CachePeekMode[] res = CACHE_PEEK_MODES[modes]; |
| |
| if (res == null) { |
| // 2. Calculate modes from scratch. |
| List<CachePeekMode> res0 = new ArrayList<>(CACHE_PEEK_MODES_CNT); |
| |
| for (int i = 0; i < CACHE_PEEK_MODES_CNT; i++) { |
| int mask = 1 << i; |
| |
| if ((modes & mask) == mask) |
| res0.add(CachePeekMode.fromOrdinal((byte)i)); |
| } |
| |
| res = res0.toArray(new CachePeekMode[res0.size()]); |
| |
| synchronized (PlatformUtils.class) { |
| CACHE_PEEK_MODES[modes] = res; |
| } |
| } |
| |
| return res; |
| } |
| |
| /** |
| * Unwrap query exception. |
| * |
| * @param err Initial error. |
| * @return Unwrapped error. |
| */ |
| public static IgniteCheckedException unwrapQueryException(Throwable err) { |
| assert err != null; |
| |
| Throwable parent = err; |
| Throwable child = parent.getCause(); |
| |
| while (true) { |
| if (child == null || child == parent) |
| break; |
| |
| if (child instanceof IgniteException || child instanceof IgniteCheckedException |
| || child instanceof CacheException) { |
| // Continue unwrapping. |
| parent = child; |
| |
| child = parent.getCause(); |
| |
| continue; |
| } |
| |
| break; |
| } |
| |
| // Specific exception found, but detailed message doesn't exist. Just pass exception name then. |
| if (parent.getMessage() == null) |
| return new IgniteCheckedException("Query execution failed due to exception: " + |
| parent.getClass().getName(), err); |
| |
| return new IgniteCheckedException(parent.getMessage(), err); |
| } |
| |
| /** |
| * Apply continuous query events to listener. |
| * |
| * @param ctx Context. |
| * @param lsnrPtr Listener pointer. |
| * @param evts Events. |
| * @throws javax.cache.event.CacheEntryListenerException In case of failure. |
| */ |
| public static void applyContinuousQueryEvents(PlatformContext ctx, long lsnrPtr, Iterable<CacheEntryEvent> evts) |
| throws CacheEntryListenerException { |
| assert lsnrPtr != 0; |
| assert evts != null; |
| |
| try (PlatformMemory mem = ctx.memory().allocate()) { |
| PlatformOutputStream out = mem.output(); |
| |
| BinaryRawWriterEx writer = ctx.writer(out); |
| |
| writer.writeLong(lsnrPtr); |
| |
| int cntPos = writer.reserveInt(); |
| |
| int cnt = 0; |
| |
| for (CacheEntryEvent evt : evts) { |
| writeCacheEntryEvent(writer, evt); |
| |
| cnt++; |
| } |
| |
| writer.writeInt(cntPos, cnt); |
| |
| out.synchronize(); |
| |
| ctx.gateway().continuousQueryListenerApply(mem.pointer()); |
| } |
| catch (Exception e) { |
| throw toCacheEntryListenerException(e); |
| } |
| } |
| |
| /** |
| * Evaluate the filter. |
| * |
| * @param ctx Context. |
| * @param filterPtr Native filter pointer. |
| * @param evt Event. |
| * @return Result. |
| * @throws CacheEntryListenerException In case of failure. |
| */ |
| public static boolean evaluateContinuousQueryEvent(PlatformContext ctx, long filterPtr, CacheEntryEvent evt) |
| throws CacheEntryListenerException { |
| assert filterPtr != 0; |
| |
| try (PlatformMemory mem = ctx.memory().allocate()) { |
| PlatformOutputStream out = mem.output(); |
| |
| out.writeLong(filterPtr); |
| |
| writeCacheEntryEvent(ctx.writer(out), evt); |
| |
| out.synchronize(); |
| |
| return ctx.gateway().continuousQueryFilterApply(mem.pointer()) == 1; |
| } |
| catch (Exception e) { |
| throw toCacheEntryListenerException(e); |
| } |
| } |
| |
| /** |
| * Convert exception into listener exception. |
| * |
| * @param e Listener exception. |
| * @return Exception. |
| */ |
| private static CacheEntryListenerException toCacheEntryListenerException(Exception e) { |
| assert e != null; |
| |
| return e instanceof CacheEntryListenerException ? (CacheEntryListenerException)e : e.getMessage() != null ? |
| new CacheEntryListenerException(e.getMessage(), e) : new CacheEntryListenerException(e); |
| } |
| |
| /** |
| * Write event to the writer. |
| * |
| * @param writer Writer. |
| * @param evt Event. |
| */ |
| private static void writeCacheEntryEvent(BinaryRawWriterEx writer, CacheEntryEvent evt) { |
| writer.writeObjectDetached(evt.getKey()); |
| writer.writeObjectDetached(evt.getOldValue()); |
| writer.writeObjectDetached(evt.getValue()); |
| writeEventType(writer, evt.getEventType()); |
| } |
| |
| /** |
| * Write event type to the writer. |
| * @param writer Writer. |
| * @param evtType Type of event. |
| */ |
| private static void writeEventType(BinaryRawWriterEx writer, EventType evtType) { |
| switch (evtType){ |
| case CREATED: writer.writeByte((byte) 0); break; |
| case UPDATED: writer.writeByte((byte) 1); break; |
| case REMOVED: writer.writeByte((byte) 2); break; |
| case EXPIRED: writer.writeByte((byte) 3); break; |
| default: |
| throw new IllegalArgumentException("Unknown event type: " + evtType); |
| } |
| } |
| |
| /** |
| * Writes error. |
| * |
| * @param ex Error. |
| * @param writer Writer. |
| */ |
| @SuppressWarnings("ThrowableResultOfMethodCallIgnored") |
| public static void writeError(Throwable ex, BinaryRawWriterEx writer) { |
| writer.writeObjectDetached(ex.getClass().getName()); |
| |
| writer.writeObjectDetached(ex.getMessage()); |
| |
| writer.writeObjectDetached(X.getFullStackTrace(ex)); |
| |
| PlatformNativeException nativeCause = X.cause(ex, PlatformNativeException.class); |
| |
| if (nativeCause != null) { |
| writer.writeBoolean(true); |
| |
| writer.writeObjectDetached(nativeCause.cause()); |
| } |
| else |
| writer.writeBoolean(false); |
| } |
| |
| /** |
| * Writer error data. |
| * |
| * @param err Error. |
| * @param writer Writer. |
| */ |
| public static void writeErrorData(Throwable err, BinaryRawWriterEx writer) { |
| writeErrorData(err, writer, null); |
| } |
| |
| /** |
| * Write error data. |
| * @param err Error. |
| * @param writer Writer. |
| * @param log Optional logger. |
| */ |
| public static void writeErrorData(Throwable err, BinaryRawWriterEx writer, @Nullable IgniteLogger log) { |
| // Write additional data if needed. |
| if (err instanceof PlatformExtendedException) { |
| PlatformExtendedException err0 = (PlatformExtendedException)err; |
| |
| writer.writeBoolean(true); // Data exists. |
| |
| int pos = writer.out().position(); |
| |
| try { |
| writer.writeBoolean(true); // Optimistically assume that we will be able to write it. |
| err0.writeData(writer); |
| } |
| catch (Exception e) { |
| if (log != null) |
| U.warn(log, "Failed to write interop exception data: " + e.getMessage(), e); |
| |
| writer.out().position(pos); |
| |
| writer.writeBoolean(false); // Error occurred. |
| writer.writeString(e.getClass().getName()); |
| |
| String innerMsg; |
| |
| try { |
| innerMsg = e.getMessage(); |
| } |
| catch (Exception ignored) { |
| innerMsg = "Exception message is not available."; |
| } |
| |
| writer.writeString(innerMsg); |
| } |
| } |
| else |
| writer.writeBoolean(false); |
| } |
| |
| /** |
| * Get GridGain platform processor. |
| * |
| * @param grid Ignite instance. |
| * @return Platform processor. |
| */ |
| public static PlatformProcessor platformProcessor(Ignite grid) { |
| GridKernalContext ctx = ((IgniteKernal) grid).context(); |
| |
| return ctx.platform(); |
| } |
| |
| /** |
| * Gets interop context for the grid. |
| * |
| * @param grid Grid |
| * @return Context. |
| */ |
| public static PlatformContext platformContext(Ignite grid) { |
| return platformProcessor(grid).context(); |
| } |
| |
| /** |
| * Reallocate arbitrary memory chunk. |
| * |
| * @param memPtr Memory pointer. |
| * @param cap Capacity. |
| */ |
| public static void reallocate(long memPtr, int cap) { |
| PlatformMemoryUtils.reallocate(memPtr, cap); |
| } |
| |
| /** |
| * Get error data. |
| * |
| * @param err Error. |
| * @return Error data. |
| */ |
| @SuppressWarnings("UnusedDeclaration") |
| public static byte[] errorData(Throwable err) { |
| if (err instanceof PlatformExtendedException) { |
| PlatformContext ctx = ((PlatformExtendedException)err).context(); |
| |
| try (PlatformMemory mem = ctx.memory().allocate()) { |
| // Write error data. |
| PlatformOutputStream out = mem.output(); |
| |
| BinaryRawWriterEx writer = ctx.writer(out); |
| |
| try { |
| PlatformUtils.writeErrorData(err, writer, ctx.kernalContext().log(PlatformContext.class)); |
| } |
| finally { |
| out.synchronize(); |
| } |
| |
| // Read error data into separate array. |
| PlatformInputStream in = mem.input(); |
| |
| in.synchronize(); |
| |
| int len = in.remaining(); |
| |
| assert len > 0; |
| |
| byte[] arr = in.array(); |
| byte[] res = new byte[len]; |
| |
| System.arraycopy(arr, 0, res, 0, len); |
| |
| return res; |
| } |
| } |
| else |
| return null; |
| } |
| |
| /** |
| * Writes invocation result (of a job/service/etc) using a common protocol. |
| * |
| * @param writer Writer. |
| * @param resObj Result. |
| * @param err Error. |
| */ |
| public static void writeInvocationResult(BinaryRawWriterEx writer, Object resObj, Throwable err) |
| { |
| if (err == null) { |
| writer.writeBoolean(true); |
| writer.writeObject(resObj); |
| } |
| else { |
| writer.writeBoolean(false); |
| |
| PlatformNativeException nativeErr = null; |
| |
| if (err instanceof IgniteCheckedException) |
| nativeErr = ((IgniteCheckedException)err).getCause(PlatformNativeException.class); |
| else if (err instanceof IgniteException) |
| nativeErr = ((IgniteException)err).getCause(PlatformNativeException.class); |
| |
| if (nativeErr == null) { |
| writer.writeBoolean(false); |
| writer.writeString(err.getClass().getName()); |
| writer.writeString(err.getMessage()); |
| writer.writeString(X.getFullStackTrace(err)); |
| } |
| else { |
| writer.writeBoolean(true); |
| writer.writeObject(nativeErr.cause()); |
| } |
| } |
| } |
| |
| /** |
| * Reads invocation result (of a job/service/etc) using a common protocol. |
| * |
| * @param ctx Platform context. |
| * @param reader Reader. |
| * @return Result. |
| * @throws IgniteCheckedException When invocation result is an error. |
| */ |
| public static Object readInvocationResult(PlatformContext ctx, BinaryRawReaderEx reader) |
| throws IgniteCheckedException { |
| // 1. Read success flag. |
| boolean success = reader.readBoolean(); |
| |
| if (success) |
| // 2. Return result as is. |
| return reader.readObjectDetached(); |
| else { |
| // 3. Read whether exception is in form of object or string. |
| boolean hasException = reader.readBoolean(); |
| |
| if (hasException) { |
| // 4. Full exception. |
| Object nativeErr = reader.readObjectDetached(); |
| |
| assert nativeErr != null; |
| |
| throw ctx.createNativeException(nativeErr); |
| } |
| else { |
| // 5. Native exception was not serializable, we have only message. |
| String errMsg = reader.readString(); |
| |
| assert errMsg != null; |
| |
| throw new IgniteCheckedException(errMsg); |
| } |
| } |
| } |
| |
| /** |
| * Create binary marshaller. |
| * |
| * @return Marshaller. |
| */ |
| @SuppressWarnings("deprecation") |
| public static GridBinaryMarshaller marshaller() { |
| BinaryContext ctx = |
| new BinaryContext(BinaryNoopMetadataHandler.instance(), new IgniteConfiguration(), new NullLogger()); |
| |
| BinaryMarshaller marsh = new BinaryMarshaller(); |
| |
| marsh.setContext(new MarshallerContextImpl(null, null)); |
| |
| ctx.configure(marsh, new IgniteConfiguration()); |
| |
| return new GridBinaryMarshaller(ctx); |
| } |
| |
| /** |
| * @param o Object to unwrap. |
| * @return Unwrapped object. |
| */ |
| private static Object unwrapBinary(Object o) { |
| if (o == null) |
| return null; |
| |
| if (knownArray(o)) |
| return o; |
| |
| if (o instanceof Map.Entry) { |
| Map.Entry entry = (Map.Entry)o; |
| |
| Object key = entry.getKey(); |
| |
| Object uKey = unwrapBinary(key); |
| |
| Object val = entry.getValue(); |
| |
| Object uVal = unwrapBinary(val); |
| |
| return (key != uKey || val != uVal) ? F.t(uKey, uVal) : o; |
| } |
| else if (BinaryUtils.knownCollection(o)) |
| return unwrapKnownCollection((Collection<Object>)o); |
| else if (BinaryUtils.knownMap(o)) |
| return unwrapBinariesIfNeeded((Map<Object, Object>)o); |
| else if (o instanceof Object[]) |
| return unwrapBinariesInArray((Object[])o); |
| else if (o instanceof BinaryObject) |
| return ((BinaryObject)o).deserialize(); |
| |
| return o; |
| } |
| |
| /** |
| * @param obj Obj. |
| * @return True is obj is a known simple type array. |
| */ |
| private static boolean knownArray(Object obj) { |
| return obj instanceof String[] || |
| obj instanceof boolean[] || |
| obj instanceof byte[] || |
| obj instanceof char[] || |
| obj instanceof int[] || |
| obj instanceof long[] || |
| obj instanceof short[] || |
| obj instanceof Timestamp[] || |
| obj instanceof double[] || |
| obj instanceof float[] || |
| obj instanceof UUID[] || |
| obj instanceof BigDecimal[]; |
| } |
| |
| /** |
| * @param o Object to test. |
| * @return True if collection should be recursively unwrapped. |
| */ |
| private static boolean knownCollection(Object o) { |
| Class<?> cls = o == null ? null : o.getClass(); |
| |
| return cls == ArrayList.class || cls == LinkedList.class || cls == HashSet.class; |
| } |
| |
| /** |
| * @param o Object to test. |
| * @return True if map should be recursively unwrapped. |
| */ |
| private static boolean knownMap(Object o) { |
| Class<?> cls = o == null ? null : o.getClass(); |
| |
| return cls == HashMap.class || cls == LinkedHashMap.class; |
| } |
| |
| /** |
| * @param col Collection to unwrap. |
| * @return Unwrapped collection. |
| */ |
| @SuppressWarnings("TypeMayBeWeakened") |
| private static Collection<Object> unwrapKnownCollection(Collection<Object> col) { |
| Collection<Object> col0 = BinaryUtils.newKnownCollection(col); |
| |
| for (Object obj : col) |
| col0.add(unwrapBinary(obj)); |
| |
| return (col0 instanceof MutableSingletonList) ? U.convertToSingletonList(col0) : col0; |
| } |
| |
| /** |
| * Unwrap array of binaries if needed. |
| * |
| * @param arr Array. |
| * @return Result. |
| */ |
| public static Object[] unwrapBinariesInArray(Object[] arr) { |
| Object[] res = new Object[arr.length]; |
| |
| for (int i = 0; i < arr.length; i++) |
| res[i] = unwrapBinary(arr[i]); |
| |
| return res; |
| } |
| |
| /** |
| * Unwraps map. |
| * |
| * @param map Map to unwrap. |
| * @return Unwrapped collection. |
| */ |
| private static Map<Object, Object> unwrapBinariesIfNeeded(Map<Object, Object> map) { |
| Map<Object, Object> map0 = BinaryUtils.newMap(map); |
| |
| for (Map.Entry<Object, Object> e : map.entrySet()) |
| map0.put(unwrapBinary(e.getKey()), unwrapBinary(e.getValue())); |
| |
| return map0; |
| } |
| /** |
| * 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); |
| } |
| } |
| } |
| |
| /** |
| * Gets the entire nested stack-trace of an throwable. |
| * |
| * @param throwable The {@code Throwable} to be examined. |
| * @return The nested stack trace, with the root cause first. |
| */ |
| public static String getFullStackTrace(Throwable throwable) { |
| return X.getFullStackTrace(throwable); |
| } |
| |
| /** |
| * Gets the schema. |
| * |
| * @param cacheObjProc Cache object processor. |
| * @param typeId Type id. |
| * @param schemaId Schema id. |
| */ |
| public static int[] getSchema(CacheObjectBinaryProcessorImpl cacheObjProc, int typeId, int schemaId) { |
| assert cacheObjProc != null; |
| |
| BinarySchemaRegistry schemaReg = cacheObjProc.binaryContext().schemaRegistry(typeId); |
| BinarySchema schema = schemaReg.schema(schemaId); |
| |
| if (schema == null) { |
| BinaryTypeImpl meta = (BinaryTypeImpl)cacheObjProc.metadata(typeId); |
| |
| if (meta != null) { |
| for (BinarySchema typeSchema : meta.metadata().schemas()) { |
| if (schemaId == typeSchema.schemaId()) { |
| schema = typeSchema; |
| break; |
| } |
| } |
| } |
| |
| if (schema != null) { |
| schemaReg.addSchema(schemaId, schema); |
| } |
| } |
| |
| return schema == null ? null : schema.fieldIds(); |
| } |
| |
| /** |
| * Writes the binary metadata to a writer. |
| * |
| * @param writer Writer. |
| * @param meta Meta. |
| */ |
| public static void writeBinaryMetadata(BinaryRawWriter writer, BinaryMetadata meta, boolean includeSchemas) { |
| assert meta != null; |
| |
| Map<String, BinaryFieldMetadata> fields = meta.fieldsMap(); |
| |
| writer.writeInt(meta.typeId()); |
| writer.writeString(meta.typeName()); |
| writer.writeString(meta.affinityKeyFieldName()); |
| |
| writer.writeInt(fields.size()); |
| |
| for (Map.Entry<String, BinaryFieldMetadata> e : fields.entrySet()) { |
| writer.writeString(e.getKey()); |
| |
| writer.writeInt(e.getValue().typeId()); |
| writer.writeInt(e.getValue().fieldId()); |
| } |
| |
| if (meta.isEnum()) { |
| writer.writeBoolean(true); |
| |
| Map<String, Integer> enumMap = meta.enumMap(); |
| |
| writer.writeInt(enumMap.size()); |
| |
| for (Map.Entry<String, Integer> e: enumMap.entrySet()) { |
| writer.writeString(e.getKey()); |
| writer.writeInt(e.getValue()); |
| } |
| } |
| else { |
| writer.writeBoolean(false); |
| } |
| |
| if (!includeSchemas) { |
| return; |
| } |
| |
| // Schemas. |
| Collection<BinarySchema> schemas = meta.schemas(); |
| |
| writer.writeInt(schemas.size()); |
| |
| for (BinarySchema schema : schemas) { |
| writer.writeInt(schema.schemaId()); |
| |
| int[] ids = schema.fieldIds(); |
| writer.writeInt(ids.length); |
| |
| for (int id : ids) { |
| writer.writeInt(id); |
| } |
| } |
| } |
| |
| /** |
| * Reads the binary metadata. |
| * |
| * @param reader Reader. |
| * @return Collection of metas. |
| */ |
| public static Collection<BinaryMetadata> readBinaryMetadataCollection(BinaryRawReaderEx reader) { |
| return readCollection(reader, |
| new PlatformReaderClosure<BinaryMetadata>() { |
| @Override public BinaryMetadata read(BinaryRawReaderEx reader) { |
| return readBinaryMetadata(reader); |
| } |
| } |
| ); |
| } |
| |
| /** |
| * Reads the binary metadata. |
| * |
| * @param reader Reader. |
| * @return Binary type metadata. |
| */ |
| public static BinaryMetadata readBinaryMetadata(BinaryRawReaderEx reader) { |
| int typeId = reader.readInt(); |
| String typeName = reader.readString(); |
| String affKey = reader.readString(); |
| |
| Map<String, BinaryFieldMetadata> fields = readLinkedMap(reader, |
| new PlatformReaderBiClosure<String, BinaryFieldMetadata>() { |
| @Override |
| public IgniteBiTuple<String, BinaryFieldMetadata> read(BinaryRawReaderEx reader) { |
| String name = reader.readString(); |
| int typeId = reader.readInt(); |
| int fieldId = reader.readInt(); |
| |
| return new IgniteBiTuple<String, BinaryFieldMetadata>(name, |
| new BinaryFieldMetadata(typeId, fieldId)); |
| } |
| }); |
| |
| Map<String, Integer> enumMap = null; |
| |
| boolean isEnum = reader.readBoolean(); |
| |
| if (isEnum) { |
| int size = reader.readInt(); |
| |
| enumMap = new LinkedHashMap<>(size); |
| |
| for (int idx = 0; idx < size; idx++) |
| enumMap.put(reader.readString(), reader.readInt()); |
| } |
| |
| // Read schemas |
| int schemaCnt = reader.readInt(); |
| |
| List<BinarySchema> schemas = null; |
| |
| if (schemaCnt > 0) { |
| schemas = new ArrayList<>(schemaCnt); |
| |
| for (int i = 0; i < schemaCnt; i++) { |
| int id = reader.readInt(); |
| int fieldCnt = reader.readInt(); |
| List<Integer> fieldIds = new ArrayList<>(fieldCnt); |
| |
| for (int j = 0; j < fieldCnt; j++) |
| fieldIds.add(reader.readInt()); |
| |
| schemas.add(new BinarySchema(id, fieldIds)); |
| } |
| } |
| |
| return new BinaryMetadata(typeId, typeName, fields, affKey, schemas, isEnum, enumMap); |
| } |
| |
| /** |
| * Writes node attributes. |
| * |
| * @param writer Writer. |
| * @param attrs Attributes. |
| */ |
| public static void writeNodeAttributes(BinaryRawWriterEx writer, Map<String, Object> attrs) { |
| assert writer != null; |
| assert attrs != null; |
| |
| if (attrs != null) { |
| writer.writeInt(attrs.size()); |
| |
| for (Map.Entry<String, Object> e : attrs.entrySet()) { |
| writer.writeString(e.getKey()); |
| writer.writeObjectDetached(e.getValue()); |
| } |
| } else { |
| writer.writeInt(0); |
| } |
| } |
| |
| /** |
| * Reads node attributes. |
| * |
| * @param reader Reader. |
| * @return Attributes. |
| */ |
| public static Map<String, Object> readNodeAttributes(BinaryRawReaderEx reader) { |
| assert reader != null; |
| |
| int attrCnt = reader.readInt(); |
| Map<String, Object> attrs = new HashMap<>(attrCnt); |
| |
| for (int j = 0; j < attrCnt; j++) { |
| attrs.put(reader.readString(), reader.readObjectDetached()); |
| } |
| |
| return attrs; |
| } |
| |
| /** |
| * Private constructor. |
| */ |
| private PlatformUtils() { |
| // No-op. |
| } |
| } |