/******************************************************************************* * 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.Collections; import java.util.Iterator; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; import java.util.Vector; import org.eclipse.persistence.tools.workbench.mappingsmodel.MWModel; import org.eclipse.persistence.tools.workbench.mappingsmodel.MWQueryKey; import org.eclipse.persistence.tools.workbench.mappingsmodel.ProblemConstants; import org.eclipse.persistence.tools.workbench.mappingsmodel.db.MWTable; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.InterfaceDescriptorCreationException; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWInheritancePolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.MWNullInheritancePolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWDescriptorHandle; 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.mappingsmodel.meta.MWClassRefreshPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.project.MWProject; import org.eclipse.persistence.tools.workbench.mappingsmodel.project.MWProjectDefaultsPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ExternalClassNotFoundException; import org.eclipse.persistence.tools.workbench.utility.CollectionTools; import org.eclipse.persistence.tools.workbench.utility.HashBag; import org.eclipse.persistence.tools.workbench.utility.filters.Filter; import org.eclipse.persistence.tools.workbench.utility.iterators.CloneIterator; import org.eclipse.persistence.tools.workbench.utility.iterators.NullIterator; 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.RelationalDescriptor; import org.eclipse.persistence.oxm.XMLDescriptor; import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping; import org.eclipse.persistence.mappings.querykeys.QueryKey; public final class MWInterfaceDescriptor extends MWDescriptor implements MWRelationalDescriptor { // these must all be relational descriptors private Collection implementorHandles; public static final String IMPLEMENTORS_COLLECTION = "implementors"; private NodeReferenceScrubber implementorScrubber; private MWInheritancePolicy nullInheritancePolicy = new MWNullInheritancePolicy(this); // ********** Constructors ********** /** * Default constructor - for TopLink use only. */ private MWInterfaceDescriptor() { super(); } public MWInterfaceDescriptor(MWProject parent, MWClass type, String name) { super(parent, type, name); } // ********** initialization ********** protected void initialize(Node parent) { super.initialize(parent); this.implementorHandles = new Vector(); } // ********** accessors ********** // ***** implementors private Iterator implementorHandles() { return new CloneIterator(this.implementorHandles) { protected void remove(Object current) { MWInterfaceDescriptor.this.removeImplementorHandle((MWDescriptorHandle) current); } }; } void removeImplementorHandle(MWDescriptorHandle handle) { this.implementorHandles.remove(handle); this.fireItemRemoved(IMPLEMENTORS_COLLECTION, handle.getDescriptor()); this.getProject().implementorsChangedFor(this); } public Iterator implementors() { return new TransformationIterator(this.implementorHandles()) { protected Object transform(Object next) { return ((MWDescriptorHandle) next).getDescriptor(); } }; } public int implementorsSize() { return this.implementorHandles.size(); } public void addImplementor(MWDescriptor descriptor) { if (CollectionTools.contains(this.implementors(), descriptor)) { throw new IllegalArgumentException(descriptor.toString()); } this.implementorHandles.add(new MWDescriptorHandle(this, descriptor, this.implementorScrubber())); this.fireItemAdded(IMPLEMENTORS_COLLECTION, descriptor); this.getProject().implementorsChangedFor(this); } public void removeImplementor(MWDescriptor descriptor) { for (Iterator stream = this.implementors(); stream.hasNext(); ) { if (stream.next() == descriptor) { stream.remove(); return; } } throw new IllegalArgumentException(descriptor.toString()); } public void removeImplementors(Collection descriptors) { this.removeImplementors(descriptors.iterator()); } public void removeImplementors(Iterator descriptors) { while (descriptors.hasNext()) { this.removeImplementor((MWDescriptor) descriptors.next()); } } public void clearImplementors() { for (Iterator stream = this.implementorHandles(); stream.hasNext(); ) { stream.next(); stream.remove(); } } // ********** queries ********** public SortedSet getAllQueryKeys() { HashBag queryKeyNameBag = new HashBag(); SortedSet commonQueryKeys = new TreeSet(); MWTableDescriptor descriptor = null; Iterator implementors = implementors(); while (implementors.hasNext()) { descriptor = (MWTableDescriptor) implementors.next(); Iterator allQueryKeys = descriptor.getAllQueryKeysIncludingInherited().iterator(); Collection duplicates = new ArrayList(); while (allQueryKeys.hasNext()) { String queryKeyName =((MWQueryKey) allQueryKeys.next()).getName(); //only add non-duplicate query keys if (!duplicates.contains(queryKeyName)) { duplicates.add(queryKeyName); queryKeyNameBag.add(queryKeyName); } } } Iterator queryKeyNames = queryKeyNameBag.iterator(); while (queryKeyNames.hasNext()) { String queryKeyName = (String) queryKeyNames.next(); if (queryKeyNameBag.count(queryKeyName) == implementorsSize()) { commonQueryKeys.add(descriptor.queryKeyNamedIncludingInherited(queryKeyName)); } } return commonQueryKeys; } public Iterator allQueryKeyNames(Iterator iterator) { return new TransformationIterator(iterator) { protected Object transform(Object next) { return ((MWQueryKey) next).getName(); } }; } public boolean hasImplementor(MWDescriptor descriptor) { return CollectionTools.contains(this.implementors(), descriptor); } public Iterator allAssociatedFields() { return NullIterator.instance(); } // ********** containment hierarchy ********** protected void addChildrenTo(List children) { super.addChildrenTo(children); synchronized (this.implementorHandles) { children.addAll(this.implementorHandles); } } private NodeReferenceScrubber implementorScrubber() { if (this.implementorScrubber == null) { this.implementorScrubber = this.buildImplementorScrubber(); } return this.implementorScrubber; } private NodeReferenceScrubber buildImplementorScrubber() { return new NodeReferenceScrubber() { public void nodeReferenceRemoved(Node node, MWHandle handle) { MWInterfaceDescriptor.this.removeImplementorHandle((MWDescriptorHandle) handle); } public String toString() { return "MWInterfaceDescriptor.buildImplementorScrubber()"; } }; } //TODO If a descriptor is made aggregate, do we actually want to remove it, //shouldn't we just have problems, aggregates are not allowed as implementors public void descriptorReplaced(MWDescriptor oldDescriptor, MWDescriptor newDescriptor) { super.descriptorReplaced(oldDescriptor, newDescriptor); if (this.hasImplementor(oldDescriptor)) { this.removeImplementor(oldDescriptor); if (newDescriptor instanceof MWTableDescriptor) { this.addImplementor(newDescriptor); } } } // ********** MWDescriptor Implementation ********** public void initializeOn(MWDescriptor newDescriptor) { ((MWRelationalDescriptor) newDescriptor).initializeFromMWInterfaceDescriptor(this); } protected void refreshClass(MWClassRefreshPolicy refreshPolicy) throws ExternalClassNotFoundException, InterfaceDescriptorCreationException { super.refreshClass(refreshPolicy); if (! this.getMWClass().isInterface()) { this.asMWTableDescriptor(); } } public void applyAdvancedPolicyDefaults(MWProjectDefaultsPolicy defaultsPolicy) { //do nothing, advanced properites do not apply to interface descriptors } public void unmap() { super.unmap(); this.clearImplementors(); } public boolean canHaveInheritance() { return false; } public MWInheritancePolicy getInheritancePolicy() { return nullInheritancePolicy; } public boolean hasDefinedInheritance() { return false; } public boolean hasActiveInstantiationPolicy() { return false; } // ********** MWRelationalDescriptor implementation ********** public Iterator allQueryKeys() { return this.getAllQueryKeys().iterator(); } public Iterator allQueryKeysIncludingInherited() { return allQueryKeys(); } public Iterator allQueryKeyNames() { return new TransformationIterator(allQueryKeys()) { protected Object transform(Object next) { return ((MWQueryKey) next).getName(); } }; } public MWQueryKey queryKeyNamed(String name) { for (Iterator stream = this.allQueryKeys(); stream.hasNext(); ) { MWQueryKey queryKey = (MWQueryKey) stream.next(); if (queryKey.getName().equals(name)) { return queryKey; } } return null; } public MWQueryKey queryKeyNamedIncludingInherited(String name) { return queryKeyNamed(name); } public Iterator associatedTables() { return NullIterator.instance(); } public int associatedTablesSize() { return 0; } public MWTable getPrimaryTable() { return null; } public Iterator associatedTablesIncludingInherited() { return this.associatedTables(); } public int associatedTablesIncludingInheritedSize() { return this.associatedTablesSize(); } public Iterator candidateTables() { return this.associatedTables(); } public int candidateTablesSize() { return this.associatedTablesSize(); } public Iterator candidateTablesIncludingInherited() { return this.candidateTables(); } public int candidateTablesIncludingInheritedSize() { return this.candidateTablesSize(); } public void notifyExpressionsToRecalculateQueryables() { // do nothing } public List getQueryables(Filter queryableFilter) { return Collections.EMPTY_LIST; } public boolean isTableDescriptor() { return false; } public boolean isAggregateDescriptor() { return false; } public Collection buildAggregateFieldNameGenerators() { return Collections.EMPTY_SET; } public void initializeFromMWAggregateDescriptor(MWAggregateDescriptor oldDescriptor) { // super.initializeFromMWAggregateDescriptor(oldDescriptor); this.initializeFromMWRelationalClassDescriptor(oldDescriptor); } public void initializeFromMWRelationalClassDescriptor(MWRelationalClassDescriptor oldDescriptor) { // super.initializeFromMWRelationalClassDescriptor(oldDescriptor); this.initializeFromMWMappingDescriptor(oldDescriptor); } public void initializeFromMWTableDescriptor(MWTableDescriptor oldDescriptor) { // super.initializeFromMWTableDescriptor(oldDescriptor); this.initializeFromMWRelationalClassDescriptor(oldDescriptor); } public void initializeFromMWInterfaceDescriptor(MWInterfaceDescriptor oldDescriptor) { // super.initializeFromMWInterfaceDescriptor(oldDescriptor); this.initializeFromMWDescriptor(oldDescriptor); } public MWAggregateDescriptor asMWAggregateDescriptor() { throw new RuntimeException("Can't change an interface descriptor to an aggregate descriptor unless the type is not an interface."); } public MWTableDescriptor asMWTableDescriptor() throws InterfaceDescriptorCreationException { if (getMWClass().isInterface()) { throw new RuntimeException("Can't change an interface descriptor to a class descriptor unless the type is not an interface."); } MWTableDescriptor newDescriptor = (MWTableDescriptor) this.getProject().addDescriptorForType(this.getMWClass()); this.initializeDescriptorAfterMorphing(newDescriptor); return newDescriptor; } public MWInterfaceDescriptor asMWInterfaceDescriptor() { return this; } public boolean isInterfaceDescriptor() { return true; } // *************** Problem Handling ************** protected void addProblemsTo(List newProblems) { super.addProblemsTo(newProblems); this.checkImplementors(newProblems); } private void checkImplementors(List newProblems) { for (Iterator stream = this.implementors(); stream.hasNext(); ) { MWDescriptor implementor = (MWDescriptor) stream.next(); if ( ! CollectionTools.contains(implementor.getMWClass().allInterfaces(), this.getMWClass())) { newProblems.add(this.buildProblem(ProblemConstants.INTERFACE_DESCRIPTOR_IMPLEMENTOR_DOES_NOT_IMPLEMENT_INTERFACE, implementor.displayString())); } } } // ********** Runtime Conversion ********** public ClassDescriptor buildRuntimeDescriptor() { ClassDescriptor runtimeDescriptor = super.buildRuntimeDescriptor(); Iterator queryKeys = allQueryKeys(); while (queryKeys.hasNext()) { MWQueryKey bldrQueryKey = (MWQueryKey) queryKeys.next(); QueryKey queryKey = new QueryKey(); queryKey.setName(bldrQueryKey.getName()); runtimeDescriptor.addQueryKey(queryKey); } return runtimeDescriptor; } protected ClassDescriptor buildBasicRuntimeDescriptor() { RelationalDescriptor descriptor = new RelationalDescriptor(); descriptor.setJavaClassName(getMWClass().getName()); descriptor.descriptorIsForInterface(); return descriptor; } // ********** TopLink methods ********** public static XMLDescriptor buildDescriptor() { XMLDescriptor descriptor = new XMLDescriptor(); descriptor.setJavaClass(MWInterfaceDescriptor.class); descriptor.getInheritancePolicy().setParentClass(MWDescriptor.class); XMLCompositeCollectionMapping implementorHandlesMapping = new XMLCompositeCollectionMapping(); implementorHandlesMapping.setAttributeName("implementorHandles"); implementorHandlesMapping.setSetMethodName("setImplementorHandlesForTopLink"); implementorHandlesMapping.setGetMethodName("getImplementorHandlesForTopLink"); implementorHandlesMapping.setReferenceClass(MWDescriptorHandle.class); implementorHandlesMapping.setXPath("implementor-handles/descriptor-handle"); descriptor.addMapping(implementorHandlesMapping); return descriptor; } /** * sort the collection for TopLink */ private Collection getImplementorHandlesForTopLink() { synchronized (this.implementorHandles) { return new TreeSet(this.implementorHandles); } } private void setImplementorHandlesForTopLink(Collection implementorHandles) { for (Iterator stream = implementorHandles.iterator(); stream.hasNext(); ) { ((MWDescriptorHandle) stream.next()).setScrubber(this.implementorScrubber()); } this.implementorHandles = implementorHandles; } }