/* * Copyright 2005 Werner Guttmann * * 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. * * $Id$ */ package org.castor.persist.resolver; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OptionalDataException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.castor.persist.ProposedEntity; import org.castor.persist.TransactionContext; import org.castor.persist.UpdateAndRemovedFlags; import org.castor.persist.UpdateFlags; import org.exolab.castor.jdo.PersistenceException; import org.exolab.castor.mapping.AccessMode; import org.exolab.castor.persist.ClassMolder; import org.exolab.castor.persist.FieldMolder; import org.exolab.castor.persist.OID; import org.exolab.castor.persist.spi.Identity; /** * Implementation of {@link org.castor.persist.resolver.ResolverStrategy} for * serializable fields. * * @author <a href="mailto:werner DOT guttmann AT gmx DOT net">Werner Guttmann</a> * @since 0.9.9 */ public final class SerializableResolver extends BaseRelationResolver { /** The <a href="http://jakarta.apache.org/commons/logging/">Jakarta Commons * Logging </a> instance used for all logging. */ private static final Log LOG = LogFactory.getLog(SerializableResolver.class); private final int _fieldIndex; /** * Creates an instance of SerializableResolver. * @param classMolder Associated {@link ClassMolder} * @param fieldMolder Associated {@link FieldMolder} * @param fieldIndex Field index within all fields of parent class molder. */ public SerializableResolver(final ClassMolder classMolder, final FieldMolder fieldMolder, final int fieldIndex) { super(classMolder, fieldMolder); _fieldIndex = fieldIndex; } /** * @throws PersistenceException * @see org.castor.persist.resolver.ResolverStrategy#create( * org.castor.persist.TransactionContext, java.lang.Object) */ public Object create(final TransactionContext tx, final Object object) throws PersistenceException { Object field = null; try { Object dependent = _fieldMolder.getValue(object, tx.getClassLoader()); if (dependent != null) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream os = new ObjectOutputStream(bos); os.writeObject(dependent); field = bos.toByteArray(); } } catch (IOException e) { throw new PersistenceException( "Error during serializing dependent object", e); } return field; } /** * @see org.castor.persist.resolver.ResolverStrategy#markCreate( * org.castor.persist.TransactionContext, org.exolab.castor.persist.OID, * java.lang.Object) */ public boolean markCreate(final TransactionContext tx, final OID oid, final Object object) { boolean updateCache = false; return updateCache; } /** * @see org.castor.persist.resolver.ResolverStrategy#preStore( * org.castor.persist.TransactionContext, org.exolab.castor.persist.OID, * java.lang.Object, int, java.lang.Object) */ public UpdateFlags preStore(final TransactionContext tx, final OID oid, final Object object, final int timeout, final Object field) throws PersistenceException { UpdateFlags flags = new UpdateFlags(); // deserialize byte[] into java object try { byte[] bytes = (byte[]) field; Object fieldValue = _fieldMolder.getValue(object, tx.getClassLoader()); if (fieldValue != null && bytes != null) { // The following code can be updated, after Blob-->InputStream // to enhance performance. ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream os = new ObjectInputStream(bis); Object dependent = os.readObject(); if (!dependent.equals(fieldValue)) { if (_fieldMolder.isStored() && _fieldMolder.isCheckDirty()) { flags.setUpdatePersist(true); } flags.setUpdateCache(true); } } else if (fieldValue != null || bytes != null) { // indicate store is needed if (_fieldMolder.isStored() /* && fieldMolder.isCheckDirty() */) { flags.setUpdatePersist(true); } flags.setUpdateCache(true); } } catch (OptionalDataException e) { throw new PersistenceException( "Error while deserializing an dependent object", e); } catch (ClassNotFoundException e) { throw new PersistenceException( "Error while deserializing an dependent object", e); } catch (IOException e) { throw new PersistenceException( "Error while deserializing an dependent object", e); } return flags; } /** * @throws PersistenceException * @see org.castor.persist.resolver.ResolverStrategy#store( * org.castor.persist.TransactionContext, java.lang.Object, java.lang.Object) */ public Object store(final TransactionContext tx, final Object object, final Object field) throws PersistenceException { Object newField = null; try { Object dependent = _fieldMolder.getValue(object, tx.getClassLoader()); if (dependent != null) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream os = new ObjectOutputStream(bos); os.writeObject(dependent); newField = bos.toByteArray(); } } catch (IOException e) { throw new PersistenceException( "Error during serializing dependent object", e); } return newField; } /** * @see org.castor.persist.resolver.ResolverStrategy#update( * org.castor.persist.TransactionContext, org.exolab.castor.persist.OID, * java.lang.Object, org.exolab.castor.mapping.AccessMode, java.lang.Object) */ public void update(final TransactionContext tx, final OID oid, final Object object, final AccessMode suggestedAccessMode, final Object field) { // nothing to do } /** * @see org.castor.persist.resolver.ResolverStrategy#updateCache( * org.castor.persist.TransactionContext, org.exolab.castor.persist.OID, * java.lang.Object) */ public Object updateCache(final TransactionContext tx, final OID oid, final Object object) { Object field = null; try { Object o = _fieldMolder.getValue(object, tx.getClassLoader()); if (o != null) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream os = new ObjectOutputStream(bos); os.writeObject(o); field = bos.toByteArray(); } } catch (IOException e) { // TODO [WG]: investigate ???????????????????????????? // It won't happen. ByteArrayOutputStream will not throw IOException String msg = "ByteArrayOutputStream throw IOException: " + e.getMessage(); LOG.error(msg, e); } return field; } /** * @see org.castor.persist.resolver.ResolverStrategy#markDelete( * org.castor.persist.TransactionContext, java.lang.Object, java.lang.Object) */ public void markDelete(final TransactionContext tx, final Object object, final Object field) { // nothing to do } /** * @see org.castor.persist.resolver.ResolverStrategy#revertObject( * org.castor.persist.TransactionContext, org.exolab.castor.persist.OID, * java.lang.Object, java.lang.Object) */ public void revertObject(final TransactionContext tx, final OID oid, final Object object, final Object field) throws PersistenceException { // deserialize byte[] into java object try { byte[] bytes = (byte[]) field; if (bytes != null) { // The following code can be updated, after Blob-->InputStream // to enhance performance. ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream os = new ObjectInputStream(bis); Object o = os.readObject(); _fieldMolder.setValue(object, o, tx.getClassLoader()); } else { _fieldMolder.setValue(object, null, tx.getClassLoader()); } } catch (OptionalDataException e) { throw new PersistenceException( "Error while deserializing an dependent object", e); } catch (ClassNotFoundException e) { throw new PersistenceException( "Error while deserializing an dependent object", e); } catch (IOException e) { throw new PersistenceException( "Error while deserializing an dependent object", e); } } /** * @see org.castor.persist.resolver.ResolverStrategy#expireCache( * org.castor.persist.TransactionContext, java.lang.Object) */ public void expireCache(final TransactionContext tx, final Object field) { // nothing to do } /** * @see org.castor.persist.resolver.ResolverStrategy#load( * org.castor.persist.TransactionContext, org.exolab.castor.persist.OID, * ProposedEntity, org.exolab.castor.mapping.AccessMode) */ public void load(final TransactionContext tx, final OID oid, final ProposedEntity proposedObject, final AccessMode suggestedAccessMode) throws PersistenceException { // deserialize byte[] into java object try { byte[] bytes = (byte[]) proposedObject.getField(_fieldIndex); if (bytes != null) { // The following code can be updated, after Blob-->InputStream // to enhance performance. ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream os = new ObjectInputStream(bis); Object object = os.readObject(); _fieldMolder.setValue(proposedObject.getEntity(), object, tx .getClassLoader()); } else { _fieldMolder.setValue(proposedObject.getEntity(), null, tx .getClassLoader()); } } catch (OptionalDataException e) { throw new PersistenceException( "Error while deserializing an dependent object", e); } catch (ClassNotFoundException e) { throw new PersistenceException( "Error while deserializing an dependent object", e); } catch (IOException e) { throw new PersistenceException( "Error while deserializing an dependent object", e); } } /** * @see org.castor.persist.resolver.ResolverStrategy#postCreate( * org.castor.persist.TransactionContext, org.exolab.castor.persist.OID, * java.lang.Object, java.lang.Object, org.exolab.castor.persist.spi.Identity) */ public Object postCreate(final TransactionContext tx, final OID oid, final Object object, final Object field, final Identity createdId) { return field; } /** * @see org.castor.persist.resolver.ResolverStrategy#removeRelation( * org.castor.persist.TransactionContext, java.lang.Object, * org.exolab.castor.persist.ClassMolder, java.lang.Object) */ public UpdateAndRemovedFlags removeRelation(final TransactionContext tx, final Object object, final ClassMolder relatedMolder, final Object relatedObject) { return new UpdateAndRemovedFlags(); } /** * @inheritDoc */ public boolean updateWhenNoTimestampSet( final TransactionContext tx, final OID oid, final Object object, final AccessMode suggestedAccessMode) throws PersistenceException { // nothing need to be done here for primitive return false; } }