blob: 2314e837ec6d7b53cea41cb19ac905350d0b074b [file] [log] [blame]
/*
* Copyright 2004-2005 The Apache Software Foundation or its licensors,
* as applicable.
*
* Licensed 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.jackrabbit.core.state.orm.hibernate;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.jcr.PropertyType;
import org.apache.jackrabbit.core.value.BLOBFileValue;
import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.core.NodeId;
import org.apache.jackrabbit.core.PropertyId;
import org.apache.jackrabbit.name.QName;
import org.apache.jackrabbit.core.state.AbstractPersistenceManager;
import org.apache.jackrabbit.core.state.ItemState;
import org.apache.jackrabbit.core.state.ItemStateException;
import org.apache.jackrabbit.core.state.NoSuchItemStateException;
import org.apache.jackrabbit.core.state.NodeReferences;
import org.apache.jackrabbit.core.state.NodeReferencesId;
import org.apache.jackrabbit.core.state.NodeState;
import org.apache.jackrabbit.core.state.PMContext;
import org.apache.jackrabbit.core.state.PropertyState;
import org.apache.jackrabbit.core.state.orm.ORMBlobValue;
import org.apache.jackrabbit.core.state.orm.ORMNodeReference;
import org.apache.jackrabbit.core.state.orm.ORMPropertyState;
import org.apache.log4j.Logger;
import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.ObjectNotFoundException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.cfg.Configuration;
import net.sf.hibernate.type.Type;
import org.apache.jackrabbit.core.state.PersistenceManager;
import org.apache.ojb.broker.PersistenceBroker;
import org.apache.jackrabbit.core.state.ChangeLog;
import org.apache.ojb.broker.PersistenceBrokerFactory;
import org.apache.ojb.broker.PersistenceBrokerException;
/**
* Hibernate implementation of a Jackrabbit persistence manager.
*/
public class HibernatePersistenceManager implements PersistenceManager {
private static Logger log = Logger.getLogger(HibernatePersistenceManager.class);
private SessionFactory sessionFactory;
public HibernatePersistenceManager() {
}
/**
* @see org.apache.jackrabbit.core.state.PersistenceManager#init
*/
public void init(PMContext context) throws Exception {
try {
// Create the SessionFactory
sessionFactory = new Configuration().configure().
buildSessionFactory();
} catch (Throwable ex) {
log.error("Initial SessionFactory creation failed.", ex);
throw new ExceptionInInitializerError(ex);
}
}
/**
* @see org.apache.jackrabbit.core.state.PersistenceManager#close
*/
public void close() throws Exception {
}
/**
* @see org.apache.jackrabbit.core.state.PersistenceManager#load(NodeId)
*/
public NodeState load(NodeId nodeId) throws NoSuchItemStateException,
ItemStateException {
log.debug("Request for " + nodeId.getUUID());
NodeState state = null;
Session session = null;
Transaction tx = null;
try {
session = sessionFactory.openSession();
tx = session.beginTransaction();
List nodeList = session.find(
"from org.apache.jackrabbit.core.state.orm.hibernate.HibernateNodeState as node WHERE " +
"node.uuid = ?",
new Object[] {nodeId.getUUID()},
new Type[] {Hibernate.STRING});
tx.commit();
if (nodeList.size() != 1) {
throw new NoSuchItemStateException("Couldn't find unique node " +
nodeId.getUUID() + ", found " +
nodeList.size() +
" results instead");
}
HibernateNodeState result = (HibernateNodeState) nodeList.get(0);
state = createNew(nodeId);
result.toPersistentNodeState(state);
} catch (HibernateException he) {
try {
if (tx != null)
tx.rollback();
} catch (HibernateException he2) {
log.error("Error while rolling back transaction", he2);
}
throw new ItemStateException("Error loading " + nodeId.getUUID(),
he);
} finally {
if (session != null) {
try {
session.close();
} catch (HibernateException he) {
throw new ItemStateException(
"Error while closing hibernate session", he);
}
}
}
return state;
}
/**
* @see org.apache.jackrabbit.core.state.PersistenceManager#load(PropertyId)
*/
public PropertyState load(PropertyId propId) throws
NoSuchItemStateException, ItemStateException {
PropertyState state = null;
Session session = null;
try {
session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
ORMPropertyState propState = null;
try {
List propertyList = session.find(
"from org.apache.jackrabbit.core.state.orm.ORMPropertyState as prop WHERE " +
"prop.parentUUID = ? and prop.name = ?",
new Object[] {propId.getParentUUID(),
propId.getName().toString()},
new Type[] {Hibernate.STRING, Hibernate.STRING});
tx.commit();
if (propertyList.size() != 1) {
throw new NoSuchItemStateException(
"Couldn't find unique property " + propId + ", found " +
propertyList.size() + " results instead");
}
propState = (ORMPropertyState) propertyList.get(0);
state = createNew(propId);
propState.toPersistentPropertyState(state);
if (propState.getType().intValue() == PropertyType.BINARY) {
// we must now load the binary values.
ArrayList internalValueList = new ArrayList();
List blobValueList = session.find(
"from org.apache.jackrabbit.core.state.orm.ORMBlobValue as bv WHERE " +
"bv.parentUUID = ? and bv.propertyName = ?",
new Object[] {propId.getParentUUID(),
propId.getName().toString()},
new Type[] {Hibernate.STRING, Hibernate.STRING});
Iterator resultIter = blobValueList.iterator();
while (resultIter.hasNext()) {
ORMBlobValue ormBlobValue = (ORMBlobValue) resultIter.
next();
ByteArrayInputStream in = new ByteArrayInputStream(
ormBlobValue.getBlobValue());
try {
internalValueList.add(InternalValue.create(in));
} catch (Throwable t) {
throw new ItemStateException(
"Error while trying to load blob value", t);
}
}
state.setValues( (InternalValue[]) internalValueList.
toArray(new
InternalValue[internalValueList.
size()]));
}
} catch (ObjectNotFoundException onfe) {
throw new NoSuchItemStateException("Couldn't find " + propId,
onfe);
}
} catch (HibernateException he) {
throw new ItemStateException("Error loading " + propId, he);
} finally {
if (session != null) {
try {
session.close();
} catch (HibernateException he) {
throw new ItemStateException(
"Error while closing hibernate session", he);
}
}
}
return state;
}
/**
* @see org.apache.jackrabbit.core.state.PersistenceManager#load(NodeReferencesId)
*/
public NodeReferences load(NodeReferencesId targetId) throws
NoSuchItemStateException, ItemStateException {
log.debug("Loading node references for targetId=" +
targetId.toString());
NodeReferences refs = null;
Session session = null;
Transaction tx = null;
try {
session = sessionFactory.openSession();
tx = session.beginTransaction();
Iterator nodeRefIter = session.iterate("from org.apache.jackrabbit.core.state.orm.ORMNodeReference as nf where nf.targetId='" +
targetId.toString() +
"'");
refs = new NodeReferences(targetId);
while (nodeRefIter.hasNext()) {
ORMNodeReference curNodeReference = (ORMNodeReference)
nodeRefIter.
next();
refs.addReference(new PropertyId(curNodeReference.
getPropertyParentUUID(),
QName.
valueOf(curNodeReference.
getPropertyName())));
}
tx.commit();
} catch (HibernateException he) {
try {
if (tx != null)
tx.rollback();
} catch (HibernateException he2) {
log.error("Error while rolling back transaction", he2);
}
log.error("Error while loading node reference for targetId=" +
targetId.toString(), he);
} finally {
if (session != null) {
try {
session.close();
} catch (HibernateException he) {
throw new ItemStateException(
"Error while closing hibernate session", he);
}
}
}
return refs;
}
/**
* @see org.apache.jackrabbit.core.state.PersistenceManager#exists(NodeId)
*/
public boolean exists(NodeId id) throws ItemStateException {
HibernateNodeState result = null;
Session session = null;
Transaction tx = null;
try {
session = sessionFactory.openSession();
tx = session.beginTransaction();
List nodeList = session.find(
"from org.apache.jackrabbit.core.state.orm.hibernate.HibernateNodeState as node WHERE " +
"node.uuid = ?",
new Object[] {id.toString()},
new Type[] {Hibernate.STRING});
tx.commit();
if (nodeList.size() < 1) {
return false;
} else {
if (nodeList.size() > 1) {
log.warn("Node " + id +
" exists more than once in database !");
}
return true;
}
} catch (HibernateException he) {
try {
if (tx != null)
tx.rollback();
} catch (HibernateException he2) {
log.error("Error while rolling back transaction", he2);
}
throw new ItemStateException("Error loading " + id, he);
} finally {
if (session != null) {
try {
session.close();
} catch (HibernateException he) {
throw new ItemStateException(
"Error while closing hibernate session", he);
}
}
}
}
/**
* @see org.apache.jackrabbit.core.state.PersistenceManager#exists(PropertyId)
*/
public boolean exists(PropertyId id) throws ItemStateException {
boolean result = false;
Session session = null;
Transaction tx = null;
try {
session = sessionFactory.openSession();
tx = session.beginTransaction();
ORMPropertyState propState = null;
PropertyId propId = (PropertyId) id;
List propertyList = session.find(
"from org.apache.jackrabbit.core.state.orm.ORMPropertyState as prop WHERE " +
"prop.parentUUID = ? and prop.name = ?",
new Object[] {propId.getParentUUID(),
propId.getName().toString()},
new Type[] {Hibernate.STRING, Hibernate.STRING});
tx.commit();
if (propertyList.size() < 1) {
return false;
} else {
if (propertyList.size() > 1) {
log.warn("Property " + id +
" exists more than once in database !");
}
return true;
}
} catch (HibernateException he) {
try {
if (tx != null)
tx.rollback();
} catch (HibernateException he2) {
log.error("Error while rolling back transaction", he2);
}
throw new ItemStateException("Error loading " + id, he);
} finally {
if (session != null) {
try {
session.close();
} catch (HibernateException he) {
throw new ItemStateException(
"Error while closing hibernate session", he);
}
}
}
}
/**
* @see org.apache.jackrabbit.core.state.PersistenceManager#exists(NodeReferencesId)
*/
public boolean exists(NodeReferencesId targetId) throws ItemStateException {
boolean result = false;
Session session = null;
Transaction tx = null;
try {
session = sessionFactory.openSession();
tx = session.beginTransaction();
Iterator nodeRefIter = session.iterate("from org.apache.jackrabbit.core.state.orm.ORMNodeReference as nf where nf.targetId='" +
targetId.toString() +
"'");
NodeReferences refs = new NodeReferences(targetId);
if (nodeRefIter.hasNext()) {
result = true;
}
tx.commit();
} catch (HibernateException he) {
try {
if (tx != null)
tx.rollback();
} catch (HibernateException he2) {
log.error("Error while rolling back transaction", he2);
}
throw new ItemStateException(
"Error while testing reference existence for targetId=" +
targetId, he);
} finally {
if (session != null) {
try {
session.close();
} catch (HibernateException he) {
throw new ItemStateException(
"Error while closing hibernate session", he);
}
}
}
return result;
}
/**
* @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#store(NodeState)
*/
public void store(NodeState state, Session session) throws ItemStateException, HibernateException {
log.debug("Request to store " + state.getId());
boolean isUpdate = true;
HibernateNodeState nodeState = new HibernateNodeState(state);
if (state.getStatus() == ItemState.STATUS_NEW) {
session.save(nodeState);
} else {
session.update(nodeState);
}
}
/**
* @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#store(PropertyState)
*/
public void store(PropertyState state, Session session) throws ItemStateException, HibernateException {
log.debug("Request to store " + state.getId());
boolean isUpdate = true;
ORMPropertyState propState = new ORMPropertyState(state);
InternalValue[] values = state.getValues();
if (values != null) {
for (int i = 0; i < values.length; i++) {
// first we delete any existing blob values (this is faster
// than trying to load and update each value seperately)
session.delete("from org.apache.jackrabbit.core.state.orm.ORMBlobValue as bv where bv.parentUUID=? AND bv.propertyName=?",
new Object[] {state.getParentUUID(),
state.getName().toString()},
new Type[] {Hibernate.STRING,
Hibernate.STRING});
InternalValue val = values[i];
if (val != null) {
if (state.getType() == PropertyType.BINARY) {
ORMBlobValue ormBlobValue = null;
ormBlobValue = new ORMBlobValue();
ormBlobValue.setParentUUID(state.getParentUUID());
ormBlobValue.setPropertyName(state.getName().
toString());
ormBlobValue.setIndex(new Integer(i));
BLOBFileValue blobVal = (BLOBFileValue) val.
internalValue();
propState.setValues("");
ByteArrayOutputStream out = new
ByteArrayOutputStream();
try {
blobVal.spool(out);
} catch (Throwable t) {
throw new ItemStateException(t.getMessage(), t);
}
ormBlobValue.setSize(new Long(blobVal.getLength()));
ormBlobValue.setBlobValue(out.toByteArray());
session.save(ormBlobValue);
}
}
}
}
if (state.getStatus() == ItemState.STATUS_NEW) {
session.save(propState);
} else {
session.update(propState);
}
}
/**
* @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#store(NodeReferences)
*/
public void store(NodeReferences refs, Session session) throws ItemStateException, HibernateException {
Iterator nodeRefPropIdIter = refs.getReferences().iterator();
log.debug("Request to store node references for targetId=" +
refs.getTargetId());
// destroy all the references before saving
destroy(refs, session);
int i = 0;
while (nodeRefPropIdIter.hasNext()) {
PropertyId curPropertyId = (PropertyId) nodeRefPropIdIter.next();
ORMNodeReference curNodeReference = new ORMNodeReference(refs.
getTargetId().toString(), curPropertyId.getParentUUID(),
curPropertyId.getName().toString());
session.save(curNodeReference);
i++;
if (i % 20 == 0) {
session.flush();
session.clear();
}
}
}
/**
* @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#destroy(NodeState)
*/
public void destroy(NodeState state, Session session) throws ItemStateException, HibernateException {
log.debug("Deleting node " + state.getUUID());
HibernateNodeState nodeState = null;
try {
List nodeList = session.find(
"from org.apache.jackrabbit.core.state.orm.hibernate.HibernateNodeState as node WHERE " +
"node.uuid = ?",
new Object[] {state.getId().toString()},
new Type[] {Hibernate.STRING});
if (nodeList.size() != 1) {
} else {
nodeState = (HibernateNodeState) nodeList.get(0);
session.delete(nodeState);
}
} catch (ObjectNotFoundException onfe) {
}
}
/**
* @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#destroy(PropertyState)
*/
public void destroy(PropertyState state, Session session) throws ItemStateException, HibernateException {
log.debug("Deleting property " + state.getId());
ORMPropertyState propState = null;
try {
List propertyList = session.find(
"from org.apache.jackrabbit.core.state.orm.ORMPropertyState as prop WHERE " +
"prop.itemId = ?",
new Object[] {state.getId().toString()},
new Type[] {Hibernate.STRING});
if (propertyList.size() != 1) {
} else {
propState = (ORMPropertyState) propertyList.get(0);
session.delete(propState);
if (state.getType() == PropertyType.BINARY) {
session.delete("from org.apache.jackrabbit.core.state.orm.ORMBlobValue as bv where bv.parentUUID=? AND bv.propertyName=?",
new Object[] {state.getParentUUID(),
state.getName().toString()},
new Type[] {Hibernate.STRING,
Hibernate.STRING});
}
}
} catch (ObjectNotFoundException onfe) {
}
}
/**
* @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#destroy(NodeReferences)
*/
public void destroy(NodeReferences refs, Session session) throws ItemStateException, HibernateException {
log.debug("Deleting node refences for targetId=" +
refs.getTargetId().toString());
session.delete("from org.apache.jackrabbit.core.state.orm.ORMNodeReference as nf where nf.targetId='" +
refs.getTargetId().toString() +
"'");
refs.clearAllReferences();
}
/**
* @see PersistenceManager#createNew
*/
public NodeState createNew(NodeId id)
{
return new NodeState(id.getUUID(), null, null, NodeState.STATUS_NEW,
false);
}
/**
* @see PersistenceManager#createNew
*/
public PropertyState createNew(PropertyId id)
{
return new PropertyState(id.getName(), id.getParentUUID(),
PropertyState.STATUS_NEW, false);
}
/**
* @see PersistenceManager#store(ChangeLog)
*
* This method ensures that changes are either written completely to the
* underlying persistence layer, or not at all.
*/
public void store(ChangeLog changeLog) throws ItemStateException
{
Session session = null;
Transaction tx = null;
try
{
session = sessionFactory.openSession();
tx = session.beginTransaction();
Iterator iter = changeLog.deletedStates();
while (iter.hasNext())
{
ItemState state = (ItemState) iter.next();
if (state.isNode())
{
destroy((NodeState) state, session);
} else
{
destroy((PropertyState) state, session);
}
}
iter = changeLog.addedStates();
while (iter.hasNext())
{
ItemState state = (ItemState) iter.next();
if (state.isNode())
{
store((NodeState) state, session);
} else
{
store((PropertyState) state, session);
}
}
iter = changeLog.modifiedStates();
while (iter.hasNext())
{
ItemState state = (ItemState) iter.next();
if (state.isNode())
{
store((NodeState) state, session);
} else
{
store((PropertyState) state, session);
}
}
iter = changeLog.modifiedRefs();
while (iter.hasNext())
{
NodeReferences refs = (NodeReferences) iter.next();
if (refs.hasReferences())
{
store(refs, session);
} else
{
destroy(refs, session);
}
}
tx.commit() ;
} catch (ItemStateException e)
{
if (tx != null) {
try {
tx.rollback();
} catch (HibernateException ex) {
throw new ItemStateException("Error while rolling back", ex);
}
}
throw e;
} catch (HibernateException e)
{
if (tx != null) {
try {
tx.rollback();
} catch (HibernateException ex) {
throw new ItemStateException("Error while rolling back", ex);
}
}
throw new ItemStateException("Unable to store", e);
} finally
{
if (session != null) {
try {
session.close();
} catch (HibernateException ex) {
throw new ItemStateException("Error while closing session", ex);
}
}
}
}
}