org.apache.openjpa.abstractstore.AbstractStoreManager Maven / Gradle / Ivy
The newest version!
/*
* 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.abstractstore;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.conf.OpenJPAConfigurationImpl;
import org.apache.openjpa.kernel.FetchConfiguration;
import org.apache.openjpa.kernel.FetchConfigurationImpl;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.PCState;
import org.apache.openjpa.kernel.Seq;
import org.apache.openjpa.kernel.StoreContext;
import org.apache.openjpa.kernel.StoreManager;
import org.apache.openjpa.kernel.StoreQuery;
import org.apache.openjpa.lib.rop.ResultObjectProvider;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.meta.ValueStrategies;
import org.apache.openjpa.util.ApplicationIds;
import org.apache.openjpa.util.Id;
import org.apache.openjpa.util.ImplHelper;
/**
* Abstract store manager implementation to ease development of custom
* OpenJPA back-ends. A concrete subclass must define implementations for the
* following methods:
*
* - {@link StoreManager#exists}
* - {@link #initialize}
* - {@link #load}
* - {@link
* #flush(Collection,Collection,Collection,Collection,Collection)}
* - {@link #executeExtent}
*
Additionally, subclasses should not attempt to acquire resources
* until {@link #open} has been called. Store manager instances might be
* created to call metadata methods such as {@link #newConfiguration} or
* {@link #getUnsupportedOptions} and never opened. These instances should
* not consume any data store resources.
* Notes:
*
* - The {@link StoreManager#initialize} method is responsible
* for creating new instances of objects freshly loaded from the
* database. The method will be invoked with a {@link OpenJPAStateManager}
* that the newly-loaded object should be associated with. To create the
* new object and set up this association correctly, the implementation
* should use the {@link OpenJPAStateManager#initialize} method.
* - If your data store supports some sort of transaction or
* unit of work, you should override the {@link #begin}, {@link #commit},
* and {@link #rollback} methods.
* - This class provides no infrastructure support for optimistic
* transactions. To provide optimistic transaction support:
*
* - Override {@link #beginOptimistic}, {@link #rollbackOptimistic},
* and {@link #syncVersion}.
* - Override {@link #getUnsupportedOptions} to not include {@link
* OpenJPAConfiguration#OPTION_OPTIMISTIC} in the list of unsupported
* options.
* - Ensure that your flush implementation sets the next
* version for each modified object via the {@link
* OpenJPAStateManager#setNextVersion} method.
* - If your version object does not implement {@link Comparable},
* override {@link #compareVersion}, which relies on the
* {@link Comparable#compareTo} method.
*
* - If your data store supports a mechanism for automatically
* generating and managing identity values (or if you want to
* provide that facility on top of your data store), implement
* the {@link #getDataStoreIdSequence} method if you want to use a
*
long
as your datastore identity type and are
* happy with OpenJPA's {@link Id} class. To use another datastore identity
* type, override {@link #getManagedType},
* {@link #getDataStoreIdType}, {@link #copyDataStoreId}, and
* {@link #newDataStoreId} instead. In either case, override
* {@link #getUnsupportedOptions} to not include
* {@link OpenJPAConfiguration#OPTION_ID_DATASTORE} in the list of
* unsupported options.
* - If your data store does not support queries (or if you do
* not want to convert OpenJPA's query parse tree into a
* datastore-specific query), you still have two options in terms
* of query execution:
*
* - In-memory execution: If you
* execute a query against an extent or a class, OpenJPA will
* automatically load the full extent of objects into memory and
* execute the query in memory.
* - openjpa.MethodQL: MethodQL allows
* you to use the query APIs to execute a method that finds
* data in your back-end and returns that data as a
* {@link org.apache.openjpa.lib.rop.ResultList}. For more details on
* MethodQL, see the OpenJPA Reference Guide.
*
*
*
* @since 0.3.1
*/
public abstract class AbstractStoreManager
implements StoreManager {
protected StoreContext ctx;
@Override
public final void setContext(StoreContext ctx) {
this.ctx = ctx;
open();
}
/**
* Returns the {@link StoreContext} that this store manager is
* associated with.
*/
public StoreContext getContext() {
return ctx;
}
/**
* No-op implementation. Ready this store manager for persistent operations.
*/
protected void open() {
}
/**
* No-op implementation. Override this method to provide optimistic
* locking semantics for your data store if you need notification of
* the beginning of an optimistic transaction.
*/
@Override
public void beginOptimistic() {
}
/**
* No-op implementation. Override this method to provide optimistic
* locking semantics for your data store if you need notification of
* a rollback of an optimistic transaction before {@link #begin} is invoked.
*/
@Override
public void rollbackOptimistic() {
}
/**
* OpenJPA assumes that after this method is invoked, all data
* accesses through this store manager will be part of a single
* unit of work that can be rolled back.
* This is a no-op implementation. If your data store does not
* support any concept of locking or transactions, you need not
* override this method.
*/
@Override
public void begin() {
}
/**
* This is a no-op implementation. If your data store does not
* have a concept of transactions or a unit of work, you need not
* override this method. If it does, then override this method to
* notify the data store that the current transaction should be committed.
*/
@Override
public void commit() {
}
/**
* This is a no-op implementation. If your data store does not
* have a concept of transactions or a unit of work, you need not
* override this method. If it does, then override this method to
* notify the data store that the current transaction should be rolled back.
*/
@Override
public void rollback() {
}
/**
* Since this store manager does not provide optimistic locking
* support, this method always returns true
.
*/
@Override
public boolean syncVersion(OpenJPAStateManager sm, Object edata) {
return true;
}
/**
* This method is invoked when OpenJPA needs to load an object whose
* identity is known but which has not yet been loaded from the data
* store. sm
is a partially-set-up state manager for this
* object. The ID and least-derived type information for the instance
* to load can be obtained by invoking
* sm.getObjectId()
and sm.getMetaData()
.
*
* When implementing this method, load the data for this object from
* the data store, determine the most-derived subclass of the newly-loaded
* data, and then use the {@link OpenJPAStateManager#initialize} method to
* populate sm
with a new instance of the appropriate type.
* Once {@link OpenJPAStateManager#initialize} has been invoked, proceed to
* load field data into sm
as in the {@link #load} method, by
* using {@link OpenJPAStateManager#store} (or the appropriate
* OpenJPAStateManager.storetype
method) to put the
* data into the object.
*/
@Override
public abstract boolean initialize(OpenJPAStateManager sm, PCState state,
FetchConfiguration fetch, Object edata);
/**
* This method is invoked when OpenJPA needs to load additional data
* into an object that has already been at least partially loaded by
* a previous {@link #initialize} invocation.
* Load data into sm
by using {@link
* OpenJPAStateManager#store} (or the appropriate
* OpenJPAStateManager.storetype
method) to put the
* data into the object.
*/
@Override
public abstract boolean load(OpenJPAStateManager sm, BitSet fields,
FetchConfiguration fetch, int lockLevel, Object edata);
/**
* This implementation just delegates to the proper singular
* method ({@link StoreManager#initialize} or {@link StoreManager#load})
* depending on each state manager's state. If your data store provides
* bulk loading APIs, overriding this method to be more clever may be
* advantageous.
*/
@Override
public Collection