blob: 55121ac1c0b4e1d7675b5e3bc125bcbea7d98457 [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.geode.pdx.internal;
import java.nio.ByteBuffer;
import java.util.Date;
import org.apache.geode.InternalGemFireException;
import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.pdx.PdxFieldDoesNotExistException;
import org.apache.geode.pdx.PdxFieldTypeMismatchException;
import org.apache.geode.pdx.WritablePdxInstance;
public class WritablePdxInstanceImpl extends PdxInstanceImpl implements WritablePdxInstance {
private static final long serialVersionUID = 7398999150097596214L;
private static final Object NULL_TOKEN = new Object();
private Object[] dirtyFields = null;
public WritablePdxInstanceImpl(PdxReaderImpl original) {
super(original);
}
private synchronized void dirtyField(PdxField f, Object value) {
if (dirtyFields == null) {
dirtyFields = new Object[getPdxType().getFieldCount()];
}
if (value == null) {
value = NULL_TOKEN;
}
dirtyFields[f.getFieldIndex()] = value;
clearCachedState();
}
/**
* Flush pending writes if the given field is dirty.
*/
@Override
protected synchronized PdxReaderImpl getUnmodifiableReader(String fieldName) {
if (dirtyFields != null) {
PdxField f = getPdxType().getPdxField(fieldName);
if (f != null) {
if (dirtyFields[f.getFieldIndex()] != null) {
return getUnmodifiableReader();
}
}
}
return new PdxReaderImpl(this);
}
@Override
public synchronized Object getCachedObject() {
return super.getCachedObject();
}
@Override
public synchronized int hashCode() {
return super.hashCode();
}
/**
* Flush any pending writes.
*/
@Override
protected synchronized PdxReaderImpl getUnmodifiableReader() {
if (dirtyFields != null) {
PdxOutputStream os = new PdxOutputStream(basicSize() + PdxWriterImpl.HEADER_SIZE);
PdxWriterImpl writer;
if (getPdxType().getHasDeletedField()) {
// Need a new type that does not have the deleted field
PdxType pt = new PdxType(getPdxType().getClassName(), !getPdxType().getNoDomainClass());
InternalCache cache = GemFireCacheImpl
.getForPdx("PDX registry is unavailable because the Cache has been closed.");
TypeRegistry tr = cache.getPdxRegistry();
writer = new PdxWriterImpl(pt, tr, os);
} else {
writer = new PdxWriterImpl(getPdxType(), os);
}
for (PdxField f : getPdxType().getFields()) {
if (f.isDeleted()) {
continue;
}
Object dv = dirtyFields[f.getFieldIndex()];
if (dv != null) {
if (dv == NULL_TOKEN) {
dv = null;
}
writer.writeField(f, dv);
} else {
writer.writeRawField(f, getRaw(f));
}
}
writer.completeByteStreamGeneration();
ByteBuffer bb = os.toByteBuffer();
bb.position(PdxWriterImpl.HEADER_SIZE);
basicSetBuffer(bb.slice());
dirtyFields = null;
}
return new PdxReaderImpl(this);
}
@Override
public void setField(String fieldName, Object value) {
PdxField f = getPdxType().getPdxField(fieldName);
if (f == null) {
throw new PdxFieldDoesNotExistException(
"A field named " + fieldName + " does not exist on " + getPdxType());
}
if (value != null) {
switch (f.getFieldType()) {
case CHAR:
if (!(value instanceof Character)) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a Character but was a " + value.getClass());
}
break;
case BOOLEAN:
if (!(value instanceof Boolean)) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a Boolean but was a " + value.getClass());
}
break;
case BYTE:
if (!(value instanceof Byte)) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a Byte but was a " + value.getClass());
}
break;
case SHORT:
if (!(value instanceof Short)) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a Short but was a " + value.getClass());
}
break;
case INT:
if (!(value instanceof Integer)) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a Integer but was a " + value.getClass());
}
break;
case LONG:
if (!(value instanceof Long)) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a Long but was a " + value.getClass());
}
break;
case FLOAT:
if (!(value instanceof Float)) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a Float but was a " + value.getClass());
}
break;
case DOUBLE:
if (!(value instanceof Double)) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a Double but was a " + value.getClass());
}
break;
case STRING:
if (!(value instanceof String)) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a String but was a " + value.getClass());
}
break;
case BOOLEAN_ARRAY:
if (!(value instanceof boolean[])) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a boolean[] but was a " + value.getClass());
}
break;
case CHAR_ARRAY:
if (!(value instanceof char[])) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a char[] but was a " + value.getClass());
}
break;
case BYTE_ARRAY:
if (!(value instanceof byte[])) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a byte[] but was a " + value.getClass());
}
break;
case SHORT_ARRAY:
if (!(value instanceof short[])) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a short[] but was a " + value.getClass());
}
break;
case INT_ARRAY:
if (!(value instanceof int[])) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a int[] but was a " + value.getClass());
}
break;
case LONG_ARRAY:
if (!(value instanceof long[])) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a long[] but was a " + value.getClass());
}
break;
case FLOAT_ARRAY:
if (!(value instanceof float[])) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a float[] but was a " + value.getClass());
}
break;
case DOUBLE_ARRAY:
if (!(value instanceof double[])) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a double[] but was a " + value.getClass());
}
break;
case STRING_ARRAY:
if (!(value instanceof String[])) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a String[] but was a " + value.getClass());
}
break;
case ARRAY_OF_BYTE_ARRAYS:
if (!(value instanceof byte[][])) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a byte[][] but was a " + value.getClass());
}
break;
case OBJECT_ARRAY:
if (!(value instanceof Object[])) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a Object[] but was a " + value.getClass());
}
break;
case OBJECT:
// no check needed
break;
// All of the following classes are not final. We only support the exact class in this case;
// not subclasses.
case DATE:
if (!Date.class.equals(value.getClass())) {
throw new PdxFieldTypeMismatchException(
"Values for this field must be a Date but was a " + value.getClass());
}
break;
default:
throw new InternalGemFireException("Unhandled field type " + f.getFieldType());
}
} else {
switch (f.getFieldType()) {
case CHAR:
value = Character.valueOf((char) 0);
break;
case BOOLEAN:
value = Boolean.valueOf(false);
break;
case BYTE:
value = Byte.valueOf((byte) 0);
break;
case SHORT:
value = Short.valueOf((short) 0);
break;
case INT:
value = Integer.valueOf(0);
break;
case FLOAT:
value = Float.valueOf(0.0f);
break;
case DOUBLE:
value = Double.valueOf(0.0);
break;
case LONG:
value = Long.valueOf(0L);
break;
case DATE:
case STRING:
case BOOLEAN_ARRAY:
case CHAR_ARRAY:
case BYTE_ARRAY:
case SHORT_ARRAY:
case INT_ARRAY:
case LONG_ARRAY:
case FLOAT_ARRAY:
case DOUBLE_ARRAY:
case STRING_ARRAY:
case ARRAY_OF_BYTE_ARRAYS:
case OBJECT_ARRAY:
case OBJECT:
// null ok
break;
default:
throw new InternalGemFireException("Unhandled field type " + f.getFieldType());
}
}
dirtyField(f, value);
}
@Override
public boolean equals(Object obj) {
// no need to compare dirtyFields
// Overriding just to make this clear
return super.equals(obj);
}
}