/* * 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.openjpa.kernel; import java.io.IOException; import java.io.ObjectOutput; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedActionException; import java.util.BitSet; import org.apache.openjpa.enhance.PersistenceCapable; import org.apache.openjpa.enhance.StateManager; import org.apache.openjpa.enhance.Reflection; import org.apache.openjpa.lib.util.J2DoPrivHelper; import org.apache.openjpa.meta.AccessCode; import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.FieldMetaData; import org.apache.openjpa.meta.JavaTypes; import org.apache.openjpa.meta.ValueMetaData; import org.apache.openjpa.util.GeneralException; import org.apache.openjpa.util.ImplHelper; /** * State manager used to access state of embedded object id primary key fields. * * @author Abe White */ public class ObjectIdStateManager implements OpenJPAStateManager { private static final Byte ZERO_BYTE = Byte.valueOf((byte)0); private static final Character ZERO_CHAR = Character.valueOf((char)0); private static final Double ZERO_DOUBLE = Double.valueOf(0); private static final Float ZERO_FLOAT = Float.valueOf(0); private static final Short ZERO_SHORT = Short.valueOf((short)0); private Object _oid; private final OpenJPAStateManager _owner; private final ValueMetaData _vmd; /** * Constructor; supply embedded object id and its owner. * * @param owner may be null */ public ObjectIdStateManager(Object oid, OpenJPAStateManager owner, ValueMetaData ownerVal) { _oid = oid; _owner = owner; _vmd = ownerVal; } public Object getGenericContext() { return (_owner == null) ? null : _owner.getGenericContext(); } public Object getPCPrimaryKey(Object oid, int field) { throw new UnsupportedOperationException(); } public StateManager replaceStateManager(StateManager sm) { throw new UnsupportedOperationException(); } public Object getVersion() { return null; } public void setVersion(Object version) { throw new UnsupportedOperationException(); } public boolean isDirty() { return false; } public boolean isTransactional() { return false; } public boolean isPersistent() { return false; } public boolean isNew() { return false; } public boolean isDeleted() { return false; } public boolean isDetached() { return true; } public boolean isVersionUpdateRequired() { return false; } public boolean isVersionCheckRequired() { return false; } public void dirty(String field) { throw new UnsupportedOperationException(); } public Object fetchObjectId() { return null; } public void accessingField(int idx) { throw new UnsupportedOperationException(); } public boolean serializing() { throw new UnsupportedOperationException(); } public boolean writeDetached(ObjectOutput out) throws IOException { throw new UnsupportedOperationException(); } public void proxyDetachedDeserialized(int idx) { throw new UnsupportedOperationException(); } public void settingBooleanField(PersistenceCapable pc, int idx, boolean cur, boolean next, int set) { throw new UnsupportedOperationException(); } public void settingCharField(PersistenceCapable pc, int idx, char cur, char next, int set) { throw new UnsupportedOperationException(); } public void settingByteField(PersistenceCapable pc, int idx, byte cur, byte next, int set) { throw new UnsupportedOperationException(); } public void settingShortField(PersistenceCapable pc, int idx, short cur, short next, int set) { throw new UnsupportedOperationException(); } public void settingIntField(PersistenceCapable pc, int idx, int cur, int next, int set) { throw new UnsupportedOperationException(); } public void settingLongField(PersistenceCapable pc, int idx, long cur, long next, int set) { throw new UnsupportedOperationException(); } public void settingFloatField(PersistenceCapable pc, int idx, float cur, float next, int set) { throw new UnsupportedOperationException(); } public void settingDoubleField(PersistenceCapable pc, int idx, double cur, double next, int set) { throw new UnsupportedOperationException(); } public void settingStringField(PersistenceCapable pc, int idx, String cur, String next, int set) { throw new UnsupportedOperationException(); } public void settingObjectField(PersistenceCapable pc, int idx, Object cur, Object next, int set) { throw new UnsupportedOperationException(); } public void providedBooleanField(PersistenceCapable pc, int idx, boolean cur) { throw new UnsupportedOperationException(); } public void providedCharField(PersistenceCapable pc, int idx, char cur) { throw new UnsupportedOperationException(); } public void providedByteField(PersistenceCapable pc, int idx, byte cur) { throw new UnsupportedOperationException(); } public void providedShortField(PersistenceCapable pc, int idx, short cur) { throw new UnsupportedOperationException(); } public void providedIntField(PersistenceCapable pc, int idx, int cur) { throw new UnsupportedOperationException(); } public void providedLongField(PersistenceCapable pc, int idx, long cur) { throw new UnsupportedOperationException(); } public void providedFloatField(PersistenceCapable pc, int idx, float cur) { throw new UnsupportedOperationException(); } public void providedDoubleField(PersistenceCapable pc, int idx, double cur) { throw new UnsupportedOperationException(); } public void providedStringField(PersistenceCapable pc, int idx, String cur) { throw new UnsupportedOperationException(); } public void providedObjectField(PersistenceCapable pc, int idx, Object cur) { throw new UnsupportedOperationException(); } public boolean replaceBooleanField(PersistenceCapable pc, int idx) { throw new UnsupportedOperationException(); } public char replaceCharField(PersistenceCapable pc, int idx) { throw new UnsupportedOperationException(); } public byte replaceByteField(PersistenceCapable pc, int idx) { throw new UnsupportedOperationException(); } public short replaceShortField(PersistenceCapable pc, int idx) { throw new UnsupportedOperationException(); } public int replaceIntField(PersistenceCapable pc, int idx) { throw new UnsupportedOperationException(); } public long replaceLongField(PersistenceCapable pc, int idx) { throw new UnsupportedOperationException(); } public float replaceFloatField(PersistenceCapable pc, int idx) { throw new UnsupportedOperationException(); } public double replaceDoubleField(PersistenceCapable pc, int idx) { throw new UnsupportedOperationException(); } public String replaceStringField(PersistenceCapable pc, int idx) { throw new UnsupportedOperationException(); } public Object replaceObjectField(PersistenceCapable pc, int idx) { throw new UnsupportedOperationException(); } /////////////////////////////////// // OpenJPAStateManager implementation /////////////////////////////////// public void initialize(Class forType, PCState state) { throw new UnsupportedOperationException(); } public void load(FetchConfiguration fetch) { throw new UnsupportedOperationException(); } public Object getManagedInstance() { return _oid; } public PersistenceCapable getPersistenceCapable() { return ImplHelper.toPersistenceCapable(_oid, _vmd.getRepository().getConfiguration()); } public ClassMetaData getMetaData() { return _vmd.getEmbeddedMetaData(); } public OpenJPAStateManager getOwner() { return _owner; } public int getOwnerIndex() { return _vmd.getFieldMetaData().getIndex(); } public boolean isEmbedded() { return true; } public boolean isFlushed() { return false; } public boolean isFlushedDirty() { return false; } public boolean isProvisional() { return false; } public BitSet getLoaded() { throw new UnsupportedOperationException(); } public BitSet getDirty() { throw new UnsupportedOperationException(); } public BitSet getFlushed() { throw new UnsupportedOperationException(); } public BitSet getUnloaded(FetchConfiguration fetch) { throw new UnsupportedOperationException(); } public Object newProxy(int field) { throw new UnsupportedOperationException(); } public Object newFieldProxy(int field) { throw new UnsupportedOperationException(); } public boolean isDefaultValue(int field) { Object val = getValue(field); if (val == null) return true; FieldMetaData fmd = getMetaData().getField(field); switch (fmd.getDeclaredTypeCode()) { case JavaTypes.BOOLEAN: return Boolean.FALSE.equals(val); case JavaTypes.CHAR: return ((Character) val).charValue() == 0; case JavaTypes.BYTE: case JavaTypes.DOUBLE: case JavaTypes.FLOAT: case JavaTypes.INT: case JavaTypes.LONG: case JavaTypes.SHORT: return ((Number) val).intValue() == 0; case JavaTypes.STRING: return "".equals(val); default: return false; } } public StoreContext getContext() { return (_owner == null) ? null : _owner.getContext(); } public PCState getPCState() { throw new UnsupportedOperationException(); } public Object getObjectId() { return null; } public void setObjectId(Object oid) { throw new UnsupportedOperationException(); } public boolean assignObjectId(boolean flush) { throw new UnsupportedOperationException(); } public Object getId() { return null; } public Object getLock() { return null; } public void setLock(Object lock) { throw new UnsupportedOperationException(); } public void setNextVersion(Object version) { throw new UnsupportedOperationException(); } public Object getImplData() { return null; } public Object setImplData(Object data, boolean cacheable) { throw new UnsupportedOperationException(); } public boolean isImplDataCacheable() { return false; } public Object getImplData(int field) { return null; } public Object setImplData(int field, Object data) { throw new UnsupportedOperationException(); } public boolean isImplDataCacheable(int field) { return false; } public Object getIntermediate(int field) { return null; } public void setIntermediate(int field, Object data) { throw new UnsupportedOperationException(); } public void removed(int field, Object removed, boolean key) { throw new UnsupportedOperationException(); } public boolean beforeRefresh(boolean all) { throw new UnsupportedOperationException(); } public void dirty(int field) { throw new UnsupportedOperationException(); } public void storeBoolean(int field, boolean extVal) { setValue(field, (extVal) ? Boolean.TRUE : Boolean.FALSE, true); } public void storeByte(int field, byte extVal) { setValue(field, Byte.valueOf(extVal), true); } public void storeChar(int field, char extVal) { setValue(field, Character.valueOf(extVal), true); } public void storeInt(int field, int extVal) { setValue(field, extVal, true); } public void storeShort(int field, short extVal) { setValue(field, Short.valueOf(extVal), true); } public void storeLong(int field, long extVal) { setValue(field, extVal, true); } public void storeFloat(int field, float extVal) { setValue(field, Float.valueOf(extVal), true); } public void storeDouble(int field, double extVal) { setValue(field, Double.valueOf(extVal), true); } public void storeString(int field, String extVal) { setValue(field, extVal, extVal != null); } public void storeObject(int field, Object extVal) { setValue(field, extVal, extVal != null); } public void store(int field, Object extVal) { boolean forceInst = true; if (extVal == null) { extVal = getDefaultValue(field); forceInst = false; } setValue(field, extVal, forceInst); } public void storeBooleanField(int field, boolean extVal) { storeBoolean(field, extVal); } public void storeByteField(int field, byte extVal) { storeByte(field, extVal); } public void storeCharField(int field, char extVal) { storeChar(field, extVal); } public void storeIntField(int field, int extVal) { storeInt(field, extVal); } public void storeShortField(int field, short extVal) { storeShort(field, extVal); } public void storeLongField(int field, long extVal) { storeLong(field, extVal); } public void storeFloatField(int field, float extVal) { storeFloat(field, extVal); } public void storeDoubleField(int field, double extVal) { storeDouble(field, extVal); } public void storeStringField(int field, String extVal) { storeString(field, extVal); } public void storeObjectField(int field, Object extVal) { storeObject(field, extVal); } public void storeField(int field, Object value) { store(field, value); } public boolean fetchBoolean(int field) { return ((Boolean) getValue(field)).booleanValue(); } public byte fetchByte(int field) { return ((Number) getValue(field)).byteValue(); } public char fetchChar(int field) { return ((Character) getValue(field)).charValue(); } public short fetchShort(int field) { return ((Number) getValue(field)).shortValue(); } public int fetchInt(int field) { return ((Number) getValue(field)).intValue(); } public long fetchLong(int field) { return ((Number) getValue(field)).longValue(); } public float fetchFloat(int field) { return ((Number) getValue(field)).floatValue(); } public double fetchDouble(int field) { return ((Number) getValue(field)).doubleValue(); } public String fetchString(int field) { return (String) getValue(field); } public Object fetchObject(int field) { return getValue(field); } public Object fetch(int field) { Object ret = getValue(field); if (ret == null) ret = getDefaultValue(field); return ret; } public boolean fetchBooleanField(int field) { return fetchBoolean(field); } public byte fetchByteField(int field) { return fetchByte(field); } public char fetchCharField(int field) { return fetchChar(field); } public short fetchShortField(int field) { return fetchShort(field); } public int fetchIntField(int field) { return fetchInt(field); } public long fetchLongField(int field) { return fetchLong(field); } public float fetchFloatField(int field) { return fetchFloat(field); } public double fetchDoubleField(int field) { return fetchDouble(field); } public String fetchStringField(int field) { return fetchString(field); } public Object fetchObjectField(int field) { return fetch(field); } public Object fetchField(int field, boolean transitions) { return fetch(field); } public Object fetchInitialField(int field) { throw new UnsupportedOperationException(); } public void setRemote(int field, Object value) { store(field, value); } public void lock() { } public void unlock() { } /** * Return the default value of the given field based on its type. */ private Object getDefaultValue(int field) { FieldMetaData fmd = getMetaData().getField(field); switch (fmd.getDeclaredTypeCode()) { case JavaTypes.BOOLEAN: return Boolean.FALSE; case JavaTypes.BYTE: return ZERO_BYTE; case JavaTypes.CHAR: return ZERO_CHAR; case JavaTypes.DOUBLE: return ZERO_DOUBLE; case JavaTypes.FLOAT: return ZERO_FLOAT; case JavaTypes.INT: return 0; case JavaTypes.LONG: return 0L; case JavaTypes.SHORT: return ZERO_SHORT; default: return null; } } /** * Return the value of the given field using reflection. * Relies on the fact that all oid fields/properties are made public * during enhancement. */ private Object getValue(int field) { if (_oid == null) return null; FieldMetaData fmd = getMetaData().getField(field); Object val = null; if (fmd.getBackingMember() instanceof Field) val = Reflection.get(_oid, (Field) fmd.getBackingMember()); else if (fmd.getBackingMember() instanceof Method) val = Reflection.get(_oid, (Method) fmd.getBackingMember()); else if (AccessCode.isField(fmd.getDefiningMetaData().getAccessType())) val = Reflection.get(_oid, Reflection.findField(_oid.getClass(), fmd.getName(), true)); else val = Reflection.get(_oid, Reflection.findGetter(_oid.getClass(), fmd.getName(), true)); if (fmd.getValue().getEmbeddedMetaData() != null) return new ObjectIdStateManager(val, null, fmd); return val; } /** * Set the value of the given field using reflection. * Relies on the fact that all oid fields/properties are made public * during enhancement. */ private void setValue(int field, Object val, boolean forceInst) { if (_oid == null && forceInst) { try { _oid = AccessController.doPrivileged( J2DoPrivHelper.newInstanceAction( getMetaData().getDescribedType())); } catch (Exception e) { if (e instanceof PrivilegedActionException) e = ((PrivilegedActionException) e).getException(); throw new GeneralException(e); } } else if (_oid == null) return; FieldMetaData fmd = getMetaData().getField(field); if (fmd.getBackingMember() instanceof Field) Reflection.set(_oid, (Field) fmd.getBackingMember(), val); else if (AccessCode.isField(fmd.getDefiningMetaData().getAccessType())) Reflection.set(_oid, Reflection.findField(_oid.getClass(), fmd.getName(), true), val); else Reflection.set(_oid, Reflection.findSetter(_oid.getClass(), fmd.getName(), fmd.getDeclaredType(), true), val); } @Override public boolean isDelayed(int field) { return false; } @Override public void setDelayed(int field, boolean delay) { throw new UnsupportedOperationException(); } @Override public void loadDelayedField(int field) { throw new UnsupportedOperationException(); } }