/*******************************************************************************
* Copyright (c) 1998, 2015 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 v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.tools.workbench.mappingsmodel.mapping;
import java.util.List;
import org.eclipse.persistence.tools.workbench.mappingsmodel.MWModel;
import org.eclipse.persistence.tools.workbench.mappingsmodel.ProblemConstants;
import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWClassHandle;
import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWHandle;
import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWHandle.NodeReferenceScrubber;
import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClass;
import org.eclipse.persistence.tools.workbench.utility.node.Node;
import org.eclipse.persistence.oxm.XMLDescriptor;
import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping;
import org.eclipse.persistence.oxm.mappings.XMLDirectMapping;
public final class DefaultingContainerClass extends MWModel {
private volatile boolean usesDefaultContainerClass;
public static final String USES_DEFAULT_CONTAINER_CLASS_PROPERTY = "usesDefaultContainerClass";
private MWClassHandle containerClassHandle;
public static final String CONTAINER_CLASS_PROPERTY = "containerClass";
// ********** constructors **********
/** Default constructor - for TopLink use only. */
private DefaultingContainerClass() {
super();
}
DefaultingContainerClass(MWContainerPolicy parent) {
super(parent);
}
// **************** Building and Initializing *************
protected void initialize(Node parent) {
super.initialize(parent);
this.containerClassHandle = new MWClassHandle(this, this.buildContainerClassScrubber());
this.usesDefaultContainerClass = true;
}
// **************** Containment hierarchy *************
protected void addChildrenTo(List children) {
super.addChildrenTo(children);
children.add(this.containerClassHandle);
}
private NodeReferenceScrubber buildContainerClassScrubber() {
return new NodeReferenceScrubber() {
public void nodeReferenceRemoved(Node node, MWHandle handle) {
DefaultingContainerClass.this.setContainerClass(null);
}
public String toString() {
return "DefaultingContainerClass.buildContainerClassScrubber()";
}
};
}
// **************** Accessors *************
private MWContainerPolicy getContainerPolicy() {
return (MWContainerPolicy) getParent();
}
public boolean usesDefaultContainerClass() {
return this.usesDefaultContainerClass;
}
public void setUseDefaultContainerClass(boolean newUsesDefaultContainerClass) {
if (newUsesDefaultContainerClass == this.usesDefaultContainerClass) {
return;
}
boolean oldUsesDefaultContainerClass = this.usesDefaultContainerClass;
MWClass oldContainerClass = getContainerClass();
setUseDefaultContainerClassInternal(newUsesDefaultContainerClass);
// if we use the default, the container class is always calculated
if (this.usesDefaultContainerClass) {
setContainerClassInternal(null);
}
// if we *used* to use the default, the container class should initially be set
// to the old calculated value
else if (oldUsesDefaultContainerClass) {
setContainerClassInternal(oldContainerClass);
}
}
private void setUseDefaultContainerClassInternal(boolean newUsesDefaultContainerClass) {
boolean oldUsesDefaultContainerClass = this.usesDefaultContainerClass;
this.usesDefaultContainerClass = newUsesDefaultContainerClass;
firePropertyChanged(USES_DEFAULT_CONTAINER_CLASS_PROPERTY, oldUsesDefaultContainerClass, newUsesDefaultContainerClass);
}
/**
* if this mapping uses the default container class, this is always calculated
*/
public MWClass getContainerClass() {
if (this.usesDefaultContainerClass()) {
return getContainerPolicy().defaultContainerClass();
}
return this.containerClassHandle.getType();
}
public void setContainerClass(MWClass newContainerClass) {
setContainerClassInternal(newContainerClass);
// if we are setting the container class using this method (i.e. not directly)
// we assume that we are not using the default container class
if (newContainerClass != null)
setUseDefaultContainerClassInternal(false);
}
private void setContainerClassInternal(MWClass newContainerClass) {
MWClass oldContainerClass = this.getContainerClass();
this.containerClassHandle.setType(newContainerClass);
this.firePropertyChanged(CONTAINER_CLASS_PROPERTY, oldContainerClass, newContainerClass);
}
// ************** Problem Handling ****************
protected void addProblemsTo(List currentProblems) {
super.addProblemsTo(currentProblems);
this.checkContainerClass(currentProblems);
}
private void checkContainerClass(List currentProblems) {
if (this.getContainerClass() == null) {
currentProblems.add(buildProblem(ProblemConstants.MAPPING_CONTAINER_CLASS_NOT_SPECIFIED));
} else {
if ( ! this.getContainerClass().isInstantiable()) {
currentProblems.add(buildProblem(ProblemConstants.MAPPING_CONTAINER_CLASS_NOT_INSTANTIABLE));
}
}
}
// **************** TopLink methods ***************************************
public static XMLDescriptor buildDescriptor() {
XMLDescriptor descriptor = new XMLDescriptor();
descriptor.setJavaClass(DefaultingContainerClass.class);
XMLDirectMapping usesDefaultContainerClassMapping = new XMLDirectMapping();
usesDefaultContainerClassMapping.setAttributeName("usesDefaultContainerClass");
usesDefaultContainerClassMapping.setXPath("uses-default-container-class/text()");
usesDefaultContainerClassMapping.setNullValue(Boolean.FALSE);
descriptor.addMapping(usesDefaultContainerClassMapping);
XMLCompositeObjectMapping containerClassMapping = new XMLCompositeObjectMapping();
containerClassMapping.setAttributeName("containerClassHandle");
containerClassMapping.setSetMethodName("setContainerClassHandleForTopLink");
containerClassMapping.setGetMethodName("getContainerClassHandleForTopLink");
containerClassMapping.setReferenceClass(MWClassHandle.class);
containerClassMapping.setXPath("container-class-handle");
descriptor.addMapping(containerClassMapping);
return descriptor;
}
/**
* check for null
*/
private MWClassHandle getContainerClassHandleForTopLink() {
return (this.containerClassHandle.getType() == null) ? null : this.containerClassHandle;
}
private void setContainerClassHandleForTopLink(MWClassHandle handle) {
NodeReferenceScrubber scrubber = this.buildContainerClassScrubber();
this.containerClassHandle = ((handle == null) ? new MWClassHandle(this, scrubber) : handle.setScrubber(scrubber));
}
}