/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.server; import com.foundationdb.server.types.TInstance; import com.foundationdb.server.types.value.UnderlyingType; import com.foundationdb.server.types.value.Value; import com.foundationdb.server.types.value.ValueSource; import java.util.HashMap; import java.util.Map; public final class PersistitValueValueSource implements ValueSource { // PersistitValueValueSource interface public void attach(com.persistit.Value value) { this.persistitValue = value; clear(); value.setStreamMode(true); } public void getReady(TInstance expectedTInstance) { if (persistitValue.isNull(true)) { cacheObject = NULL; } else { Class<?> valueClass = persistitValue.getType(); UnderlyingType rawUnderlying = classesToUnderlying.get(valueClass); if (rawUnderlying == TInstance.underlyingType(expectedTInstance)) { value.underlying(expectedTInstance); cacheObject = null; } else cacheObject = READY_FOR_CACHE; } } // ValueSource interface @Override public boolean hasAnyValue() { return (persistitValue != null); } @Override public boolean hasRawValue() { return hasAnyValue() && (cacheObject == null); } @Override public boolean hasCacheValue() { return (cacheObject != null) && (cacheObject != NULL); } @Override public boolean canGetRawValue() { return hasRawValue(); } private boolean needsDecoding(UnderlyingType toUnderlying) { assert toUnderlying == TInstance.underlyingType(value.getType()) : "expected underlying " + toUnderlying + " but was set up for " + value.getType(); return ! value.hasRawValue(); } @Override public Object getObject() { if (cacheObject == null) throw new IllegalStateException("no cache object: " + value); if (cacheObject == READY_FOR_CACHE) cacheObject = persistitValue.get(); return (cacheObject == NULL) ? null : cacheObject; } @Override public TInstance getType() { assert hasRawValue() : "underlying type is only available when there is a raw value"; return value.getType(); } @Override public boolean isNull() { return cacheObject == NULL; } @Override public boolean getBoolean() { if (needsDecoding(UnderlyingType.BOOL)) value.putBool(persistitValue.getBoolean()); return value.getBoolean(); } @Override public boolean getBoolean(boolean defaultValue) { return isNull() ? defaultValue : getBoolean(); } @Override public byte getInt8() { if (needsDecoding(UnderlyingType.INT_8)) value.putInt8(persistitValue.getByte()); return value.getInt8(); } @Override public short getInt16() { if (needsDecoding(UnderlyingType.INT_16)) value.putInt16(persistitValue.getShort()); return value.getInt16(); } @Override public char getUInt16() { if (needsDecoding(UnderlyingType.UINT_16)) value.putUInt16(persistitValue.getChar()); return value.getUInt16(); } @Override public int getInt32() { if (needsDecoding(UnderlyingType.INT_32)) value.putInt32(persistitValue.getInt()); return value.getInt32(); } @Override public long getInt64() { if (needsDecoding(UnderlyingType.INT_64)) value.putInt64(persistitValue.getLong()); return value.getInt64(); } @Override public float getFloat() { if (needsDecoding(UnderlyingType.FLOAT)) value.putFloat(persistitValue.getFloat()); return value.getFloat(); } @Override public double getDouble() { if (needsDecoding(UnderlyingType.DOUBLE)) value.putDouble(persistitValue.getDouble()); return value.getDouble(); } @Override public byte[] getBytes() { if (needsDecoding(UnderlyingType.BYTES)) value.putBytes(persistitValue.getByteArray()); return value.getBytes(); } @Override public String getString() { if (needsDecoding(UnderlyingType.STRING)) value.putString(persistitValue.getString(), null); return value.getString(); } // private private void clear() { value.underlying(null); } // object state public PersistitValueValueSource() { clear(); } private com.persistit.Value persistitValue; private Value value = new Value(); private Object cacheObject = null; private static final Object READY_FOR_CACHE = new Object(); private static final Object NULL = new Object(); private static final Map<Class<?>,UnderlyingType> classesToUnderlying = createTranslationMap(); private static Map<Class<?>, UnderlyingType> createTranslationMap() { Map<Class<?>,UnderlyingType> map = new HashMap<>(UnderlyingType.values().length); map.put(boolean.class, UnderlyingType.BOOL); map.put(byte.class, UnderlyingType.INT_8); map.put(short.class, UnderlyingType.INT_16); map.put(char.class, UnderlyingType.UINT_16); map.put(int.class, UnderlyingType.INT_32); map.put(long.class, UnderlyingType.INT_64); map.put(float.class, UnderlyingType.FLOAT); map.put(double.class, UnderlyingType.DOUBLE); map.put(byte[].class, UnderlyingType.BYTES); map.put(String.class, UnderlyingType.STRING); return map; } }