blob: 9c7cf6724188b709faedebc05494f0d4154fd5e4 [file] [log] [blame]
/*
* Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.internal.sessions.remote;
import java.util.*;
import org.eclipse.persistence.indirection.*;
import org.eclipse.persistence.mappings.*;
import org.eclipse.persistence.internal.descriptors.*;
import org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder;
/**
* Helper class for RemoteSessionController.
* This descriptor iterator will replace all the normal
* value holders in an object with remote value holders
* that can be serialized to the client.
*/
public class ReplaceValueHoldersIterator extends DescriptorIterator {
RemoteSessionController controller;
/**
* default constructor
*/
private ReplaceValueHoldersIterator() {
super();
}
/**
* public constructor
*/
public ReplaceValueHoldersIterator(RemoteSessionController controller) {
this();
this.initialize(controller);
}
/**
* build and return an object descriptor for the specified object
*/
protected ObjectDescriptor buildObjectDescriptor(Object object) {
return controller.buildObjectDescriptor(object);
}
/**
* build a properly initialized remote value holder
*/
protected RemoteValueHolder buildRemoteValueHolderFor(ValueHolderInterface valueHolder) {
RemoteValueHolder remoteValueHolder = null;
if (valueHolder instanceof RemoteValueHolder) {
remoteValueHolder = (RemoteValueHolder)valueHolder;
} else if ((valueHolder instanceof UnitOfWorkValueHolder) && ((UnitOfWorkValueHolder)valueHolder).getWrappedValueHolder() instanceof RemoteValueHolder) {
return (RemoteValueHolder)((UnitOfWorkValueHolder)valueHolder).getWrappedValueHolder();
} else {
remoteValueHolder = new RemoteValueHolder();
remoteValueHolder.setWrappedServerValueHolder(valueHolder);
remoteValueHolder.setMapping(this.getCurrentMapping());
}
saveRemoteValueHolder(remoteValueHolder);
return remoteValueHolder;
}
/**
* initialize instance
*/
protected void initialize(RemoteSessionController controller) {
this.controller = controller;
}
/**
* Iterate an indirect container.
*/
@Override
protected void internalIterateIndirectContainer(IndirectContainer container) {
ValueHolderInterface containedValueHolder = container.getValueHolder();
if (containedValueHolder instanceof RemoteValueHolder) {
containedValueHolder = ((RemoteValueHolder)containedValueHolder).getWrappedServerValueHolder();
}
synchronized (containedValueHolder) {
// extract VH within sync block to ensure correct one is used.
ValueHolderInterface valueHolder = container.getValueHolder();
RemoteValueHolder remoteValueHolder = buildRemoteValueHolderFor(valueHolder);
container.setValueHolder(remoteValueHolder);
remoteValueHolder.setServerIndirectionObject(container);
}
}
/**
* Synchronously create a remote value holder. The value holder passed in is ignored
* so that we can ensure that the value holder being held by the object is used
* instead of the one that was passed in.
*/
@Override
protected void internalIterateValueHolder(ValueHolderInterface originalValueHolder) {
ValueHolderInterface rootValueHolder = originalValueHolder;
// Ensure we have the base server side value holder. There will only be one of these per server.
if (rootValueHolder instanceof RemoteValueHolder) {
rootValueHolder = ((RemoteValueHolder)rootValueHolder).getWrappedServerValueHolder();
}
synchronized (rootValueHolder) {
ValueHolderInterface valueHolder = (ValueHolderInterface)getCurrentMapping().getAttributeValueFromObject(getVisitedParent());
RemoteValueHolder remoteValueHolder = buildRemoteValueHolderFor(valueHolder);
if (valueHolder != remoteValueHolder) {
if (this.getCurrentMapping().isOneToOneMapping()) {
this.setOneToOneMappingSettingsIn(remoteValueHolder);
}
this.getCurrentMapping().setAttributeValueInObject(this.getVisitedParent(), remoteValueHolder);
}
}
}
/**
* if we get here, it is a domain object
*/
@Override
protected void iterate(Object object) {
((Map)getResult()).put(object, this.buildObjectDescriptor(object));
}
/**
* save the remote value holder for later use
*/
protected void saveRemoteValueHolder(RemoteValueHolder remoteValueHolder) {
controller.saveRemoteValueHolder(remoteValueHolder);
}
/**
* Set one-to-one mapping information.
* This allows us to look for a cache hit
* before going to the database.
*/
protected void setOneToOneMappingSettingsIn(RemoteValueHolder remoteValueHolder) {
ObjectReferenceMapping oneToOneMapping = (ObjectReferenceMapping)this.getCurrentMapping();// cast it
if (oneToOneMapping.getDescriptor().getObjectBuilder().isPrimaryKeyMapping(oneToOneMapping)) {
remoteValueHolder.setRow(oneToOneMapping.extractPrimaryKeyRowForSourceObject(this.getVisitedParent(), this.getSession()));
}
remoteValueHolder.setTargetObjectPrimaryKeys(oneToOneMapping.extractPrimaryKeysForReferenceObject(this.getVisitedParent(), this.getSession()));
}
}