/*******************************************************************************
*
* Copyright (c) 2012 GigaSpaces Technologies Ltd. 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.
*
******************************************************************************/
package org.apache.openjpa.kernel;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import org.apache.openjpa.kernel.BrokerImpl;
import org.apache.openjpa.kernel.StateManagerImpl;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.meta.ValueMetaData;
import org.openspaces.jpa.openjpa.Broker;
/**
* A GigaSpaces extended version of OpenJPA's StateManager
* which has an additional member for storing an entity's owner reference
* for supporting GigaSpaces owned relationships model.
*
* @author Idan Moyal
* @since 8.0.1
*
*/
public class StateManager extends StateManagerImpl {
//
private static final long serialVersionUID = 1L;
/**
* Used for storing the relationship's owner state manager. If the state manager
* is the root of the relationship & therefore has no owner, the value is null.
*/
private StateManager _ownerStateManager;
private FieldMetaData _ownerMetaData;
private boolean _cleared = false;
public StateManager(Object id, ClassMetaData meta, BrokerImpl broker) {
super(id, meta, broker);
}
/**
* Sets the state manager's owner information (state manager & field meta data)
* @param ownerStateManager The owner's state manager.
* @param ownerMetaData The owner's field meta data.
*/
public void setOwnerInformation(StateManager ownerStateManager, FieldMetaData ownerMetaData) {
this._ownerStateManager = ownerStateManager;
this._ownerMetaData = ownerMetaData;
}
/**
* @return The state manager's Owner state manager.
*/
public StateManager getOwnerStateManager() {
return _ownerStateManager;
}
/**
* @return The state manager Owner's field meta data.
*/
public FieldMetaData getOwnerMetaData() {
return _ownerMetaData;
}
/**
* Called after an instance is persisted by a user through the broker.
* Cascades the persist operation to fields marked
* {@link ValueMetaData#CASCADE_IMMEDIATE}.
*/
@Override
void cascadePersist(OpCallbacks call) {
FieldMetaData[] fmds = getMetaData().getFields();
for (int i = 0; i < fmds.length; i++) {
if (!getLoaded().get(i))
continue;
if (fmds[i].getCascadePersist() == ValueMetaData.CASCADE_IMMEDIATE
|| fmds[i].getKey().getCascadePersist() == ValueMetaData.CASCADE_IMMEDIATE
|| fmds[i].getElement().getCascadePersist() == ValueMetaData.CASCADE_IMMEDIATE) {
cascadePersist(i, call, fetchField(i, false));
}
}
}
/**
* Cascade-persists the provided value and setting an owner for the owned
* relationships entities (One-to-one & One-to-many).
* @param field The field to cascade persist.
* @param call Operation call back.
* @param value The field value to cascade persist.
*/
private void cascadePersist(int field, OpCallbacks call, Object value) {
if (value == null)
return;
FieldMetaData fmd = getMetaData().getField(field);
Broker broker = (Broker) getBroker();
switch (fmd.getDeclaredTypeCode()) {
case JavaTypes.PC:
case JavaTypes.PC_UNTYPED:
if (!broker.isDetachedNew() && broker.isDetached(value))
return; // allow but ignore
StateManager stateManager = (StateManager) broker.persist(value, null, true, call);
// Set owner reference for one-to-one relationship only
if (fmd.getAssociationType() == FieldMetaData.ONE_TO_ONE)
stateManager.setOwnerInformation(this, fmd);
break;
case JavaTypes.ARRAY:
broker.persistCollection(Arrays.asList((Object[]) value), true, call, this, fmd);
break;
case JavaTypes.COLLECTION:
broker.persistCollection((Collection<?>) value, true, call, this, fmd);
break;
case JavaTypes.MAP:
if (fmd.getKey().getCascadePersist()
== ValueMetaData.CASCADE_IMMEDIATE)
broker.persistCollection(((Map<?, ?>) value).keySet(), true, call, this, fmd);
if (fmd.getElement().getCascadePersist()
== ValueMetaData.CASCADE_IMMEDIATE)
broker.persistCollection(((Map<?, ?>) value).values(), true, call, this, fmd);
break;
}
}
@Override
void clearFields() {
super.clearFields();
_cleared = true;
}
/**
* Gets whether the fields of this state manager have been cleared.
* @return true if fields were cleared, otherwise false.
*/
public boolean isCleared() {
return _cleared;
}
/**
* Resets the cleared fields states to false.
*/
public void resetClearedState() {
this._cleared = false;
}
}