/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.transformation.materialization; import java.io.File; import java.util.HashSet; import java.util.Iterator; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.teiid.core.designer.ModelerCoreException; import org.teiid.core.designer.ModelerCoreRuntimeException; import org.teiid.core.designer.util.StringConstants; import org.teiid.core.designer.util.StringUtilities; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.builder.ModelBuildUtil; import org.teiid.designer.core.validation.rules.StringNameValidator; import org.teiid.designer.core.workspace.ModelFileUtil; import org.teiid.designer.core.workspace.ModelResource; import org.teiid.designer.core.workspace.ModelUtil; import org.teiid.designer.core.workspace.ModelWorkspaceException; import org.teiid.designer.extension.ExtensionPlugin; import org.teiid.designer.extension.definition.ModelObjectExtensionAssistant; import org.teiid.designer.extension.registry.ModelExtensionRegistry; import org.teiid.designer.metamodels.core.ModelType; import org.teiid.designer.metamodels.relational.BaseTable; import org.teiid.designer.metamodels.relational.Column; import org.teiid.designer.metamodels.relational.PrimaryKey; import org.teiid.designer.metamodels.relational.RelationalFactory; import org.teiid.designer.metamodels.relational.RelationalPackage; import org.teiid.designer.metamodels.relational.Table; import org.teiid.designer.metamodels.relational.UniqueConstraint; import org.teiid.designer.metamodels.relational.UniqueKey; import org.teiid.designer.metamodels.relational.extension.InfinispanCacheModelExtensionConstants; import org.teiid.designer.metamodels.relational.extension.RelationalModelExtensionConstants; import org.teiid.designer.transformation.TransformationPlugin; import org.teiid.designer.transformation.reverseeng.ReverseEngConstants; /** * This class is used for managing the creation of the JDG-specific POJO and related content including the * materialized source model and table * * @author blafond * */ public class MaterializedModelManager implements ReverseEngConstants { private static String RESULT_MSG = TransformationPlugin.Util.getString("MaterializedModelManager.resultStr"); //$NON-NLS-1$ private static String OK_MSG = TransformationPlugin.Util.getString("MaterializedModelManager.success"); //$NON-NLS-1$ private static IStatus OK_STATUS = new Status(IStatus.OK, TransformationPlugin.PLUGIN_ID, TransformationPlugin.Util.getString("MaterializedModelManager.allInputsOkStatusMessage")); //$NON-NLS-1$ private final StringNameValidator nameValidator = new StringNameValidator(); private ModelResource targetModelResource; private IProject targetProject; private IContainer targetLocation; private Table selectedViewOrTable; private String sourceModelName; private String sourceTableName; private String pojoClassName; private String pojoPackageName; private String annotationType = PROTOBUF; private File pojoFileSystemFolder; private IContainer pojoWorkspaceFolder; private String moduleZipFileName; private boolean createPojo; private boolean generateModule; private MultiStatus result; private Mode mode; public MaterializedModelManager(EObject selectedTableOrView, Mode mode) { this.mode = mode; // // NOTE that for Materialization a virtual table must be selected // if( this.mode == Mode.MATERIALIZE) { this.selectedViewOrTable = (Table)selectedTableOrView; this.sourceTableName = ModelerCore.getModelEditor().getName(this.selectedViewOrTable); this.pojoClassName = this.sourceTableName; this.pojoPackageName = DEFAULT_PACKAGE_NAME; this.sourceModelName = this.sourceTableName + SOURCE_MODEL_NAME_SUFFIX; try { this.targetModelResource = ModelUtil.getModel(this.selectedViewOrTable); this.targetLocation = targetModelResource.getCorrespondingResource().getParent(); this.pojoWorkspaceFolder = this.targetLocation.getProject(); this.moduleZipFileName = this.sourceTableName + DEFAULT_MODULE_SUFFIX; targetProject = this.targetModelResource.getCorrespondingResource().getProject(); } catch (ModelWorkspaceException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { // This mode bypasses the materialization step and does NOT create a source model/table this.createPojo = true; this.selectedViewOrTable = (Table)selectedTableOrView; this.sourceTableName = ModelerCore.getModelEditor().getName(this.selectedViewOrTable); this.pojoClassName = this.sourceTableName; this.pojoPackageName = DEFAULT_PACKAGE_NAME; try { this.targetModelResource = ModelUtil.getModel(this.selectedViewOrTable); this.targetLocation = targetModelResource.getCorrespondingResource().getParent(); this.pojoWorkspaceFolder = this.targetLocation.getProject(); this.moduleZipFileName = this.sourceTableName + DEFAULT_MODULE_SUFFIX; this.targetProject = this.targetModelResource.getCorrespondingResource().getProject(); this.sourceModelName = this.targetModelResource.getItemName(); } catch (ModelWorkspaceException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public MultiStatus execute() { try { ModelResource newSourceModel = constructRelationalModel(); selectedViewOrTable.setMaterialized(true); Table matTable = createMaterializedSourceTable( selectedViewOrTable, false); selectedViewOrTable.setMaterializedTable(matTable); // Add the schema to the materialized view model addValue(newSourceModel, matTable, getModelResourceContents(newSourceModel)); // Create staging table, add to model and set extension property Table stagingTable = createMaterializedSourceTable( selectedViewOrTable, true); addValue(newSourceModel, stagingTable, getModelResourceContents(newSourceModel)); String modelName = ModelUtil.getName(newSourceModel); getExtensionAssistant().setPropertyValue( stagingTable, InfinispanCacheModelExtensionConstants.PropertyIds.PRIMARY_TABLE, modelName + StringConstants.DOT + matTable.getName()); /* "teiid_rel:MATVIEW_AFTER_LOAD_SCRIPT" 'execute {jdgsourcemodelname}.native(''swap cache names'');' "teiid_rel:MATVIEW_BEFORE_LOAD_SCRIPT" 'execute {jdgsourcemodelname}.native(''truncate cache'');', "teiid_rel:MATERIALIZED_STAGE_TABLE" '{jdgsourcemodelname}.{stagingTable}') where {jdgsourcemodelname} as the new JDG Source Model that is created. */ String afterLoadScriptStr = "execute " + sourceModelName + ".native(\'\'swap cache names\'\');"; String beforeLoadScriptStr = "execute " + sourceModelName + ".native(\'\'truncate cache\'\');"; String stageTableStr = sourceModelName + "." + stagingTable.getName(); ModelObjectExtensionAssistant assistant = getRelationalExtensionAssistant(); assistant.setPropertyValue(selectedViewOrTable, RelationalModelExtensionConstants.PropertyIds.MATVIEW_AFTER_LOAD_SCRIPT, afterLoadScriptStr); assistant.setPropertyValue(selectedViewOrTable, RelationalModelExtensionConstants.PropertyIds.MATVIEW_BEFORE_LOAD_SCRIPT, beforeLoadScriptStr); assistant.setPropertyValue(selectedViewOrTable, RelationalModelExtensionConstants.PropertyIds.MATERIALIZED_STAGE_TABLE, stageTableStr); ModelBuildUtil.rebuildImports(targetModelResource.getEmfResource(), true); newSourceModel.save(new NullProgressMonitor(), false); } catch (Exception err) { TransformationPlugin.Util.log(err); } if(result == null) { addStatus(IStatus.OK, OK_MSG, null); } return result; } /** * @return Returns the resultPhysicalModel. * @since 4.1 */ public ModelResource getMaterializedViewModel() { return this.targetModelResource; } private Table createMaterializedSourceTable(Table table, boolean createStagingTable) { //create the new table and the staging table and add them to the result physical model final Table newMatTable = (Table)RelationalFactory.eINSTANCE.create(table.eClass() ); //Create a uniqueName String name = pojoClassName; if( createStagingTable ) { name = "ST_" + name; } String tmp = nameValidator.createValidUniqueName(name); if(tmp != null) { name = tmp; } //Set table names newMatTable.setName(name); //Copy table values copyTableValues(table, newMatTable); //Iterate over the children of the Materialized View and create corresponding columns, primary keys, and indexes in both //the new table and the stage table. final Iterator cols = table.getColumns().iterator(); final HashSet pks = new HashSet(); while(cols.hasNext() ) { final Column nextCol = (Column)cols.next(); final Column newCol = RelationalFactory.eINSTANCE.createColumn(); newMatTable.getColumns().add(newCol); copyColValues(nextCol, newCol); pks.addAll(nextCol.getUniqueKeys() ); } final Iterator pksIt = pks.iterator(); while(pksIt.hasNext() ) { final UniqueKey nextKey = (UniqueKey)pksIt.next(); final UniqueKey newKey = (UniqueKey)RelationalFactory.eINSTANCE.create(nextKey.eClass() ); if(nextKey instanceof PrimaryKey) { ((BaseTable)newMatTable).setPrimaryKey( (PrimaryKey)newKey); }else { ((BaseTable)newMatTable).getUniqueConstraints().add((UniqueConstraint) newKey); } copyUniqueKeyValues(nextKey, newKey); } return newMatTable; } private void addValue(final Object owner, final Object value, EList feature) { try { ModelerCore.getModelEditor().addValue(owner, value, feature); } catch (ModelerCoreException err) { TransformationPlugin.Util.log(err); } } protected void copyTableValues(final Table orig, final Table copy) { //copy.setNameInSource( orig.getNameInSource() ); // Materialized Tables do not represent DB schema or tables so DO NOT SET copy.setCardinality(orig.getCardinality() ); copy.setSystem(orig.isSystem() ); // Defect 16941 - the supportsUpdate flag should always be true for a materialization table //copy.setSupportsUpdate(orig.isSupportsUpdate() ); copy.setSupportsUpdate(true); } private void copyColValues(final Column orig, final Column copy) { copy.setAutoIncremented(orig.isAutoIncremented() ); copy.setCaseSensitive(orig.isCaseSensitive() ); copy.setCharacterSetName(orig.getCharacterSetName() ); copy.setCollationName(orig.getCollationName() ); copy.setCurrency(copy.isCurrency() ); copy.setDefaultValue(orig.getDefaultValue() ); copy.setFixedLength(orig.isFixedLength() ); copy.setFormat(orig.getFormat() ); copy.setLength(orig.getLength() ); copy.setMaximumValue(orig.getMaximumValue() ); copy.setMinimumValue(orig.getMinimumValue() ); copy.setName(orig.getName() ); // copy.setNameInSource(orig.getNameInSource() ); // Materialized Tables do not represent DB schema or tables so DO NOT SET copy.setNativeType(orig.getNativeType() ); copy.setNullable(orig.getNullable() ); copy.setPrecision(orig.getPrecision() ); copy.setRadix(orig.getRadix() ); copy.setScale(orig.getScale() ); copy.setSearchability(orig.getSearchability() ); copy.setSelectable(orig.isSelectable() ); copy.setSigned(orig.isSigned() ); copy.setType(orig.getType() ); // Defect 16941 - the updateable flag should always be true for the columns of a materialization table //copy.setUpdateable(orig.isUpdateable() ); copy.setUpdateable(true); } private void addStatus(final int severity, final String msg, final Exception e) { if(result == null) { result = new MultiStatus(TransformationPlugin.PLUGIN_ID, -1, RESULT_MSG, null); } result.add(new Status(severity, TransformationPlugin.PLUGIN_ID, -1, msg, e) ); } private void copyUniqueKeyValues(final UniqueKey orig, final UniqueKey copy) { copy.setName(orig.getName()); copy.setNameInSource(orig.getNameInSource()); try { final BaseTable copyOwner = copy.getTable(); final BaseTable origOwner = orig.getTable(); final Iterator cols = orig.getColumns().iterator(); while(cols.hasNext() ) { final Column nextOrigCol = (Column)cols.next(); final int index = origOwner.getColumns().indexOf(nextOrigCol); final Column copyCol = (Column)copyOwner.getColumns().get(index); if(nextOrigCol.getName().equals(copyCol.getName() ) ) { copy.getColumns().add(copyCol); }else { final String msg = TransformationPlugin.Util.getString("MaterializedModelManager.errorSettingUCvals", copy.getName()); //$NON-NLS-1$ throw new ModelerCoreRuntimeException(msg); } } } catch (Exception err) { final String msg = TransformationPlugin.Util.getString("MaterializedModelManager.errorSettingUCvals", copy.getName()); //$NON-NLS-1$ throw new ModelerCoreRuntimeException(msg); } } public Table getVirtualTable() { return this.selectedViewOrTable; } public IContainer getTargetLocation() { return targetLocation; } public void setTargetLocation(IContainer projectOrFolder) { this.targetLocation = projectOrFolder; } public EList getModelResourceContents(ModelResource mr) { EList eList = null; try { eList = mr.getEmfResource().getContents(); } catch (ModelWorkspaceException err) { TransformationPlugin.Util.log(err); } return eList; } public void setMaterializedViewModel(ModelResource materializedViewModel) { this.targetModelResource = materializedViewModel; } public String getMaterializedSourceModelName() { return sourceModelName; } public void setMaterializedSourceModelName(String materializedSourceModelName) { this.sourceModelName = materializedSourceModelName; } public IContainer getLocationName() { return targetLocation; } public String getSourceTableName() { return sourceTableName; } public void setSourceTableName(String sourceTableName) { this.sourceTableName = sourceTableName; } public String getPojoClassName() { return pojoClassName; } public void setPojoClassName(String pojoClassName) { this.pojoClassName = pojoClassName; } public String getPojoPackageName() { return pojoPackageName; } public void setPojoPackageName(String pojoPackageName) { this.pojoPackageName = pojoPackageName; } public String getAnnotationType() { return annotationType; } public void setAnnotationType(String annotationType) { this.annotationType = annotationType; } public File getPojoFileSystemFolder() { return pojoFileSystemFolder; } public void setPojoFileSystemFolder(File pojoFileSystemFolder) { this.pojoFileSystemFolder = pojoFileSystemFolder; } public IContainer getPojoWorkspaceFolder() { return pojoWorkspaceFolder; } public void setPojoWorkspaceFolder(IContainer pojoWorkspaceFolder) { this.pojoWorkspaceFolder = pojoWorkspaceFolder; } public String getModuleZipFileName() { return moduleZipFileName; } public void setModuleZipFileName(String moduleZipFileName) { this.moduleZipFileName = moduleZipFileName; } public boolean doCreatePojo() { return createPojo; } public void setCreatePojo(boolean createPojo) { this.createPojo = createPojo; } public boolean doGenerateModule() { return generateModule; } public void setGenerateModule(boolean generateModule) { this.generateModule = generateModule; } public IProject getProject() { return this.targetProject; } public boolean isPojoMode() { return this.mode == Mode.POJO; } public IStatus validate(int pageNumber) { if( pageNumber == 1 ) { if( this.selectedViewOrTable == null ) { return new Status(IStatus.ERROR, TransformationPlugin.PLUGIN_ID, TransformationPlugin.Util.getString("MaterializedModelManager_noVirtualTablesSelectedError")); //$NON-NLS-1$ } if( this.targetLocation == null ) { return new Status(IStatus.ERROR, TransformationPlugin.PLUGIN_ID, TransformationPlugin.Util.getString("MaterializedModelManager_targetLocationIsNullError")); //$NON-NLS-1$ } if( StringUtilities.isEmpty(sourceModelName) ) { return new Status(IStatus.ERROR, TransformationPlugin.PLUGIN_ID, TransformationPlugin.Util.getString("MaterializedModelManager_sourceModelNameIsUndefined")); //$NON-NLS-1$ } if( this.selectedViewOrTable.isMaterialized() ) { return new Status(IStatus.WARNING, TransformationPlugin.PLUGIN_ID, TransformationPlugin.Util.getString("MaterializedModelManager_viewAlreadyMaterializedError", selectedViewOrTable.getName())); //$NON-NLS-1$ } } else if( pageNumber == 2 ) { if( this.doCreatePojo() ) { if( StringUtilities.isEmpty(pojoPackageName) ) { return new Status(IStatus.ERROR, TransformationPlugin.PLUGIN_ID, TransformationPlugin.Util.getString("MaterializedModelManager_packageNameUndefined")); //$NON-NLS-1$ } if( StringUtilities.isEmpty(pojoClassName) ) { return new Status(IStatus.ERROR, TransformationPlugin.PLUGIN_ID, TransformationPlugin.Util.getString("MaterializedModelManager_classNameUndefined")); //$NON-NLS-1$ } if( this.doGenerateModule() && StringUtilities.isEmpty(moduleZipFileName) ) { return new Status(IStatus.ERROR, TransformationPlugin.PLUGIN_ID, TransformationPlugin.Util.getString("MaterializedModelManager_moduleZipFileNameUndefined")); //$NON-NLS-1$ } } } return OK_STATUS; } /** * Create a Relational Model with the supplied name, in the desired project * * @param targetProj the project resource under which to create the model * @param modelName the model name to create * @return the newly-created ModelResource */ private ModelResource constructRelationalModel() { String modelNameWithExt = sourceModelName.trim(); if (!modelNameWithExt.endsWith(ModelFileUtil.DOT_XMI)) { modelNameWithExt += ModelFileUtil.DOT_XMI; } IPath relativeModelPath = targetLocation.getProjectRelativePath().append(modelNameWithExt); final IFile modelFile = targetLocation.getProject().getFile(relativeModelPath); final ModelResource resrc = ModelerCore.create(modelFile); try { resrc.getModelAnnotation().setPrimaryMetamodelUri(RelationalPackage.eNS_URI); resrc.getModelAnnotation().setModelType(ModelType.PHYSICAL_LITERAL); } catch (ModelWorkspaceException mwe) { mwe.printStackTrace(); } try { getExtensionAssistant().applyMedIfNecessary(modelFile); // TODO: JDG Use-Case >> Add translator properties some point // <property name="SupportsDirectQueryProcedure" value="true"/> // <property name="SupportsNativeQueries" value="true"/> resrc.save(new NullProgressMonitor(), false); } catch (ModelWorkspaceException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return resrc; } private ModelObjectExtensionAssistant getExtensionAssistant() { final ModelExtensionRegistry registry = ExtensionPlugin.getInstance().getRegistry(); return (ModelObjectExtensionAssistant)registry.getModelExtensionAssistant(INFINISPAN_EXT_ASSISTANT_NS); } private ModelObjectExtensionAssistant getRelationalExtensionAssistant() { final ModelExtensionRegistry registry = ExtensionPlugin.getInstance().getRegistry(); return (ModelObjectExtensionAssistant)registry.getModelExtensionAssistant(RELATIONAL_EXT_ASSISTANT_NS); } }