blob: f5f8045162266dcfe810bbb786ef560755c41a7f [file] [log] [blame]
package edu.uci.ics.asterix.external.library.java;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import edu.uci.ics.asterix.common.exceptions.AsterixException;
import edu.uci.ics.asterix.dataflow.data.nontagged.serde.ARecordSerializerDeserializer;
import edu.uci.ics.asterix.dataflow.data.nontagged.serde.AStringSerializerDeserializer;
import edu.uci.ics.asterix.external.library.JTypeObjectFactory;
import edu.uci.ics.asterix.om.base.AInt32;
import edu.uci.ics.asterix.om.base.AMutableInt32;
import edu.uci.ics.asterix.om.base.AMutableOrderedList;
import edu.uci.ics.asterix.om.base.AMutableRecord;
import edu.uci.ics.asterix.om.base.AMutableString;
import edu.uci.ics.asterix.om.base.ARecord;
import edu.uci.ics.asterix.om.base.AString;
import edu.uci.ics.asterix.om.base.IAObject;
import edu.uci.ics.asterix.om.types.AOrderedListType;
import edu.uci.ics.asterix.om.types.ARecordType;
import edu.uci.ics.asterix.om.types.ATypeTag;
import edu.uci.ics.asterix.om.types.AUnionType;
import edu.uci.ics.asterix.om.types.BuiltinType;
import edu.uci.ics.asterix.om.types.EnumDeserializer;
import edu.uci.ics.asterix.om.types.IAType;
import edu.uci.ics.asterix.om.util.NonTaggedFormatUtil;
import edu.uci.ics.asterix.om.util.container.IObjectPool;
import edu.uci.ics.asterix.om.util.container.ListObjectPool;
import edu.uci.ics.hyracks.algebricks.common.exceptions.NotImplementedException;
import edu.uci.ics.hyracks.api.dataflow.value.ISerializerDeserializer;
import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
public class JTypes {
public static final class JInt implements IJObject {
private AMutableInt32 value = new AMutableInt32(0);
public void setValue(int v) {
this.value.setValue(v);
}
public int getValue() {
return value.getIntegerValue().intValue();
}
@Override
public ATypeTag getTypeTag() {
return value.getType().getTypeTag();
}
@Override
public IAObject getIAObject() {
return value;
}
}
public static final class JString implements IJObject {
private AMutableString value = new AMutableString("");
public void setValue(String v) {
this.value.setValue(v);
}
public String getValue() {
return value.getStringValue();
}
@Override
public ATypeTag getTypeTag() {
return value.getType().getTypeTag();
}
@Override
public IAObject getIAObject() {
return value;
}
}
public static final class JList implements IJObject {
private AOrderedListType listType;
private AMutableOrderedList value;
public JList(AOrderedListType listType) {
this.listType = listType;
this.value = new AMutableOrderedList(listType);
}
public void add(IJObject element) {
value.add(element.getIAObject());
}
@Override
public ATypeTag getTypeTag() {
return value.getType().getTypeTag();
}
@Override
public IAObject getIAObject() {
return value;
}
}
public static final class JRecord implements IJObject {
private AMutableRecord value;
private byte[] recordBytes;
private ARecordType recordType;
private List<IJObject> fields;
private List<String> fieldNames;
private List<IAType> fieldTypes;
private final IObjectPool<IJObject, IAType> objectPool = new ListObjectPool<IJObject, IAType>(
new JTypeObjectFactory());
private int numFieldsAdded = 0;
private List<Boolean> openField;
private final static byte SER_NULL_TYPE_TAG = ATypeTag.NULL.serialize();
private final static byte SER_RECORD_TYPE_TAG = ATypeTag.RECORD.serialize();
public JRecord(ARecordType recordType) {
this.recordType = recordType;
this.fields = new ArrayList<IJObject>();
initFieldInfo();
}
public JRecord(ARecordType recordType, IJObject[] fields) {
this.recordType = recordType;
this.fields = new ArrayList<IJObject>();
for (IJObject jObject : fields) {
this.fields.add(jObject);
}
initFieldInfo();
}
private void initFieldInfo() {
this.openField = new ArrayList<Boolean>();
fieldNames = new ArrayList<String>();
for (String name : recordType.getFieldNames()) {
fieldNames.add(name);
openField.add(false);
}
fieldTypes = new ArrayList<IAType>();
for (IAType type : recordType.getFieldTypes()) {
fieldTypes.add(type);
}
}
private IAObject[] getIAObjectArray(List<IJObject> fields) {
IAObject[] retValue = new IAObject[fields.size()];
int index = 0;
for (IJObject jObject : fields) {
retValue[index++] = getIAObject(jObject);
}
return retValue;
}
private IAObject getIAObject(IJObject jObject) {
IAObject retVal = null;
switch (jObject.getTypeTag()) {
case INT32:
case STRING:
retVal = jObject.getIAObject();
break;
case RECORD:
ARecordType recType = ((JRecord) jObject).getRecordType();
IAObject[] fields = new IAObject[((JRecord) jObject).getFields().size()];
int index = 0;
for (IJObject field : ((JRecord) jObject).getFields()) {
fields[index++] = getIAObject(field);
}
retVal = new AMutableRecord(recType, fields);
}
return retVal;
}
public void addField(String fieldName, IJObject fieldValue) {
int pos = getFieldPosByName(fieldName);
if (pos >= 0) {
throw new IllegalArgumentException("field already defined");
}
numFieldsAdded++;
fields.add(fieldValue);
fieldNames.add(fieldName);
fieldTypes.add(fieldValue.getIAObject().getType());
openField.add(true);
}
public IJObject getValueByName(String fieldName) throws AsterixException, IOException {
int fieldPos = getFieldPosByName(fieldName);
if (recordBytes == null) {
IJObject jtype = getJObject(value.getValueByPos(fieldPos));
fields.set(fieldPos, jtype);
return jtype;
}
if (recordBytes[0] == SER_NULL_TYPE_TAG) {
return null;
}
if (recordBytes[0] != SER_RECORD_TYPE_TAG) {
throw new AsterixException("Field accessor is not defined for values of type"
+ EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(recordBytes[0]));
}
int fieldValueOffset = ARecordSerializerDeserializer.getFieldOffsetById(recordBytes, fieldPos,
getNullBitMapSize(), recordType.isOpen());
if (fieldValueOffset < 0) {
return null;
}
IAType fieldValueType = recordType.getFieldTypes()[fieldPos];
ATypeTag fieldValueTypeTag = null;
int fieldValueLength = 0;
if (fieldValueType.getTypeTag().equals(ATypeTag.UNION)) {
if (NonTaggedFormatUtil.isOptionalField((AUnionType) fieldValueType)) {
fieldValueTypeTag = ((AUnionType) fieldValueType).getUnionList()
.get(NonTaggedFormatUtil.OPTIONAL_TYPE_INDEX_IN_UNION_LIST).getTypeTag();
fieldValueLength = NonTaggedFormatUtil.getFieldValueLength(recordBytes, fieldValueOffset,
fieldValueTypeTag, false);
// out.writeByte(fieldValueTypeTag.serialize());
} else {
// union .. the general case
throw new NotImplementedException();
}
} else {
fieldValueTypeTag = fieldValueType.getTypeTag();
fieldValueLength = NonTaggedFormatUtil.getFieldValueLength(recordBytes, fieldValueOffset,
fieldValueTypeTag, false);
// out.writeByte(fieldValueTypeTag.serialize());
}
IJObject fieldValue = getJType(fieldValueTypeTag, recordBytes, fieldValueOffset, fieldValueLength, fieldPos);
fields.set(fieldPos, fieldValue);
return fieldValue;
}
public void setValue(byte[] recordBytes) {
this.recordBytes = recordBytes;
}
public void setValueAtPos(int pos, IJObject jtype) {
fields.set(pos, jtype);
}
public void setValue(AMutableRecord mutableRecord) {
this.value = mutableRecord;
this.recordType = mutableRecord.getType();
}
@Override
public ATypeTag getTypeTag() {
return recordType.getTypeTag();
}
public void setField(String fieldName, IJObject fieldValue) {
int pos = getFieldPosByName(fieldName);
switch (fields.get(pos).getTypeTag()) {
case INT32:
((JInt) fields.get(pos)).setValue(((AMutableInt32) fieldValue.getIAObject()).getIntegerValue()
.intValue());
break;
case STRING:
((JString) fields.get(pos)).setValue(((AMutableString) fieldValue.getIAObject()).getStringValue());
break;
case RECORD:
((JRecord) fields.get(pos)).setValue(((AMutableRecord) fieldValue));
break;
}
}
private int getFieldPosByName(String fieldName) {
int index = 0;
for (String name : fieldNames) {
if (name.equals(fieldName)) {
return index;
}
index++;
}
return -1;
}
private IJObject getJType(ATypeTag typeTag, byte[] argument, int offset, int len, int fieldIndex)
throws HyracksDataException {
IJObject jObject;
switch (typeTag) {
case INT32: {
int v = valueFromBytes(argument, offset, len);
jObject = objectPool.allocate(BuiltinType.AINT32);
((JInt) jObject).setValue(v);
break;
}
case STRING: {
String v = AStringSerializerDeserializer.INSTANCE.deserialize(
new DataInputStream(new ByteArrayInputStream(argument, offset, len))).getStringValue();
jObject = objectPool.allocate(BuiltinType.ASTRING);
((JString) jObject).setValue(v);
break;
}
case RECORD:
ARecordType fieldRecordType = (ARecordType) recordType.getFieldTypes()[fieldIndex];
jObject = objectPool.allocate(fieldRecordType);
byte[] recBytes = new byte[len];
System.arraycopy(argument, offset, recBytes, 0, len);
((JRecord) jObject).setValue(argument);
break;
default:
throw new IllegalStateException("Argument type: " + typeTag);
}
return jObject;
}
private IJObject getJObject(IAObject iaobject) throws HyracksDataException {
ATypeTag typeTag = iaobject.getType().getTypeTag();
IJObject jtype;
switch (typeTag) {
case INT32: {
int v = ((AInt32) iaobject).getIntegerValue().intValue();
jtype = new JInt();
((JInt) jtype).setValue(v);
break;
}
case STRING: {
jtype = new JString();
((JString) jtype).setValue(((AString) iaobject).getStringValue());
break;
}
case RECORD:
ARecordType fieldRecordType = ((ARecord) iaobject).getType();
jtype = new JRecord(fieldRecordType);
((JRecord) jtype).setValue((AMutableRecord) iaobject);
break;
default:
throw new IllegalStateException("Argument type: " + typeTag);
}
return jtype;
}
private static int valueFromBytes(byte[] bytes, int offset, int length) {
return ((bytes[offset] & 0xff) << 24) + ((bytes[offset + 1] & 0xff) << 16)
+ ((bytes[offset + 2] & 0xff) << 8) + ((bytes[offset + 3] & 0xff) << 0);
}
public ARecordType getRecordType() {
return recordType;
}
public List<IJObject> getFields() {
return fields;
}
@Override
public IAObject getIAObject() {
if (value == null || numFieldsAdded > 0) {
value = new AMutableRecord(recordType, getIAObjectArray(fields));
}
return value;
}
public void close() {
objectPool.reset();
if (numFieldsAdded > 0) {
int totalFields = fieldNames.size();
for (int i = 0; i < numFieldsAdded; i++) {
fieldNames.remove(totalFields - 1 - i);
fieldTypes.remove(totalFields - 1 - i);
fields.remove(totalFields - 1 - i);
}
numFieldsAdded = 0;
}
}
private int getNullBitMapSize() {
int nullBitmapSize = 0;
if (NonTaggedFormatUtil.hasNullableField(recordType)) {
nullBitmapSize = (int) Math.ceil(recordType.getFieldNames().length / 8.0);
} else {
nullBitmapSize = 0;
}
return nullBitmapSize;
}
public List<Boolean> getOpenField() {
return openField;
}
public List<String> getFieldNames() {
return fieldNames;
}
public List<IAType> getFieldTypes() {
return fieldTypes;
}
}
}