blob: 58eff96b98c9babb130a7c2f33464795ec23ade3 [file] [log] [blame]
/*
* 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.cache;
import java.nio.ByteBuffer;
import org.apache.ignite.events.CacheObjectTransformedEvent;
import org.apache.ignite.internal.cache.transform.CacheObjectTransformerProcessor;
import org.apache.ignite.internal.util.typedef.internal.U;
import static org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_TRANSFORMED;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.TRANSFORMED;
/** */
public class CacheObjectTransformerUtils {
/** */
private static CacheObjectTransformerProcessor transformer(CacheObjectValueContext ctx) {
return ctx.kernalContext().transformer();
}
/**
* Transforms bytes according to {@link CacheObjectTransformerProcessor} when specified.
* @param bytes Given bytes.
* @param ctx Context.
* @return Transformed bytes.
*/
public static byte[] transformIfNecessary(byte[] bytes, CacheObjectValueContext ctx) {
return transformIfNecessary(bytes, 0, bytes.length, ctx);
}
/**
* Transforms bytes according to {@link CacheObjectTransformerProcessor} when specified.
* @param bytes Given bytes.
* @param ctx Context.
* @return Transformed bytes.
*/
public static byte[] transformIfNecessary(byte[] bytes, int offset, int length, CacheObjectValueContext ctx) {
assert bytes[offset] != TRANSFORMED;
CacheObjectTransformerProcessor transformer = transformer(ctx);
if (transformer == null)
return bytes;
ByteBuffer src = ByteBuffer.wrap(bytes, offset, length);
ByteBuffer transformed = transformer.transform(src);
if (transformed != null) {
assert transformed.remaining() > 0 : transformed.remaining();
byte[] res = toArray(transformed);
if (recordable(ctx, EVT_CACHE_OBJECT_TRANSFORMED)) {
ctx.kernalContext().event().record(
new CacheObjectTransformedEvent(ctx.kernalContext().discovery().localNode(),
"Object transformed",
EVT_CACHE_OBJECT_TRANSFORMED,
detachIfNecessary(bytes, offset, length),
res,
false));
}
return res;
}
else {
byte[] res = detachIfNecessary(bytes, offset, length);
if (recordable(ctx, EVT_CACHE_OBJECT_TRANSFORMED)) {
ctx.kernalContext().event().record(
new CacheObjectTransformedEvent(ctx.kernalContext().discovery().localNode(),
"Object transformation was cancelled.",
EVT_CACHE_OBJECT_TRANSFORMED,
res,
res,
false));
}
return res;
}
}
/**
*
*/
private static byte[] detachIfNecessary(byte[] bytes, int offset, int length) {
if (offset == 0 && length == bytes.length)
return bytes;
byte[] res = new byte[length];
U.arrayCopy(bytes, offset, res, 0, length);
return res;
}
/**
* Restores transformed bytes if necessary.
* @param bytes Given bytes.
* @param ctx Context.
* @return Restored bytes.
*/
public static byte[] restoreIfNecessary(byte[] bytes, CacheObjectValueContext ctx) {
if (bytes[0] != TRANSFORMED)
return bytes;
CacheObjectTransformerProcessor transformer = transformer(ctx);
ByteBuffer src = ByteBuffer.wrap(bytes, 1, bytes.length - 1); // Skipping TRANSFORMED.
ByteBuffer restored = transformer.restore(src);
byte[] res = toArray(restored);
if (recordable(ctx, EVT_CACHE_OBJECT_TRANSFORMED)) {
ctx.kernalContext().event().record(
new CacheObjectTransformedEvent(ctx.kernalContext().discovery().localNode(),
"Object restored",
EVT_CACHE_OBJECT_TRANSFORMED,
res,
bytes,
true));
}
return res;
}
/**
* @param buf Buffer.
*/
private static byte[] toArray(ByteBuffer buf) {
if (buf.isDirect()) {
byte[] res = new byte[buf.remaining()];
buf.get(res);
return res;
}
else {
if (buf.remaining() != buf.capacity())
throw new IllegalStateException("Unexpected Heap Byte Buffer state. " +
"Wrapped array must contain the data without any offsets to avoid unnecessary copying. " +
"Position must be 0, limit must be equal to the capacity." +
" [buf=" + buf + "]");
return buf.array();
}
}
/**
* @param ctx Context.
* @param type Type.
*/
private static boolean recordable(CacheObjectValueContext ctx, int type) {
return ctx.kernalContext().event() != null // Can be null at external usage (via StandaloneGridKernalContext)
&& ctx.kernalContext().event().isRecordable(type);
}
}