blob: e78a980e3ff8fead51a8b8655e8c1595f1ad6cae [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.io.DataInput;
import java.io.DataOutput;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.apache.ignite.internal.util.tostring.GridToStringInclude;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.jetbrains.annotations.Nullable;
/**
* Binary metadata which is passed over a wire.
*/
public class BinaryMetadata implements Externalizable {
/** */
private static final long serialVersionUID = 0L;
/** */
private static final int VERSION = 1;
/** Type ID. */
@GridToStringInclude(sensitive = true)
private int typeId;
/** Type name. */
@GridToStringInclude(sensitive = true)
private String typeName;
/** Recorded object fields. */
@GridToStringInclude(sensitive = true)
private Map<String, BinaryFieldMetadata> fields;
/** Affinity key field name. */
@GridToStringInclude(sensitive = true)
private String affKeyFieldName;
/** Schemas associated with type. */
@GridToStringInclude
private Collection<BinarySchema> schemas;
/** Schema IDs registered for this type */
private Set<Integer> schemaIds;
/** Whether this is enum type. */
private boolean isEnum;
/** Enum name to ordinal mapping. */
private Map<String, Integer> nameToOrdinal;
/** Enum ordinal to name mapping. */
private Map<Integer, String> ordinalToName;
/**
* For {@link Externalizable}.
*/
public BinaryMetadata() {
// No-op.
}
/**
* Constructor.
*
* @param typeId Type ID.
* @param typeName Type name.
* @param fields Fields map.
* @param affKeyFieldName Affinity key field name.
* @param schemas Schemas.
* @param isEnum Enum flag.
* @param enumMap Enum name to ordinal mapping.
*/
public BinaryMetadata(int typeId, String typeName, @Nullable Map<String, BinaryFieldMetadata> fields,
@Nullable String affKeyFieldName, @Nullable Collection<BinarySchema> schemas, boolean isEnum,
@Nullable Map<String, Integer> enumMap) {
assert typeName != null;
this.typeId = typeId;
this.typeName = typeName;
this.fields = fields;
this.affKeyFieldName = affKeyFieldName;
this.schemas = schemas;
if (schemas != null) {
schemaIds = U.newHashSet(schemas.size());
for (BinarySchema schema : schemas)
schemaIds.add(schema.schemaId());
}
else
schemaIds = Collections.emptySet();
this.isEnum = isEnum;
if (enumMap != null) {
this.nameToOrdinal = new LinkedHashMap<>(enumMap);
this.ordinalToName = new LinkedHashMap<>(enumMap.size());
for (Map.Entry<String, Integer> e: nameToOrdinal.entrySet())
this.ordinalToName.put(e.getValue(), e.getKey());
}
}
/**
* @return Type ID.
*/
public int typeId() {
return typeId;
}
/**
* @return Type name.
*/
public String typeName() {
return typeName;
}
/**
* @return Fields.
*/
public Collection<String> fields() {
return fields != null ? fields.keySet() : Collections.<String>emptyList();
}
/**
* @return Fields.
*/
public Map<String, BinaryFieldMetadata> fieldsMap() {
return fields != null ? fields : Collections.<String, BinaryFieldMetadata>emptyMap();
}
/**
* @param fieldName Field name.
* @return Field type name.
*/
@Nullable public String fieldTypeName(String fieldName) {
BinaryFieldMetadata meta = fields != null ? fields.get(fieldName) : null;
return meta != null ? BinaryUtils.fieldTypeName(meta.typeId()) : null;
}
/**
* @return Affinity key field name.
*/
@Nullable public String affinityKeyFieldName() {
return affKeyFieldName;
}
/**
* @return Schemas.
*/
public Collection<BinarySchema> schemas() {
return schemas != null ? schemas : Collections.<BinarySchema>emptyList();
}
/**
* @param schemaId Schema ID.
* @return {@code true} if <b>BinaryMetadata</b> instance has schema with ID specified, {@code false} otherwise.
*/
public boolean hasSchema(int schemaId) {
if (schemaIds == null)
return false;
return schemaIds.contains(schemaId);
}
/**
* @return {@code True} if this is enum type.
*/
public boolean isEnum() {
return isEnum;
}
/**
* Wrap metadata into binary type.
*
* @param ctx Binary context.
* @return Binary type.
*/
public BinaryTypeImpl wrap(BinaryContext ctx) {
return new BinaryTypeImpl(ctx, this);
}
/** {@inheritDoc} */
@Override public void writeExternal(ObjectOutput out) throws IOException {
writeTo(out);
}
/**
* The object implements the writeTo method to save its contents
* by calling the methods of DataOutput for its primitive values and strings or
* calling the writeTo method for other objects.
*
* @param out the stream to write the object to.
* @exception IOException Includes any I/O exceptions that may occur.
*/
public void writeTo(DataOutput out) throws IOException {
out.writeByte(VERSION);
out.writeInt(typeId);
U.writeString(out, typeName);
if (fields == null)
out.writeInt(-1);
else {
out.writeInt(fields.size());
for (Map.Entry<String, BinaryFieldMetadata> fieldEntry : fields.entrySet()) {
U.writeString(out, fieldEntry.getKey());
fieldEntry.getValue().writeTo(out);
}
}
U.writeString(out, affKeyFieldName);
if (schemas == null)
out.writeInt(-1);
else {
out.writeInt(schemas.size());
for (BinarySchema schema : schemas)
schema.writeTo(out);
}
out.writeBoolean(isEnum);
if (isEnum) {
Map<String, Integer> map = enumMap();
out.writeInt(map.size());
for (Map.Entry<String, Integer> e : map.entrySet()) {
U.writeString(out, e.getKey());
out.writeInt(e.getValue());
}
}
}
/** {@inheritDoc} */
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
readFrom(in);
}
/**
* The object implements the readFrom method to restore its
* contents by calling the methods of DataInput for primitive
* types and strings or calling readExternal for other objects. The
* readFrom method must read the values in the same sequence
* and with the same types as were written by writeTo.
*
* @param in the stream to read data from in order to restore the object.
* @exception IOException if I/O errors occur.
*/
public void readFrom(DataInput in) throws IOException {
in.readByte(); //skip version
typeId = in.readInt();
typeName = U.readString(in);
int fieldsSize = in.readInt();
if (fieldsSize == -1)
fields = null;
else {
fields = new HashMap<>();
for (int i = 0; i < fieldsSize; i++) {
String fieldName = U.readString(in);
BinaryFieldMetadata fieldMeta = new BinaryFieldMetadata();
fieldMeta.readFrom(in);
fields.put(fieldName, fieldMeta);
}
}
affKeyFieldName = U.readString(in);
int schemasSize = in.readInt();
if (schemasSize == -1) {
schemas = null;
schemaIds = Collections.emptySet();
}
else {
schemas = new ArrayList<>();
schemaIds = U.newHashSet(schemasSize);
for (int i = 0; i < schemasSize; i++) {
BinarySchema schema = new BinarySchema();
schema.readFrom(in);
schemas.add(schema);
schemaIds.add(schema.schemaId());
}
}
isEnum = in.readBoolean();
if (isEnum) {
int size = in.readInt();
if (size >= 0) {
ordinalToName = new LinkedHashMap<>(size);
nameToOrdinal = new LinkedHashMap<>(size);
for (int idx = 0; idx < size; idx++) {
String name = U.readString(in);
int ord = in.readInt();
ordinalToName.put(ord, name);
nameToOrdinal.put(name, ord);
}
}
}
}
/**
* Gets enum constant name given its ordinal value.
*
* @param ord Enum constant ordinal value.
* @return Enum constant name.
*/
public String getEnumNameByOrdinal(int ord) {
if (ordinalToName == null)
return null;
return ordinalToName.get(ord);
}
/**
* Gets enum constant ordinal value given its name.
*
* @param name Enum constant name.
* @return Enum constant ordinal value.
*/
public Integer getEnumOrdinalByName(String name) {
assert name != null;
return nameToOrdinal.get(name);
}
/**
* @return Name to ordinal mapping.
*/
public Map<String, Integer> enumMap() {
if (nameToOrdinal == null)
return Collections.emptyMap();
return nameToOrdinal;
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(BinaryMetadata.class, this);
}
}