// ============================================================================ // // Copyright (C) 2006-2016 Talend Inc. - www.talend.com // // This source code is available under agreement available at // %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt // // You should have received a copy of the agreement // along with this program; if not, write to Talend SA // 9 rue Pages 92150 Suresnes, France // // ============================================================================ package org.talend.dq.writer; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.log4j.Logger; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; import org.talend.commons.emf.FactoriesUtil; import org.talend.commons.exception.PersistenceException; import org.talend.commons.utils.WorkspaceUtils; import org.talend.core.model.metadata.builder.connection.Connection; import org.talend.core.model.metadata.builder.connection.DatabaseConnection; import org.talend.core.model.metadata.builder.database.DqRepositoryViewService; import org.talend.core.model.properties.ConnectionItem; import org.talend.core.model.properties.Information; import org.talend.core.model.properties.InformationLevel; import org.talend.core.model.properties.Item; import org.talend.core.model.properties.ItemState; import org.talend.core.model.properties.Property; import org.talend.core.model.properties.TDQItem; import org.talend.core.model.properties.User; import org.talend.core.repository.model.ProxyRepositoryFactory; import org.talend.core.repository.utils.AbstractResourceChangesService; import org.talend.core.repository.utils.TDQServiceRegister; import org.talend.cwm.helper.SwitchHelpers; import org.talend.cwm.management.i18n.Messages; import org.talend.dataquality.PluginConstant; import org.talend.dataquality.analysis.Analysis; import org.talend.dataquality.domain.pattern.Pattern; import org.talend.dataquality.helpers.MetadataHelper; import org.talend.dataquality.indicators.definition.IndicatorDefinition; import org.talend.dataquality.properties.PropertiesFactory; import org.talend.dataquality.properties.TDQAnalysisItem; import org.talend.dataquality.properties.TDQBusinessRuleItem; import org.talend.dataquality.properties.TDQIndicatorDefinitionItem; import org.talend.dataquality.properties.TDQMatchRuleItem; import org.talend.dataquality.properties.TDQPatternItem; import org.talend.dataquality.properties.TDQReportItem; import org.talend.dataquality.rules.DQRule; import org.talend.dataquality.rules.MatchRuleDefinition; import org.talend.dataquality.rules.ParserRule; import org.talend.dataquality.rules.WhereRule; import org.talend.dq.helper.EObjectHelper; import org.talend.dq.helper.ListUtils; import org.talend.dq.helper.ModelElementIdentifier; import org.talend.dq.helper.PropertyHelper; import org.talend.model.bridge.ReponsitoryContextBridge; import org.talend.repository.ProjectManager; import org.talend.resource.ResourceManager; import org.talend.utils.sugars.ReturnCode; import org.talend.utils.sugars.TypedReturnCode; import orgomg.cwm.analysis.informationvisualization.RenderedObject; import orgomg.cwm.objectmodel.core.Dependency; import orgomg.cwm.objectmodel.core.ModelElement; import orgomg.cwmx.analysis.informationreporting.Report; /** * DOC bZhou class global comment. Detailled comment */ public abstract class AElementPersistance { private static Logger log = Logger.getLogger(AElementPersistance.class); protected EMFSharedResources util = EMFSharedResources.getInstance(); /** * Persist an element in the specified folder, the file name is created logically by the name of this element. * * @param element * @param folder * @return */ public TypedReturnCode<Object> create(ModelElement element, IFolder folder, boolean... isImportItem) { TypedReturnCode<Object> trc = new TypedReturnCode<Object>(); if (getFileExtension() == null) { trc.setMessage("File extension is null."); //$NON-NLS-1$ log.error(Messages.getString("Get file extension error")); //$NON-NLS-1$ } else { IPath itemPath = folder.getFullPath(); Property property = initProperty(element); Item item = property.getItem(); try { ProxyRepositoryFactory.getInstance().create(item, getPath(element, itemPath), isImportItem); trc.setObject(item); trc.setOk(Boolean.TRUE); } catch (Exception e) { trc.setMessage(e.getMessage()); trc.setOk(Boolean.FALSE); log.warn("Create item failed, try to create it by a logical name. ", e); } } return trc; } /** * DOC xqliu Comment method "getPath". * * @param element * @param itemPath * @return */ private IPath getPath(ModelElement element, IPath itemPath) { IPath path = new Path(PluginConstant.EMPTY_STRING); if (element instanceof DatabaseConnection) { // database connection path = itemPath.makeRelativeTo(ResourceManager.getConnectionFolder().getFullPath()); } else if (element instanceof Analysis) { // analysis path = itemPath.makeRelativeTo(ResourceManager.getAnalysisFolder().getFullPath()); } else if (element instanceof Report) { // report path = itemPath.makeRelativeTo(ResourceManager.getReportsFolder().getFullPath()); } else if (element instanceof IndicatorDefinition) { if (element instanceof WhereRule) { // dqrule path = itemPath.makeRelativeTo(ResourceManager.getRulesSQLFolder().getFullPath()); } else if (element instanceof ParserRule) { // parserrule path = itemPath.makeRelativeTo(ResourceManager.getRulesParserFolder().getFullPath()); } else if (element instanceof MatchRuleDefinition) { path = itemPath.makeRelativeTo(ResourceManager.getRulesMatcherFolder().getFullPath()); } else { // indicator definition path = itemPath.makeRelativeTo(ResourceManager.getIndicatorFolder().getFullPath()); } } else if (element instanceof Pattern) { // pattern path = itemPath.makeRelativeTo(ResourceManager.getPatternFolder().getFullPath()); } return path; } /** * DOC bZhou Comment method "createLogicalFileNmae". * * @param element * @param extension * @return */ public static String createLogicalFileName(ModelElement element, String extension) { return DqRepositoryViewService.createTechnicalName(element.getName()) + "_" + MetadataHelper.getVersion(element) //$NON-NLS-1$ + org.talend.dataquality.PluginConstant.DOT_STRING + extension; } /** * DOC bZhou Comment method "create". * * Persist the element into the specified file. * * @param element * @param file * @return */ public ReturnCode create(ModelElement element, IFile file) { ReturnCode rc = new ReturnCode(); if (!check(file)) { rc.setReturnCode(Messages.getString("AElementPersistance.FailToSave1"), false); //$NON-NLS-1$ } else { rc = create(element, file.getFullPath(), true); } return rc; } /** * DOC bZhou Comment method "create". * * Persist the element into the specified path. * * @param element * @param file * @param withProperty * @return */ public ReturnCode create(ModelElement element, IPath itemPath, boolean withProperty) { ReturnCode rc = new ReturnCode(); if (!util.addEObjectToResourceSet(itemPath.toString(), element)) { rc.setReturnCode(Messages.getString("AElementPersistance.FailToSave2", util.getLastErrorMessage()), false); //$NON-NLS-1$ } else { if (element instanceof RenderedObject) { ((RenderedObject) element).setFileName(itemPath.toString()); } if (withProperty) { createProperty(element); } rc = save(element, withProperty); } return rc; } /** * DOC bZhou Comment method "createProperty". * * Create and save a property from model element resource. * * @param modelElement * @return */ public Property createProperty(ModelElement modelElement) { Resource eResource = modelElement.eResource(); if (eResource == null) { log.error(Messages.getString("AElementPersistance.FailToCreateProperty")); //$NON-NLS-1$ return null; } Property property = initProperty(modelElement); User user = ReponsitoryContextBridge.getUser(); if (user != null) { property.setAuthor(user); } URI propURI = eResource.getURI().trimFileExtension().appendFileExtension(FactoriesUtil.PROPERTIES_EXTENSION); saveProperty(property, propURI); return property; } /** * DOC bZhou Comment method "initProperty". * * Initialized a new property. * * @param modelElement * @return */ public Property initProperty(ModelElement modelElement) { Property property = org.talend.core.model.properties.PropertiesFactory.eINSTANCE.createProperty(); setPropertyMetadata(modelElement, property); property.setCreationDate(new Date()); Item item = createItem(modelElement); property.setItem(item); item.setProperty(property); return property; } private void setPropertyMetadata(ModelElement modelElement, Property property) { String purpose = MetadataHelper.getPurpose(modelElement); String description = MetadataHelper.getDescription(modelElement); String version = MetadataHelper.getVersion(modelElement); String status = MetadataHelper.getDevStatus(modelElement); if (property.getId() == null) { property.setId(EcoreUtil.generateUUID()); } // MOD qiongli 2011-1-7 delimitedfile connection dosen't use modelElement.getName(). if (SwitchHelpers.DELIMITEDFILECONNECTION_SWITCH.doSwitch(modelElement) == null) { if (property.getLabel() == null) { property.setLabel(WorkspaceUtils.normalize(modelElement.getName())); } property.setDisplayName(modelElement.getName()); } property.setPurpose(purpose); property.setDescription(description); property.setStatusCode(status); property.setVersion(version); List<Information> informations = ListUtils.castList(Information.class, property.getInformations()); InformationLevel maxLevel = null; for (Information information : informations) { int value = information.getLevel().getValue(); if (maxLevel == null || value > maxLevel.getValue()) { maxLevel = information.getLevel(); } } property.setMaxInformationLevel(maxLevel); } /** * DOC bZhou Comment method "saveProperty". * * Save a property. * * @param property * @return */ public ReturnCode saveProperty(Property property) { ReturnCode rc = new ReturnCode(); Resource propertyResource = property.eResource(); propertyResource.getContents().add(property.getItem()); propertyResource.getContents().add(property.getItem().getState()); rc.setOk(util.saveResource(propertyResource)); if (!rc.isOk()) { rc.setMessage(util.getLastErrorMessage()); } return rc; } /** * DOC bZhou Comment method "saveProperty". * * @param property * @param uri * @return */ public ReturnCode saveProperty(Property property, URI uri) { ReturnCode rc = new ReturnCode(); Resource propResource = util.createResource(uri); propResource.getContents().add(property); rc = saveProperty(property); return rc; } /** * DOC bZhou Comment method "save". * * Save a model element and update the related property by default. * * @param element * @return */ public ReturnCode save(ModelElement element) { return save(element, true); } /** * DOC bZhou Comment method "save". * * Save a model element and update the related property. * * @param element * @param withProperty * @return */ public ReturnCode save(ModelElement element, boolean withProperty) { ReturnCode rc = new ReturnCode(); addDependencies(element); addResourceContent(element); rc.setOk(util.saveResource(element.eResource())); if (withProperty) { updateProperty(element); } if (rc.isOk()) { rc.setMessage("save " + element.getName() + " is OK!"); //$NON-NLS-1$ //$NON-NLS-2$ if (withProperty) { notifyResourceChanges(); } } else { rc.setMessage(util.getLastErrorMessage()); } return rc; } protected abstract void notifyResourceChanges(); /** * DOC bZhou Comment method "updateProperty". * * Use model element's attribute to update the related property. * * @param element */ public void updateProperty(ModelElement element) { Property property = PropertyHelper.getProperty(element); if (property != null) { setPropertyMetadata(element, property); property.setModificationDate(new Date()); saveProperty(property); } } /** * DOC bZhou Comment method "createItem". * * @param element * @return */ public Item createItem(ModelElement element) { Item item = null; // MOD mzhao feature 13114, 2010-05-19 distinguish tdq items. if (ModelElementIdentifier.isAnalysis(element)) { item = PropertiesFactory.eINSTANCE.createTDQAnalysisItem(); ((TDQAnalysisItem) item).setAnalysis((Analysis) element); } else if (ModelElementIdentifier.isDQRule(element)) { item = PropertiesFactory.eINSTANCE.createTDQBusinessRuleItem(); ((TDQBusinessRuleItem) item).setDqrule((DQRule) element); } else if (ModelElementIdentifier.isDataProvider(element)) { if (element instanceof DatabaseConnection) { item = org.talend.core.model.properties.PropertiesFactory.eINSTANCE.createDatabaseConnectionItem(); ((ConnectionItem) item).setConnection((DatabaseConnection) element); } ((ConnectionItem) item).setConnection((Connection) element); } else if (ModelElementIdentifier.isMatchRule(element)) { // this Condition must before the IndicatorDefinition one because MatchRule instance of it. item = PropertiesFactory.eINSTANCE.createTDQMatchRuleItem(); ((TDQMatchRuleItem) item).setMatchRule((MatchRuleDefinition) element); } else if (ModelElementIdentifier.isID(element)) { item = PropertiesFactory.eINSTANCE.createTDQIndicatorDefinitionItem(); ((TDQIndicatorDefinitionItem) item).setIndicatorDefinition((IndicatorDefinition) element); } else if (ModelElementIdentifier.isPattern(element)) { item = PropertiesFactory.eINSTANCE.createTDQPatternItem(); ((TDQPatternItem) item).setPattern((Pattern) element); } else if (ModelElementIdentifier.isReport(element)) { item = PropertiesFactory.eINSTANCE.createTDQReportItem(); ((TDQReportItem) item).setReport((Report) element); } else { item = org.talend.core.model.properties.PropertiesFactory.eINSTANCE.createTDQItem(); } ItemState itemState = org.talend.core.model.properties.PropertiesFactory.eINSTANCE.createItemState(); itemState.setDeleted(false); item.setState(itemState); if (item instanceof TDQItem) { setTDQItemFileName(element, item); } Resource eResource = element.eResource(); if (eResource != null) { URI uri = eResource.getURI(); if (uri.isPlatform()) { IPath elementPath = new Path(uri.toPlatformString(true)).removeLastSegments(1); IPath typedPath = ResourceManager.getRootProject().getFullPath().append(PropertyHelper.getItemTypedPath(item)); IPath statePath = elementPath.makeRelativeTo(typedPath); itemState.setPath(statePath.toString()); } } return item; } /** * Set the TDQ item file name, this file name will be usefull when commit changes to svn for example. * * @param element The element of which the name might have been renamed. * @param item */ private void setTDQItemFileName(ModelElement element, Item item) { ((TDQItem) item).setFilename(WorkspaceUtils.normalize(element.getName()) + "_" + MetadataHelper.getVersion(element) + PluginConstant.DOT_STRING //$NON-NLS-1$ + this.getFileExtension()); } /** * DOC bZhou Comment method "check". * * @param file * @return */ protected boolean check(IFile file) { return getFileExtension().equalsIgnoreCase(file.getFileExtension()); } /** * DOC bZhou Comment method "addDependencies". * * @param element */ protected abstract void addDependencies(ModelElement element); /** * DOC bZhou Comment method "updateDependencies". * * @param element */ // protected abstract void updateDependencies(ModelElement element); /** * DOC bZhou Comment method "addResourceContent". * * @param element * @return */ protected void addResourceContent(ModelElement element) { Resource eResource = element.eResource(); if (eResource != null) { addResourceContent(eResource, element); } } public void addResourceContent(Resource resource, ModelElement element) { if (resource != null) { EList<EObject> resourceContents = resource.getContents(); if (!resourceContents.contains(element)) { resourceContents.add(element); } EList<Dependency> supplierDependency = element.getSupplierDependency(); if (supplierDependency != null) { for (Dependency dependency : supplierDependency) { if (!resourceContents.contains(dependency)) { resourceContents.add(dependency); } } } } } /** * DOC bZhou Comment method "getFileExtension". * * @return */ protected abstract String getFileExtension(); /** * Save item and it's dependencies(optional). * * @param item * @param careDependency Set explicitly <B>true</B> for needs to update dependencies of item. * @return */ public abstract ReturnCode save(Item item, boolean careDependency); /** * Save item with dependencies. * * @param element * @throws PersistenceException */ protected ReturnCode saveWithDependencies(Item item, ModelElement element) throws PersistenceException { ReturnCode rc = new ReturnCode(); removeDependencies(item); addDependencies(element); addResourceContent(element.eResource(), element); Map<EObject, Collection<Setting>> find = EcoreUtil.ExternalCrossReferencer.find(element.eResource()); Set<EObject> needSaves = new HashSet<EObject>(); for (EObject object : find.keySet()) { Resource re = object.eResource(); if (re == null) { continue; } // only do save when the dependency is not reference project node, and do not do resolve if (!re.getURI().segment(1).equals(ProjectManager.getInstance().getCurrentProject().getTechnicalLabel())) { continue; } // MOD sizhaoliu TDQ-6296 the resource should be resolved before saving the item to make sure the references // are updated. EcoreUtil.resolveAll(re); needSaves.add(object); } // Set the TDQ item file name. if (item instanceof TDQItem) { setTDQItemFileName(element, item); } ProxyRepositoryFactory.getInstance().save(item); AbstractResourceChangesService resChangeService = TDQServiceRegister.getInstance().getResourceChangeService( AbstractResourceChangesService.class); if (resChangeService != null) { for (EObject toSave : needSaves) { // only do save when the dependency is not reference project node toSave = EObjectHelper.resolveObject(toSave); if (!toSave.eResource().getURI().segment(1) .equals(ProjectManager.getInstance().getCurrentProject().getTechnicalLabel())) { continue; } resChangeService.saveResourceByEMFShared(toSave.eResource()); } } return rc; } /** * Save item <B>without</B> dependencies. * * @param element * @throws PersistenceException */ protected ReturnCode saveWithoutDependencies(Item item, ModelElement element) throws PersistenceException { ReturnCode rc = new ReturnCode(); // Set the TDQ item file name. if (item instanceof TDQItem) { setTDQItemFileName(element, item); } ProxyRepositoryFactory.getInstance().save(item); return rc; } protected abstract ReturnCode removeDependencies(Item item); }