blob: ddf17f0abd4a16ca5fed884188b3bd245ef4ca98 [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.binary;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.IdentityHashMap;
import org.apache.ignite.IgniteException;
import org.apache.ignite.binary.BinaryObjectBuilder;
import org.apache.ignite.internal.binary.builder.BinaryObjectBuilderImpl;
import org.apache.ignite.internal.util.offheap.unsafe.GridUnsafeMemory;
import org.apache.ignite.internal.util.typedef.internal.SB;
import org.apache.ignite.binary.BinaryObjectException;
import org.apache.ignite.binary.BinaryType;
import org.apache.ignite.binary.BinaryObject;
import org.jetbrains.annotations.Nullable;
/**
* Internal binary object interface.
*/
public abstract class BinaryObjectExImpl implements BinaryObjectEx {
/**
* @return Length.
*/
public abstract int length();
/**
* @return Object start.
*/
public abstract int start();
/**
* @return {@code True} if object is array based.
*/
protected abstract boolean hasArray();
/**
* @return Object array if object is array based, otherwise {@code null}.
*/
public abstract byte[] array();
/**
* @return Object offheap address is object is offheap based, otherwise 0.
*/
public abstract long offheapAddress();
/**
* Gets field value.
*
* @param fieldId Field ID.
* @return Field value.
* @throws org.apache.ignite.binary.BinaryObjectException In case of any other error.
*/
@Nullable public abstract <F> F field(int fieldId) throws BinaryObjectException;
/** {@inheritDoc} */
@Override public int enumOrdinal() throws BinaryObjectException {
throw new BinaryObjectException("Object is not enum.");
}
/**
* Get field by offset.
*
* @param fieldOffset Field offset.
* @return Field value.
*/
@Nullable protected abstract <F> F fieldByOrder(int fieldOffset);
/**
* @param ctx Reader context.
* @param fieldName Field name.
* @return Field value.
*/
@Nullable protected abstract <F> F field(BinaryReaderHandles ctx, String fieldName);
/**
* Get schema ID.
*
* @return Schema ID.
*/
protected abstract int schemaId();
/**
* Create schema for object.
*
* @return Schema.
*/
protected abstract BinarySchema createSchema();
/** {@inheritDoc} */
@Override public BinaryObjectBuilder toBuilder() throws BinaryObjectException {
return BinaryObjectBuilderImpl.wrap(this);
}
/** {@inheritDoc} */
@Override public BinaryObject clone() throws CloneNotSupportedException {
return (BinaryObject)super.clone();
}
/** {@inheritDoc} */
public boolean equals(Object other) {
if (other == this)
return true;
if (other == null)
return false;
if (!(other instanceof BinaryObjectExImpl))
return false;
BinaryObjectExImpl otherPo = (BinaryObjectExImpl)other;
if (length() != otherPo.length() || typeId() != otherPo.typeId())
return false;
if (hasArray()) {
if (otherPo.hasArray()) {
int len = length();
int end = start() + len;
byte[] arr = array();
byte[] otherArr = otherPo.array();
for (int i = start(), j = otherPo.start(); i < end; i++, j++) {
if (arr[i] != otherArr[j])
return false;
}
return true;
}
else {
assert otherPo.offheapAddress() > 0;
return GridUnsafeMemory.compare(otherPo.offheapAddress() + otherPo.start(), array());
}
}
else {
assert offheapAddress() > 0;
if (otherPo.hasArray())
return GridUnsafeMemory.compare(offheapAddress() + start(), otherPo.array());
else {
assert otherPo.offheapAddress() > 0;
return GridUnsafeMemory.compare(offheapAddress() + start(),
otherPo.offheapAddress() + otherPo.start(),
length());
}
}
}
/**
* @param ctx Reader context.
* @param handles Handles for already traversed objects.
* @return String representation.
*/
private String toString(BinaryReaderHandles ctx, IdentityHashMap<BinaryObject, Integer> handles) {
int idHash = System.identityHashCode(this);
int hash = hashCode();
BinaryType meta;
try {
meta = type();
}
catch (BinaryObjectException ignore) {
meta = null;
}
if (meta == null)
return BinaryObject.class.getSimpleName() + " [idHash=" + idHash + ", hash=" + hash + ", typeId=" + typeId() + ']';
handles.put(this, idHash);
SB buf = new SB(meta.typeName());
if (meta.fieldNames() != null) {
buf.a(" [idHash=").a(idHash).a(", hash=").a(hash);
for (String name : meta.fieldNames()) {
Object val = field(ctx, name);
buf.a(", ").a(name).a('=');
if (val instanceof byte[])
buf.a(Arrays.toString((byte[]) val));
else if (val instanceof short[])
buf.a(Arrays.toString((short[])val));
else if (val instanceof int[])
buf.a(Arrays.toString((int[])val));
else if (val instanceof long[])
buf.a(Arrays.toString((long[])val));
else if (val instanceof float[])
buf.a(Arrays.toString((float[])val));
else if (val instanceof double[])
buf.a(Arrays.toString((double[])val));
else if (val instanceof char[])
buf.a(Arrays.toString((char[])val));
else if (val instanceof boolean[])
buf.a(Arrays.toString((boolean[]) val));
else if (val instanceof BigDecimal[])
buf.a(Arrays.toString((BigDecimal[])val));
else {
if (val instanceof BinaryObjectExImpl) {
BinaryObjectExImpl po = (BinaryObjectExImpl)val;
Integer idHash0 = handles.get(val);
if (idHash0 != null) { // Circular reference.
BinaryType meta0 = po.type();
assert meta0 != null;
buf.a(meta0.typeName()).a(" [hash=").a(idHash0).a(", ...]");
}
else
buf.a(po.toString(ctx, handles));
}
else
buf.a(val);
}
}
buf.a(']');
}
return buf.toString();
}
/** {@inheritDoc} */
@Override public String toString() {
try {
BinaryReaderHandles ctx = new BinaryReaderHandles();
ctx.put(start(), this);
return toString(ctx, new IdentityHashMap<BinaryObject, Integer>());
}
catch (BinaryObjectException e) {
throw new IgniteException("Failed to create string representation of binary object.", e);
}
}
}