All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.datanucleus.store.odf.ODFPersistenceHandler Maven / Gradle / Ivy

There is a newer version: 6.0.0-release
Show newest version
/**********************************************************************
Copyright (c) 2009 Andy Jefferson and others. All rights reserved.
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.

Contributors:
    ...
**********************************************************************/
package org.datanucleus.store.odf;

import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set;

import org.datanucleus.ExecutionContext;
import org.datanucleus.exceptions.NucleusDataStoreException;
import org.datanucleus.exceptions.NucleusObjectNotFoundException;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.identity.IdentityUtils;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.FieldPersistenceModifier;
import org.datanucleus.metadata.IdentityType;
import org.datanucleus.metadata.VersionMetaData;
import org.datanucleus.state.ObjectProvider;
import org.datanucleus.store.AbstractPersistenceHandler;
import org.datanucleus.store.StoreData;
import org.datanucleus.store.StoreManager;
import org.datanucleus.store.connection.ManagedConnection;
import org.datanucleus.store.fieldmanager.DeleteFieldManager;
import org.datanucleus.store.odf.fieldmanager.FetchFieldManager;
import org.datanucleus.store.odf.fieldmanager.StoreFieldManager;
import org.datanucleus.store.schema.table.MemberColumnMapping;
import org.datanucleus.store.schema.table.SurrogateColumnType;
import org.datanucleus.store.schema.table.Table;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.NucleusLogger;
import org.datanucleus.util.StringUtils;
import org.odftoolkit.odfdom.doc.OdfSpreadsheetDocument;
import org.odftoolkit.odfdom.doc.table.OdfTable;
import org.odftoolkit.odfdom.doc.table.OdfTableCell;
import org.odftoolkit.odfdom.doc.table.OdfTableRow;
import org.odftoolkit.odfdom.dom.attribute.office.OfficeValueTypeAttribute;

