/******************************************************************************* * 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.project.relational; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.persistence.tools.workbench.mappingsmodel.MWModel; import org.eclipse.persistence.tools.workbench.mappingsmodel.db.MWDatabase; import org.eclipse.persistence.tools.workbench.mappingsmodel.db.TableStringHolder; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.DescriptorStringHolder; 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.MWMappingDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.relational.MWAggregateDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.relational.MWInterfaceDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.relational.MWRelationalDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.relational.MWTableDescriptor; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.relational.MWAggregateMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.relational.MWManyToManyMapping; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClass; import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClassRepository; 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.SPIManager; import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.SimpleSPIManager; import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.classfile.CFExternalClassRepositoryFactory; import org.eclipse.persistence.tools.workbench.platformsmodel.DatabasePlatform; import org.eclipse.persistence.tools.workbench.utility.ClassTools; import org.eclipse.persistence.tools.workbench.utility.Classpath; import org.eclipse.persistence.tools.workbench.utility.CollectionTools; import org.eclipse.persistence.tools.workbench.utility.iterators.FilteringIterator; import org.eclipse.persistence.tools.workbench.utility.node.Node; import org.eclipse.persistence.tools.workbench.utility.string.PartialStringComparatorEngine.StringHolderPair; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.descriptors.DescriptorEvent; import org.eclipse.persistence.mappings.DirectToFieldMapping; import org.eclipse.persistence.mappings.OneToOneMapping; import org.eclipse.persistence.oxm.XMLDescriptor; import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping; import org.eclipse.persistence.oxm.mappings.XMLDirectMapping; import org.eclipse.persistence.oxm.mappings.XMLTransformationMapping; import org.eclipse.persistence.sessions.DatabaseLogin; import org.eclipse.persistence.sessions.DatasourceLogin; import org.eclipse.persistence.tools.schemaframework.TableCreator; import org.eclipse.persistence.sessions.factories.TableCreatorClassGenerator; public final class MWRelationalProject extends MWProject { /** A non-changing privately-owned repository for tables and login information */ private MWDatabase tableRepository; /** non-changing policy */ private MWSequencingPolicy sequencingPolicy; /** * table creator source code settings */ private volatile String tableCreatorSourceClassName; public final static String TABLE_CREATOR_SOURCE_CLASS_NAME_PROPERTY = "tableCreatorSourceClassName"; private volatile String tableCreatorSourceDirectoryName; public final static String TABLE_CREATOR_SOURCE_DIRECTORY_NAME_PROPERTY = "tableCreatorSourceDirectoryName"; /** non-changing; generate tables from classes */ private MWTableGenerationPolicy tableGenerationPolicy; //This is used for backward compatibility when generating a runtime project //If true we will generate ObjectTypeMappings, TypeConversionMappings, and SerializedObjectMappings with converters //If false we will generate only DirectToFieldMappings with converters private volatile boolean generateDeprecatedDirectMappings; public final static String GENERATE_DEPRECATED_DIRECT_MAPPINGS_PROPERTY = "generateDeprecatedDirectMappings"; // ********** static methods ********** public static XMLDescriptor buildDescriptor() { XMLDescriptor descriptor = new XMLDescriptor(); descriptor.setJavaClass(MWRelationalProject.class); descriptor.getInheritancePolicy().setParentClass(MWProject.class); XMLCompositeObjectMapping databaseMapping = new XMLCompositeObjectMapping(); databaseMapping.setAttributeName("tableRepository"); databaseMapping.setReferenceClass(MWDatabase.class); databaseMapping.setXPath("table-repository"); descriptor.addMapping(databaseMapping); XMLCompositeObjectMapping sequencingPolicyMapping = new XMLCompositeObjectMapping(); sequencingPolicyMapping.setAttributeName("sequencingPolicy"); sequencingPolicyMapping.setReferenceClass(MWSequencingPolicy.class); sequencingPolicyMapping.setXPath("sequencing"); descriptor.addMapping(sequencingPolicyMapping); XMLDirectMapping tableCreatorSourceClassNameMapping = new XMLDirectMapping(); tableCreatorSourceClassNameMapping.setAttributeName("tableCreatorSourceClassName"); tableCreatorSourceClassNameMapping.setXPath("table-creator/class/text()"); tableCreatorSourceClassNameMapping.setNullValue(""); descriptor.addMapping(tableCreatorSourceClassNameMapping); XMLDirectMapping tableCreatorSourceDirectoryNameMapping = new XMLDirectMapping(); tableCreatorSourceDirectoryNameMapping.setAttributeName("tableCreatorSourceDirectoryName"); tableCreatorSourceDirectoryNameMapping.setSetMethodName("setTableCreatorSourceDirectoryNameForTopLink"); tableCreatorSourceDirectoryNameMapping.setGetMethodName("getTableCreatorSourceDirectoryNameForTopLink"); tableCreatorSourceDirectoryNameMapping.setXPath("table-creator/directory/text()"); tableCreatorSourceDirectoryNameMapping.setNullValue(""); descriptor.addMapping(tableCreatorSourceDirectoryNameMapping); XMLCompositeObjectMapping tableGenerationPolicyMapping = new XMLCompositeObjectMapping(); tableGenerationPolicyMapping.setAttributeName("tableGenerationPolicy"); tableGenerationPolicyMapping.setReferenceClass(MWTableGenerationPolicy.class); tableGenerationPolicyMapping.setXPath("table-generation"); descriptor.addMapping(tableGenerationPolicyMapping); XMLDirectMapping generateDeprecatedDirectMappingsMapping = new XMLDirectMapping(); generateDeprecatedDirectMappingsMapping.setAttributeName("generateDeprecatedDirectMappings"); generateDeprecatedDirectMappingsMapping.setXPath("generate-deprecated-direct-mappings/text()"); generateDeprecatedDirectMappingsMapping.setNullValue(Boolean.FALSE); descriptor.addMapping(generateDeprecatedDirectMappingsMapping); return descriptor; } /** * Default constructor - for TopLink use only. */ private MWRelationalProject() { super(); } public MWRelationalProject(String name, SPIManager spiManager, DatabasePlatform databasePlatform) { super(name, spiManager); this.tableRepository = new MWDatabase(this, databasePlatform); } // ********** initialization ********** /** * initialize persistent state */ protected void initialize(Node parent) { super.initialize(parent); this.sequencingPolicy = new MWSequencingPolicy(this); this.tableCreatorSourceClassName = ""; this.tableCreatorSourceDirectoryName = ""; this.tableGenerationPolicy = new MWTableGenerationPolicy(this); this.generateDeprecatedDirectMappings = false; } protected MWProjectDefaultsPolicy buildDefaultsPolicy() { return new MWRelationalProjectDefaultsPolicy(this); } //*********** misc ************* protected void addChildrenTo(List children) { super.addChildrenTo(children); children.add(this.tableRepository); children.add(this.sequencingPolicy); children.add(this.tableGenerationPolicy); } public void notifyExpressionsToRecalculateQueryables() { for (Iterator descriptors = this.descriptors(); descriptors.hasNext(); ) { ((MWRelationalDescriptor) descriptors.next()).notifyExpressionsToRecalculateQueryables(); } } //*********** accessors ************* /** This is used by the I/O manager. */ public MWModel getMetaDataRepository() { return this.getTableRepository(); } /** This is used by MWModel - allows us to make getDatabase() final. */ public MWDatabase getTableRepository() { return this.tableRepository; } public MWSequencingPolicy getSequencingPolicy() { return this.sequencingPolicy; } public MWTableGenerationPolicy getTableGenerationPolicy() { return this.tableGenerationPolicy; } public String getTableCreatorSourceClassName() { return this.tableCreatorSourceClassName; } public void setTableCreatorSourceClassName(String tableCreatorSourceClassName) { Object old = this.tableCreatorSourceClassName; this.tableCreatorSourceClassName = tableCreatorSourceClassName; this.firePropertyChanged(TABLE_CREATOR_SOURCE_CLASS_NAME_PROPERTY, old, tableCreatorSourceClassName); } public String getTableCreatorSourceDirectoryName() { return this.tableCreatorSourceDirectoryName; } public void setTableCreatorSourceDirectoryName(String tableCreatorSourceDirectoryName) { if (tableCreatorSourceDirectoryName == null) { throw new NullPointerException(); } Object old = this.tableCreatorSourceDirectoryName; this.tableCreatorSourceDirectoryName = tableCreatorSourceDirectoryName; this.firePropertyChanged(TABLE_CREATOR_SOURCE_DIRECTORY_NAME_PROPERTY, old, tableCreatorSourceDirectoryName); } // ********** descriptors and mappings ********** protected MWDescriptor createDescriptorForType(MWClass type) throws InterfaceDescriptorCreationException { if (type.isInterface()) { return new MWInterfaceDescriptor(this, type, type.fullName()); } else { return new MWTableDescriptor(this, type, type.fullName()); } } public MWAggregateDescriptor addAggregateDescriptorForType(MWClass type) { MWAggregateDescriptor descriptor = new MWAggregateDescriptor(this, type, type.fullName()); this.addDescriptor(descriptor); return descriptor; } public Iterator descriptorsThatImplement(final MWRelationalDescriptor descriptor) { return new FilteringIterator(this.tableDescriptors()) { protected boolean accept(Object next) { return ((MWDescriptor) next).getMWClass().allInterfacesContains(descriptor.getMWClass()); } }; } public Iterator tableDescriptors() { return new FilteringIterator(this.descriptors()) { protected boolean accept(Object next) { return ((MWRelationalDescriptor) next).isTableDescriptor(); } }; } public Iterator aggregateDescriptors() { return new FilteringIterator(this.descriptors()) { protected boolean accept(Object next) { return ((MWRelationalDescriptor) next).isAggregateDescriptor(); } }; } public Iterator interfaceDescriptors() { return new FilteringIterator(this.descriptors()) { protected boolean accept(Object next) { return ((MWRelationalDescriptor) next).isInterfaceDescriptor(); } }; } public Iterator allWriteableManyToManyMappings() { return new FilteringIterator(this.allWriteableMappings()) { protected boolean accept(Object next) { return ((MWMapping) next) instanceof MWManyToManyMapping; } }; } public Iterator interfaceDescriptorsThatImplement(final MWMappingDescriptor descriptor) { return new FilteringIterator(this.interfaceDescriptors()) { protected boolean accept(Object next) { return ((MWInterfaceDescriptor) next).hasImplementor(descriptor); } }; } // ********** automap ********** /** * the project must have some tables before anything can be automapped */ public boolean canAutomapDescriptors() { return this.getDatabase().tablesSize() > 0; } /** * match classes with tables using partial string matching on their short * names, with any prevailing prefixes and/or suffixes stripped off */ protected void matchClassesAndMetaData(Collection automapDescriptors) { super.matchClassesAndMetaData(automapDescriptors); DescriptorStringHolder[] descriptorHolders = this.buildMetaDataDescriptorStringHolders(automapDescriptors); TableStringHolder[] tableHolders = this.buildTableStringHolders(); StringHolderPair[] pairs = CLASS_META_DATA_NAME_COMPARATOR_ENGINE.match(descriptorHolders, tableHolders); for (int i = pairs.length; i-- > 0;) { StringHolderPair pair = pairs[i]; DescriptorStringHolder descriptorHolder = (DescriptorStringHolder) pair.getStringHolder1(); TableStringHolder tableHolder = (TableStringHolder) pair.getStringHolder2(); if ((descriptorHolder == null) || (tableHolder == null)) { continue; } if (pair.getScore() > 0.45) { // ??? ((MWTableDescriptor) descriptorHolder.getDescriptor()).setPrimaryTable(tableHolder.getTable()); } } } private TableStringHolder[] buildTableStringHolders() { Collection unassignedTables = new ArrayList(this.getDatabase().tablesSize()); CollectionTools.addAll(unassignedTables, this.getDatabase().tables()); unassignedTables.removeAll(this.assignedTables()); return TableStringHolder.buildHolders(unassignedTables); } /** * "primary" tables only? */ private Set assignedTables() { Set tables = new HashSet(this.descriptorsSize()); for (Iterator stream = this.tableDescriptors(); stream.hasNext(); ) { tables.add(((MWTableDescriptor) stream.next()).getPrimaryTable()); } return tables; } // ********** export table creator source ********** public void exportTableCreatorSource() { File tableCreatorSourceFile = this.tableCreatorSourceFile(); tableCreatorSourceFile.getParentFile().mkdirs(); TableCreator tableCreator = new TableCreator(CollectionTools.vector(this.getDatabase().runtimeTableDefinitions())); tableCreator.setName(this.getName()); TableCreatorClassGenerator generator = new TableCreatorClassGenerator(tableCreator); generator.setClassName(this.tableCreatorSourceClassName); generator.setPackageName(this.tableCreatorSourcePackageName()); generator.setOutputFileName(tableCreatorSourceFile.getAbsolutePath()); generator.generate(); } /** * combine the current project source directory and Java file name * return a File object representing the absolute location of the intended table creator source file */ public File tableCreatorSourceFile() { return new File(this.absoluteTableCreatorSourceDirectory(), Classpath.convertToJavaFileName(this.tableCreatorSourceClassName)); } /** * if the table creator source directory is relative, relate it to the * project's save directory */ public File absoluteTableCreatorSourceDirectory() { File dir = new File(this.tableCreatorSourceDirectoryName); if ( ! dir.isAbsolute()) { dir = new File(this.getSaveDirectory(), this.tableCreatorSourceDirectoryName); } return dir; } public String tableCreatorSourcePackageName() { return ClassTools.packageNameForClassNamed(this.tableCreatorSourceClassName); } // ********** aggregate path to field ********** public void recalculateAggregatePathsToColumn(MWMappingDescriptor descriptor) { this.recalculateAggregatePathsToColumn(descriptor, null); } //current mapping is used so that we can stay out of an infinite loop if the aggregates are set up with circular references public void recalculateAggregatePathsToColumn(MWMappingDescriptor descriptor, MWAggregateMapping currentMapping) { for (Iterator stream = this.aggregateMappingsWithReferenceDescriptor(descriptor); stream.hasNext(); ) { MWAggregateMapping mapping = (MWAggregateMapping) stream.next(); if (mapping != currentMapping){ mapping.updatePathsToFields(); this.recalculateAggregatePathsToColumn(mapping.getParentDescriptor(), mapping); } } } private Iterator aggregateMappingsWithReferenceDescriptor(final MWMappingDescriptor descriptor) { return new FilteringIterator(this.allAggregateMappings()) { protected boolean accept(Object next) { return (((MWAggregateMapping) next).getReferenceDescriptor() == descriptor); } }; } private Iterator allAggregateMappings() { return new FilteringIterator(this.allMappings()) { protected boolean accept(Object next) { return (next instanceof MWAggregateMapping); } }; } // ********** conversion to runtime ********** public boolean isGenerateDeprecatedDirectMappings() { return this.generateDeprecatedDirectMappings; } public void setGenerateDeprecatedDirectMappings(boolean newValue) { boolean oldValue = this.generateDeprecatedDirectMappings; this.generateDeprecatedDirectMappings = newValue; firePropertyChanged(GENERATE_DEPRECATED_DIRECT_MAPPINGS_PROPERTY, oldValue, newValue); } protected DatasourceLogin buildRuntimeLogin() { DatabaseLogin login = this.getDatabase().buildDeploymentRuntimeDatabaseLogin(); this.getSequencingPolicy().adjustRuntimeLogin(login); return login; } // ********** TopLink methods ********** /** * convert to platform-independent representation */ private String getTableCreatorSourceDirectoryNameForTopLink() { return this.tableCreatorSourceDirectoryName.replace('\\', '/'); } /** * convert to platform-specific representation */ private void setTableCreatorSourceDirectoryNameForTopLink(String dirName) { this.tableCreatorSourceDirectoryName = new File(dirName).getPath(); } }