/*******************************************************************************
* 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.descriptor.relational;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import org.eclipse.persistence.tools.workbench.mappingsmodel.MWModel;
import org.eclipse.persistence.tools.workbench.mappingsmodel.ProblemConstants;
import org.eclipse.persistence.tools.workbench.mappingsmodel.db.MWColumn;
import org.eclipse.persistence.tools.workbench.mappingsmodel.db.MWColumnPair;
import org.eclipse.persistence.tools.workbench.mappingsmodel.db.MWReference;
import org.eclipse.persistence.tools.workbench.mappingsmodel.db.MWTable;
import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWAbstractDescriptorPolicy;
import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWDescriptorPolicy;
import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWMappingDescriptor;
import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWReferenceHandle;
import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWHandle.NodeReferenceScrubber;
import org.eclipse.persistence.tools.workbench.utility.iterators.CloneIterator;
import org.eclipse.persistence.tools.workbench.utility.iterators.TransformationIterator;
import org.eclipse.persistence.tools.workbench.utility.node.Node;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.DescriptorEvent;
import org.eclipse.persistence.descriptors.RelationalDescriptor;
import org.eclipse.persistence.mappings.TransformationMapping;
import org.eclipse.persistence.oxm.XMLDescriptor;
import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping;
import org.eclipse.persistence.sessions.Record;
public final class MWDescriptorMultiTableInfoPolicy extends MWAbstractDescriptorPolicy
{
private Collection secondaryTableHolders;
public static final String SECONDARY_TABLE_HOLDERS_COLLECTION = "secondaryTableHolders";
/** Default constructor - for TopLink use only */
private MWDescriptorMultiTableInfoPolicy() {
super();
}
public MWDescriptorMultiTableInfoPolicy(MWMappingDescriptor descriptor) {
super(descriptor);
}
// **************** Initialization ***************
/**
* initialize persistent state
*/
protected void initialize(Node parent) {
super.initialize(parent);
this.secondaryTableHolders = new Vector();
}
protected void addChildrenTo(List children) {
super.addChildrenTo(children);
synchronized (this.secondaryTableHolders) { children.addAll(this.secondaryTableHolders); }
}
// **************** Accessors ***************
public MWSecondaryTableHolder addSecondaryTable(MWTable secondaryTable) {
MWSecondaryTableHolder associationHolder = new MWSecondaryTableHolder(this, secondaryTable);
addItemToCollection(associationHolder, this.secondaryTableHolders, SECONDARY_TABLE_HOLDERS_COLLECTION);
return associationHolder;
}
public void removeSecondaryTable(MWTable table) {
for (Iterator stream = secondaryTableHolders(); stream.hasNext();) {
MWSecondaryTableHolder tableAssociationHolder = (MWSecondaryTableHolder) stream.next();
if (tableAssociationHolder.getTable() == table) {
removeSecondaryTableHolder(tableAssociationHolder);
return;
}
}
}
void removeSecondaryTableHolder(MWSecondaryTableHolder holder) {
removeItemFromCollection(holder, this.secondaryTableHolders, SECONDARY_TABLE_HOLDERS_COLLECTION);
}
public MWSecondaryTableHolder secondaryTableHolderFor(MWTable table) {
for (Iterator stream = secondaryTableHolders(); stream.hasNext();) {
MWSecondaryTableHolder tableHolder = (MWSecondaryTableHolder) stream.next();
if (tableHolder.getTable() == table) {
return tableHolder;
}
}
return null;
}
public Iterator secondaryTableHolders() {
return new CloneIterator(this.secondaryTableHolders);
}
private MWReference secondaryReferenceFor(MWTable table) {
for (Iterator stream = secondaryReferences(); stream.hasNext(); ) {
MWReference reference = (MWReference) stream.next();
if (reference.getSourceTable() == table || reference.getTargetTable() == table) {
return reference;
}
}
return null;
}
private Iterator secondaryReferences() {
Collection references = new ArrayList();
for (Iterator stream = secondaryTableHolders(); stream.hasNext(); ) {
MWSecondaryTableHolder holder = (MWSecondaryTableHolder) stream.next();
if (!holder.primaryKeysHaveSameName()) {
if (holder.getReference() != null) {
references.add(holder.getReference());
}
}
}
return references.iterator();
}
public int secondaryTableHoldersSize() {
return this.secondaryTableHolders.size();
}
public Iterator secondaryTables() {
return new TransformationIterator(secondaryTableHolders()) {
protected Object transform(Object next) {
return ((MWSecondaryTableHolder) next).getTable();
}
};
}
// ************** containment hierarchy *************
private MWTableDescriptor getTableDescriptor() {
return (MWTableDescriptor) getOwningDescriptor();
}
// ************* MWAbstractDescriptorPolicy overrides ***************
public boolean isActive() {
return true;
}
public MWDescriptorPolicy getPersistedPolicy() {
return this;
}
// ************* Problems overrides ***************
protected void addProblemsTo(List problems) {
super.addProblemsTo(problems);
checkPrimaryKeysAcrossMultipleTables(problems);
}
private void checkPrimaryKeysAcrossMultipleTables(List newProblems) {
if(!pksAcrossMultipleTablesTest(false)) {
newProblems.add(buildProblem(ProblemConstants.DESCRIPTOR_MULTI_TABLE_PKS_DONT_MATCH));
}
}
public boolean pksAcrossMultipleTablesTest(boolean moreThanOneTableMustBeDefined) {
int associatedTablesSize = getTableDescriptor().associatedTablesSize();
if (associatedTablesSize < 2) {
return !moreThanOneTableMustBeDefined;
}
MWTable primaryTable = getTableDescriptor().getPrimaryTable();
if (primaryTable == null) {
return false;
}
for (Iterator tables = getTableDescriptor().associatedTables(); tables.hasNext(); ) {
MWTable secondaryTable = (MWTable) tables.next();
// Are they related by FK's?
MWSecondaryTableHolder tableAssociationHolder = secondaryTableHolderFor(secondaryTable);
if (tableAssociationHolder == null) {
continue;
}
if (tableAssociationHolder.primaryKeysHaveSameName()) {
// Do the PK's match?
for (Iterator columns = primaryTable.primaryKeyColumns(); columns.hasNext(); ) {
MWColumn pk = (MWColumn) columns.next();
MWColumn matchingPk = secondaryTable.columnNamed(pk.getName());
if (matchingPk == null || ! matchingPk.isPrimaryKey()) {
return false;
}
}
}
}
return true;
}
// ************** runtime conversion *************
public void adjustRuntimeDescriptor(ClassDescriptor runtimeDescriptor) {
runtimeDescriptor.getAdditionalTablePrimaryKeyFields(); // lazy initialization
Iterator secondaryTables = getTableDescriptor().secondaryTables();
// add all secondary tables
while (secondaryTables.hasNext())
{
MWTable secondaryTable = (MWTable) secondaryTables.next();
((RelationalDescriptor) runtimeDescriptor).addTableName(secondaryTable.getName());
}
// add all associations
for (Iterator tableAssocs = secondaryReferences(); tableAssocs.hasNext(); ) {
MWReference ref = (MWReference) tableAssocs.next();
for (Iterator stream = ref.columnPairs(); stream.hasNext(); ) {
MWColumnPair columnPair = (MWColumnPair) stream.next();
if (columnPair.getSourceColumn() != null && columnPair.getTargetColumn() != null)
{
String sourceColumnName = columnPair.getSourceColumn().qualifiedName();
String targetColumnName = columnPair.getTargetColumn().qualifiedName();
runtimeDescriptor.addForeignKeyFieldNameForMultipleTable(sourceColumnName, targetColumnName);
}
}
}
}
// ********** TopLink methods **********
public static XMLDescriptor buildDescriptor() {
XMLDescriptor descriptor = new XMLDescriptor();
descriptor.setJavaClass(MWDescriptorMultiTableInfoPolicy.class);
XMLCompositeCollectionMapping secondaryTableAssociationHoldersMapping = new XMLCompositeCollectionMapping();
secondaryTableAssociationHoldersMapping.setAttributeName("secondaryTableHolders");
secondaryTableAssociationHoldersMapping.setReferenceClass(MWSecondaryTableHolder.class);
secondaryTableAssociationHoldersMapping.setXPath("secondary-table-holders/table-holder");
descriptor.addMapping(secondaryTableAssociationHoldersMapping);
return descriptor;
}
}