/**
 * Persistence Handler for Open Document Format (ODF) datastores.
 * Handles the insert/update/delete/fetch/locate operations by using ODF Toolkit.
 * 

* Field to Cell mapping * A field is mapped to a cell. The field metadata can define a cell number (starting at 0). * Specifying the cell number means that the user takes responsibility for the cell numbers * being consistent. The default cell numbering is alphabetical start in the root class, and working * down the inheritance tree to the actual instance class. */ public class ODFPersistenceHandler extends AbstractPersistenceHandler { /** * Constructor. * @param storeMgr Manager for the datastore */ public ODFPersistenceHandler(StoreManager storeMgr) { super(storeMgr); } /* (non-Javadoc) * @see org.datanucleus.store.StorePersistenceHandler#close() */ public void close() { // Nothing to do since we maintain no resources } /* (non-Javadoc) * @see org.datanucleus.store.StorePersistenceHandler#insertObject(org.datanucleus.state.ObjectProvider) */ public void insertObject(ObjectProvider op) { // Check if read-only so update not permitted assertReadOnlyForUpdateOfObject(op); AbstractClassMetaData cmd = op.getClassMetaData(); ExecutionContext ec = op.getExecutionContext(); ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec); try { long startTime = System.currentTimeMillis(); if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) { NucleusLogger.DATASTORE_PERSIST.debug(Localiser.msg("ODF.Insert.Start", StringUtils.toJVMIDString(op.getObject()), op.getInternalObjectId())); } OdfSpreadsheetDocument spreadsheetDoc = (OdfSpreadsheetDocument)mconn.getConnection(); StoreData sd = storeMgr.getStoreDataForClass(cmd.getFullClassName()); if (sd == null) { ((ODFStoreManager)storeMgr).manageClasses(new String[] {cmd.getFullClassName()}, ec.getClassLoaderResolver(), spreadsheetDoc); sd = storeMgr.getStoreDataForClass(cmd.getFullClassName()); } Table schemaTable = sd.getTable(); // Find the sheet (table) appropriate for storing objects of this class TODO Coordinate this with manageClasses above, maybe not needed here String sheetName = schemaTable.getName(); OdfTable table = spreadsheetDoc.getTableByName(sheetName); if (cmd.getIdentityType() == IdentityType.APPLICATION || cmd.getIdentityType() == IdentityType.DATASTORE) { // Enforce uniqueness of datastore rows try { locateObject(op); throw new NucleusUserException(Localiser.msg("ODF.Insert.ObjectWithIdAlreadyExists", StringUtils.toJVMIDString(op.getObject()), op.getInternalObjectId())); } catch (NucleusObjectNotFoundException onfe) { // Do nothing since object with this id doesn't exist } } // Add a new row to this table for this object OdfTableRow row = table.appendRow(); // Add cells for the fields to this row op.provideFields(cmd.getAllMemberPositions(), new StoreFieldManager(op, row, true, schemaTable)); if (cmd.getIdentityType() == IdentityType.DATASTORE) { int colIndex = schemaTable.getSurrogateColumn(SurrogateColumnType.DATASTORE_ID).getPosition(); OdfTableCell cell = row.getCellByIndex(colIndex); Object idKey = IdentityUtils.getTargetKeyForDatastoreIdentity(op.getInternalObjectId()); if (idKey instanceof String) { cell.setValueType(OfficeValueTypeAttribute.Value.STRING.toString()); cell.setStringValue((String)idKey); } else { long idValue = ((Long)IdentityUtils.getTargetKeyForDatastoreIdentity(op.getInternalObjectId())).longValue(); cell.setValueType(OfficeValueTypeAttribute.Value.FLOAT.toString()); cell.setDoubleValue(new Double(idValue)); } cell.getOdfElement().setStyleName("DN_PK"); } VersionMetaData vermd = cmd.getVersionMetaDataForClass(); if (vermd != null) { Object nextVersion = ec.getLockManager().getNextVersion(vermd, null); if (vermd.getFieldName() != null) { // Version field AbstractMemberMetaData verMmd = cmd.getMetaDataForMember(vermd.getFieldName()); if (verMmd.getType() == Integer.class || verMmd.getType() == int.class) { // Cater for Integer-based versions TODO Generalise this nextVersion = Integer.valueOf(((Long)nextVersion).intValue()); } } op.setTransactionalVersion(nextVersion); if (NucleusLogger.DATASTORE.isDebugEnabled()) { NucleusLogger.DATASTORE.debug(Localiser.msg("ODF.Insert.ObjectPersistedWithVersion", StringUtils.toJVMIDString(op.getObject()), op.getInternalObjectId(), "" + nextVersion)); } OdfTableCell verCell = null; if (vermd.getFieldName() != null) { AbstractMemberMetaData verMmd = cmd.getMetaDataForMember(vermd.getFieldName()); MemberColumnMapping mapping = schemaTable.getMemberColumnMappingForMember(verMmd); verCell = row.getCellByIndex(mapping.getColumn(0).getPosition()); } else { int colIndex = schemaTable.getSurrogateColumn(SurrogateColumnType.VERSION).getPosition(); verCell = row.getCellByIndex(colIndex); } if (nextVersion instanceof Long) { verCell.setValueType(OfficeValueTypeAttribute.Value.FLOAT.toString()); verCell.setDoubleValue(((Long)nextVersion).doubleValue()); } else if (nextVersion instanceof Timestamp) { verCell.setValueType(OfficeValueTypeAttribute.Value.FLOAT.toString()); verCell.setDoubleValue(new Double(((Timestamp)nextVersion).getTime())); } } if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) { NucleusLogger.DATASTORE_PERSIST.debug(Localiser.msg("ODF.ExecutionTime", (System.currentTimeMillis() - startTime))); } if (ec.getStatistics() != null) { ec.getStatistics().incrementNumWrites(); ec.getStatistics().incrementInsertCount(); } if (NucleusLogger.DATASTORE.isDebugEnabled()) { NucleusLogger.DATASTORE.debug(Localiser.msg("ODF.Insert.ObjectPersisted", StringUtils.toJVMIDString(op.getObject()), op.getInternalObjectId())); } // Use SCO wrappers from this point op.replaceAllLoadedSCOFieldsWithWrappers(); } catch (Exception e) { throw new NucleusDataStoreException("Error inserting object", e); } finally { mconn.release(); } } /* (non-Javadoc) * @see org.datanucleus.store.StorePersistenceHandler#updateObject(org.datanucleus.state.ObjectProvider, int[]) */ public void updateObject(ObjectProvider op, int[] fieldNumbers) { // Check if read-only so update not permitted assertReadOnlyForUpdateOfObject(op); AbstractClassMetaData cmd = op.getClassMetaData(); ExecutionContext ec = op.getExecutionContext(); ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec); try { OdfSpreadsheetDocument spreadsheetDoc = (OdfSpreadsheetDocument)mconn.getConnection(); StoreData sd = storeMgr.getStoreDataForClass(cmd.getFullClassName()); if (sd == null) { ((ODFStoreManager)storeMgr).manageClasses(new String[] {cmd.getFullClassName()}, ec.getClassLoaderResolver(), spreadsheetDoc); sd = storeMgr.getStoreDataForClass(cmd.getFullClassName()); } Table schemaTable = sd.getTable(); // TODO Add optimistic checks int[] updatedFieldNums = fieldNumbers; Object nextVersion = null; VersionMetaData vermd = cmd.getVersionMetaDataForClass(); if (vermd != null) { // Version object so calculate version to store with Object currentVersion = op.getTransactionalVersion(); if (currentVersion instanceof Integer) { // Cater for Integer-based versions TODO Generalise this currentVersion = Long.valueOf(((Integer)currentVersion).longValue()); } nextVersion = ec.getLockManager().getNextVersion(vermd, currentVersion); if (vermd.getFieldName() != null) { // Version field AbstractMemberMetaData verMmd = cmd.getMetaDataForMember(vermd.getFieldName()); if (verMmd.getType() == Integer.class || verMmd.getType() == int.class) { // Cater for Integer-based versions TODO Generalise this nextVersion = Integer.valueOf(((Long)nextVersion).intValue()); } op.replaceField(verMmd.getAbsoluteFieldNumber(), nextVersion); boolean updatingVerField = false; for (int i=0;i 0) { fieldStr.append(","); } fieldStr.append(cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumbers[i]).getName()); } NucleusLogger.DATASTORE_PERSIST.debug(Localiser.msg("ODF.Update.Start", StringUtils.toJVMIDString(op.getObject()), op.getInternalObjectId(), fieldStr.toString())); } // Update the row in the worksheet OdfTableRow row = ODFUtils.getTableRowForObjectInSheet(op, spreadsheetDoc, true); if (row == null) { String sheetName = schemaTable.getName(); throw new NucleusDataStoreException(Localiser.msg("ODF.RowNotFoundForSheetForWorkbook", sheetName, StringUtils.toJVMIDString(op.getInternalObjectId()))); } op.provideFields(updatedFieldNums, new StoreFieldManager(op, row, false, schemaTable)); if (vermd != null) { // Versioned object so set version cell in spreadsheet op.setTransactionalVersion(nextVersion); if (NucleusLogger.DATASTORE.isDebugEnabled()) { NucleusLogger.DATASTORE.debug(Localiser.msg("ODF.Insert.ObjectPersistedWithVersion", StringUtils.toJVMIDString(op.getObject()), op.getInternalObjectId(), "" + nextVersion)); } OdfTableCell verCell = null; if (vermd.getFieldName() != null) { AbstractMemberMetaData verMmd = cmd.getMetaDataForMember(vermd.getFieldName()); MemberColumnMapping mapping = schemaTable.getMemberColumnMappingForMember(verMmd); verCell = row.getCellByIndex(mapping.getColumn(0).getPosition()); } else { int verCellIndex = schemaTable.getSurrogateColumn(SurrogateColumnType.VERSION).getPosition(); verCell = row.getCellByIndex(verCellIndex); } if (nextVersion instanceof Long) { verCell.setDoubleValue(new Double((Long)nextVersion)); } else if (nextVersion instanceof Integer) { verCell.setDoubleValue(new Double((Integer)nextVersion)); } else if (nextVersion instanceof Timestamp) { verCell.setDoubleValue(new Double(((Timestamp)nextVersion).getTime())); } } if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) { NucleusLogger.DATASTORE_PERSIST.debug(Localiser.msg("ODF.ExecutionTime", (System.currentTimeMillis() - startTime))); } if (ec.getStatistics() != null) { ec.getStatistics().incrementNumWrites(); ec.getStatistics().incrementUpdateCount(); } } catch (Exception e) { throw new NucleusDataStoreException("Exception updating object", e); } finally { mconn.release(); } } /* (non-Javadoc) * @see org.datanucleus.store.StorePersistenceHandler#deleteObject(org.datanucleus.state.ObjectProvider) */ public void deleteObject(ObjectProvider op) { // Check if read-only so update not permitted assertReadOnlyForUpdateOfObject(op); AbstractClassMetaData cmd = op.getClassMetaData(); ExecutionContext ec = op.getExecutionContext(); ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec); try { OdfSpreadsheetDocument spreadsheetDoc = (OdfSpreadsheetDocument)mconn.getConnection(); StoreData sd = storeMgr.getStoreDataForClass(cmd.getFullClassName()); if (sd == null) { ((ODFStoreManager)storeMgr).manageClasses(new String[] {cmd.getFullClassName()}, ec.getClassLoaderResolver(), spreadsheetDoc); sd = storeMgr.getStoreDataForClass(cmd.getFullClassName()); } Table schemaTable = sd.getTable(); // TODO Add optimistic checks // Delete all reachable PC objects (due to dependent-field) op.loadUnloadedFields(); op.provideFields(cmd.getAllMemberPositions(), new DeleteFieldManager(op)); // Delete this object long startTime = System.currentTimeMillis(); if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) { NucleusLogger.DATASTORE_PERSIST.debug(Localiser.msg("ODF.Delete.Start", StringUtils.toJVMIDString(op.getObject()), op.getInternalObjectId())); } OdfTableRow row = ODFUtils.getTableRowForObjectInSheet(op, spreadsheetDoc, false); if (row == null) { throw new NucleusObjectNotFoundException("object not found", op.getObject()); } // Remove the row node spreadsheetDoc.getTableByName(schemaTable.getName()).removeRowsByIndex(row.getRowIndex(), 1); if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) { NucleusLogger.DATASTORE_PERSIST.debug(Localiser.msg("ODF.ExecutionTime", (System.currentTimeMillis() - startTime))); } if (ec.getStatistics() != null) { ec.getStatistics().incrementNumWrites(); ec.getStatistics().incrementDeleteCount(); } } catch (Exception e) { throw new NucleusDataStoreException("Exception deleting object", e); } finally { mconn.release(); } } /* (non-Javadoc) * @see org.datanucleus.store.StorePersistenceHandler#fetchObject(org.datanucleus.state.ObjectProvider, int[]) */ public void fetchObject(ObjectProvider op, int[] fieldNumbers) { AbstractClassMetaData cmd = op.getClassMetaData(); if (NucleusLogger.PERSISTENCE.isDebugEnabled()) { // Debug information about what we are retrieving StringBuilder str = new StringBuilder("Fetching object \""); str.append(StringUtils.toJVMIDString(op.getObject())).append("\" (id="); str.append(op.getInternalObjectId()).append(")").append(" fields ["); for (int i=0;i 0) { str.append(","); } str.append(cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumbers[i]).getName()); } str.append("]"); NucleusLogger.PERSISTENCE.debug(str.toString()); } // Strip out any non-persistent fields Set nonpersistableFields = null; for (int i = 0; i < fieldNumbers.length; i++) { AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumbers[i]); if (mmd.getPersistenceModifier() != FieldPersistenceModifier.PERSISTENT) { if (nonpersistableFields == null) { nonpersistableFields = new HashSet(); } nonpersistableFields.add(fieldNumbers[i]); } } if (nonpersistableFields != null) { // Just go through motions for non-persistable fields for (Integer fieldNum : nonpersistableFields) { op.replaceField(fieldNum, op.provideField(fieldNum)); } } if (nonpersistableFields == null || nonpersistableFields.size() != fieldNumbers.length) { ExecutionContext ec = op.getExecutionContext(); ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec); boolean notFound = false; try { OdfSpreadsheetDocument spreadsheetDoc = (OdfSpreadsheetDocument)mconn.getConnection(); StoreData sd = storeMgr.getStoreDataForClass(cmd.getFullClassName()); if (sd == null) { ((ODFStoreManager)storeMgr).manageClasses(new String[] {cmd.getFullClassName()}, ec.getClassLoaderResolver(), spreadsheetDoc); sd = storeMgr.getStoreDataForClass(cmd.getFullClassName()); } Table schemaTable = sd.getTable(); long startTime = System.currentTimeMillis(); if (NucleusLogger.DATASTORE_RETRIEVE.isDebugEnabled()) { NucleusLogger.DATASTORE_RETRIEVE.debug(Localiser.msg("ODF.Fetch.Start", StringUtils.toJVMIDString(op.getObject()), op.getInternalObjectId())); } OdfTableRow row = ODFUtils.getTableRowForObjectInSheet(op, spreadsheetDoc, false); if (row == null) { notFound = true; } else { if (nonpersistableFields != null) { // Strip out any nonpersistable fields int[] persistableFieldNums = new int[fieldNumbers.length - nonpersistableFields.size()]; int pos = 0; for (int i = 0; i < fieldNumbers.length; i++) { if (!nonpersistableFields.contains(fieldNumbers[i])) { persistableFieldNums[pos++] = fieldNumbers[i]; } } fieldNumbers = persistableFieldNums; } op.replaceFields(fieldNumbers, new FetchFieldManager(op, row, schemaTable)); if (NucleusLogger.DATASTORE_RETRIEVE.isDebugEnabled()) { NucleusLogger.DATASTORE_RETRIEVE.debug(Localiser.msg("ODF.ExecutionTime", (System.currentTimeMillis() - startTime))); } if (ec.getStatistics() != null) { ec.getStatistics().incrementNumReads(); ec.getStatistics().incrementFetchCount(); } // TODO Version retrieval } } catch (Exception e) { throw new NucleusDataStoreException("Exception fetching object", e); } finally { mconn.release(); } if (notFound) { throw new NucleusObjectNotFoundException("object not found", op.getObject()); } } } /* (non-Javadoc) * @see org.datanucleus.store.StorePersistenceHandler#findObject(org.datanucleus.ExecutionContext, java.lang.Object) */ public Object findObject(ExecutionContext om, Object id) { return null; } /* (non-Javadoc) * @see org.datanucleus.store.StorePersistenceHandler#locateObject(org.datanucleus.state.ObjectProvider) */ public void locateObject(ObjectProvider op) { ExecutionContext ec = op.getExecutionContext(); ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec); try { OdfSpreadsheetDocument spreadsheetDoc = (OdfSpreadsheetDocument)mconn.getConnection(); final AbstractClassMetaData cmd = op.getClassMetaData(); StoreData sd = storeMgr.getStoreDataForClass(cmd.getFullClassName()); if (sd == null) { ((ODFStoreManager)storeMgr).manageClasses(new String[] {cmd.getFullClassName()}, ec.getClassLoaderResolver(), spreadsheetDoc); } OdfTableRow row = ODFUtils.getTableRowForObjectInSheet(op, spreadsheetDoc, false); if (ec.getStatistics() != null) { ec.getStatistics().incrementNumReads(); } if (row != null) { return; } } catch (Exception e) { NucleusLogger.PERSISTENCE.error("Exception thrown when querying object", e); throw new NucleusDataStoreException("Error when trying to find object with id=" + op.getInternalObjectId(), e); } finally { mconn.release(); } throw new NucleusObjectNotFoundException("Object not found", op.getInternalObjectId()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy