/*
* Copyright 2009-2016 Tilmann Zaeschke. All rights reserved.
*
* This file is part of ZooDB.
*
* ZooDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZooDB 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZooDB. If not, see <http://www.gnu.org/licenses/>.
*
* See the README and COPYING files for further information.
*/
package org.zoodb.internal;
import java.util.Date;
import org.zoodb.api.impl.ZooPC;
import org.zoodb.internal.util.DBLogger;
import org.zoodb.internal.util.Util;
import org.zoodb.schema.ZooClass;
import org.zoodb.schema.ZooField;
import org.zoodb.schema.ZooHandle;
/**
* Handle for direct access to object instances in the database.
*
* @author Tilmann Zaschke
*/
public class ZooHandleImpl implements ZooHandle {
private final long oid;
private final Node node;
private final Session session;
private final ZooClassProxy versionProxy;
private GenericObject gObj;
private ZooPC pcObj;
private boolean isInvalid = false;
public ZooHandleImpl(GenericObject go, ZooClassProxy versionProxy) {
this(go.getOid(), versionProxy, null, go);
}
private ZooHandleImpl(long oid, ZooClassProxy versionProxy, ZooPC pc, GenericObject go) {
this.oid = oid;
this.node = versionProxy.getSchemaDef().jdoZooGetNode();
this.session = node.getSession();
this.versionProxy = versionProxy;
this.pcObj = pc;
this.gObj = go;
}
@Override
public long getOid() {
return oid;
}
@Override
public void setOid(long oid) {
throw new UnsupportedOperationException();
}
public Session getSession() {
return session;
}
@Override
public byte getAttrByte(String attrName) {
return (Byte) findField(attrName).getValue(this);
}
@Override
public boolean getAttrBool(String attrName) {
return (Boolean) findField(attrName).getValue(this);
}
@Override
public short getAttrShort(String attrName) {
return (Short) findField(attrName).getValue(this);
}
@Override
public int getAttrInt(String attrName) {
return (Integer) findField(attrName).getValue(this);
}
@Override
public long getAttrLong(String attrName) {
return (Long) findField(attrName).getValue(this);
}
@Override
public char getAttrChar(String attrName) {
return (Character) findField(attrName).getValue(this);
}
@Override
public float getAttrFloat(String attrName) {
return (Float) findField(attrName).getValue(this);
}
@Override
public double getAttrDouble(String attrName) {
return (Double) findField(attrName).getValue(this);
}
@Override
public String getAttrString(String attrName) {
return (String) findField(attrName).getValue(this);
}
@Override
public Date getAttrDate(String attrName) {
return (Date) findField(attrName).getValue(this);
}
@Override
public ZooHandle getAttrRefHandle(String attrName) {
return (ZooHandle) findField(attrName).getValue(this);
}
@Override
public long getAttrRefOid(String attrName) {
ZooFieldProxy prx = (ZooFieldProxy) findField(attrName);
ZooFieldDef def = prx.getFieldDef();
if (!def.isPersistentType()) {
throw new IllegalStateException("This attribute is not a persistent type: " + attrName);
}
gObj.activateRead();
Object oid = gObj.getFieldRaw(def.getFieldPos());
if (oid == null) {
return 0;
}
return (Long)oid;
}
public GenericObject getGenericObject() {
if (gObj == null) {
gObj = session.internalGetCache().getGeneric(oid);
if (gObj == null) {
//This can also for example if the object already exists in the database.
gObj = node.readGenericObject(versionProxy.getSchemaDef(), oid);
}
}
gObj.ensureLatestVersion();
return gObj;
}
@Override
public void remove() {
checkWrite();
if (gObj != null) {
getGenericObject().jdoZooMarkDeleted();
}
if (pcObj != null) {
session.deletePersistent(pcObj);
}
}
private void checkRead() {
check(false);
}
private void checkWrite() {
check(true);
}
private void check(boolean write) {
if (isInvalid) {
throw new IllegalStateException("This object has been invalidated/deleted.");
}
versionProxy.checkInvalid(write);
if (session.isClosed()) {
throw new IllegalStateException("Session is closed.");
}
if (gObj != null && gObj.jdoZooIsDeleted()) {
throw new IllegalStateException("Object is deleted.");
}
}
@Override
public ZooClass getType() {
checkRead();
return versionProxy;
}
@Override
public Object getJavaObject() {
checkRead();
if (pcObj == null) {
if (gObj != null && (gObj.jdoZooIsNew() || gObj.jdoZooIsDirty())) {
//TODO the problem here is the initialisation of the PC, which would require
//a way to serialize GOs into memory and deserialize them into an PC.
throw new UnsupportedOperationException("Cannot convert new or dirty handles " +
"into Java objects. Please commit() first or create Java object directly.");
}
pcObj = (ZooPC) session.getObjectById(oid);
}
return pcObj;
}
@Override
public Object getValue(String attrName) {
checkRead();
return versionProxy.getField(attrName).getValue(this);
}
@Override
public void setValue(String attrName, Object val) {
findField(attrName).setValue(this, val);
}
private ZooField findField(String attrName) {
checkRead();
ZooField f = versionProxy.getField(attrName);
if (f == null) {
throw DBLogger.newUser("Field not found: " + attrName);
}
return f;
}
ZooPC internalGetPCI() {
return pcObj;
}
@Override
public String toString() {
return Util.oidToString(oid);
}
public void invalidate() {
isInvalid = true;
}
}