// ============================================================================ // // 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.cwm.dependencies; import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; 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.resource.Resource; import org.talend.commons.emf.FactoriesUtil; import org.talend.commons.exception.PersistenceException; import org.talend.core.model.metadata.builder.connection.Connection; import org.talend.core.model.properties.Item; import org.talend.core.model.properties.Property; import org.talend.core.model.repository.ERepositoryObjectType; import org.talend.core.model.repository.IRepositoryViewObject; import org.talend.core.model.repository.RepositoryViewObject; import org.talend.core.repository.model.ProxyRepositoryFactory; import org.talend.cwm.helper.ModelElementHelper; import org.talend.cwm.helper.ResourceHelper; import org.talend.cwm.management.i18n.Messages; import org.talend.dataquality.analysis.Analysis; import org.talend.dataquality.domain.pattern.Pattern; import org.talend.dataquality.helpers.AnalysisHelper; import org.talend.dataquality.helpers.IndicatorHelper; import org.talend.dataquality.indicators.Indicator; import org.talend.dataquality.indicators.definition.IndicatorDefinition; import org.talend.dataquality.properties.TDQAnalysisItem; import org.talend.dataquality.properties.TDQFileItem; import org.talend.dataquality.properties.TDQSourceFileItem; import org.talend.dataquality.properties.impl.TDQAnalysisItemImpl; import org.talend.dataquality.properties.impl.TDQIndicatorDefinitionItemImpl; import org.talend.dataquality.reports.TdReport; import org.talend.dq.helper.EObjectHelper; import org.talend.dq.helper.FileUtils; import org.talend.dq.helper.PropertyHelper; import org.talend.dq.writer.AElementPersistance; import org.talend.dq.writer.impl.ElementWriterFactory; import org.talend.resource.EResourceConstant; import org.talend.resource.ResourceManager; import org.talend.utils.sugars.ReturnCode; import org.talend.utils.sugars.TypedReturnCode; import orgomg.cwm.foundation.softwaredeployment.DataManager; import orgomg.cwm.objectmodel.core.Dependency; import orgomg.cwm.objectmodel.core.ModelElement; /** * @author scorreia * * A singleton class to handle dependencies between objects. * * PTODO scorreia clean code of this class. */ public final class DependenciesHandler { /** * As specified in CWM document at p. 67, the dependency kind can be of two types "Usage" or "Abstraction", but can * also be of other types. */ public static final String USAGE = "Usage"; //$NON-NLS-1$ private static DependenciesHandler instance; private static Logger log = Logger.getLogger(DependenciesHandler.class); private DependenciesHandler() { // this.dependencyResource = loadFromFile(PATH_NAME); } public static DependenciesHandler getInstance() { if (instance == null) { instance = new DependenciesHandler(); } return instance; } /** * Method "clearDependencies" is to be used before a file is deleted. The root element is given as argument and the * dependencies on this element are removed in all resources that depend on this element. * * @param elementToDelete a root element which file will be deleted. * @return the list of modified dependencies */ public List<Resource> clearDependencies(ModelElement elementToDelete) { EList<Dependency> clientDependencies; // get the client dependencies ( clientDependencies = elementToDelete.getClientDependency(); // locate resource of each Dependency object List<Resource> modifiedResources = new ArrayList<Resource>(); Iterator<Dependency> it = clientDependencies.iterator(); while (it.hasNext()) { Dependency dependency = it.next(); // MOD qiongli bug 15587.if dependcy is Proxy,reload it and remove the client element if (dependency.eIsProxy()) { dependency = (Dependency) EObjectHelper.resolveObject(dependency); }// ~ Resource dependencyResource = dependency.eResource(); if (dependencyResource != null) { modifiedResources.add(dependencyResource); } } // this clears also the reverse dependencies: remove the elementToDelete // from // Dependency.getClient() clientDependencies.clear(); // now get the objects that depend on the elementToDelete EList<Dependency> supplierDependencies = elementToDelete.getSupplierDependency(); for (Dependency dependency : supplierDependencies) { EList<ModelElement> client = dependency.getClient(); // get the resource of each client for (ModelElement modelElement : client) { Resource clientResource = modelElement.eResource(); if (clientResource != null) { modifiedResources.add(clientResource); } } // clear the dependencies of all clients // this clear the corresponding getClientDependency() of each client // (objects that requires the // elementToDelete) client.clear(); } // MOD zshen :softwareSystem don't belong to dependency but need to remove together. // MOD sizhaoliu TDQ-6316 // if (elementToDelete instanceof Connection) { // SoftwareSystemManager.getInstance().cleanSoftWareSystem((Connection) elementToDelete); // } return modifiedResources; } /** * Method "removeDependenciesBetweenModels" is to be used before a model dependency(elementToRemove) removed from * the elementFromRemove. The elementToRemove not truly to deleted, not a file to deleted, just remove the * dependency between elementFromRemove and elementToRemove, * * @param elementFromRemove * @param elementToRemove * @return */ public List<Resource> removeDependenciesBetweenModels(ModelElement elementFromRemove, List<? extends ModelElement> elementToRemove) { EList<Dependency> clientDependencies; List<Resource> toRemoveResources = new ArrayList<Resource>(); for (ModelElement modelElement : elementToRemove) { toRemoveResources.add(modelElement.eResource()); } // get the client dependencies ( clientDependencies = elementFromRemove.getClientDependency(); // locate resource of each Dependency object List<Resource> modifiedResources = new ArrayList<Resource>(); if (clientDependencies != null) { Iterator<Dependency> dependencyIterator = clientDependencies.iterator(); while (dependencyIterator.hasNext()) { Dependency dependency = dependencyIterator.next(); Resource dependencyResource = dependency.eResource(); if (!toRemoveResources.contains(dependencyResource)) { continue; } if (dependencyResource != null) { modifiedResources.add(dependencyResource); dependencyIterator.remove(); } } } return modifiedResources; } /** * * This method removes supplier dependencies. See * {@link DependenciesHandler#removeDependenciesBetweenModels(ModelElement, List)} * * @param rule * @param analyses * @return */ public boolean removeSupplierDependenciesBetweenModels(ModelElement rule, List<? extends ModelElement> analyses) { List<Resource> toRemoveResources = new ArrayList<Resource>(); for (ModelElement modelElement : analyses) { toRemoveResources.add(modelElement.eResource()); } // get the client dependencies ( EList<Dependency> supplierDependencies = rule.getSupplierDependency(); for (Dependency dependency : supplierDependencies) { EList<ModelElement> client = dependency.getClient(); // get the resource of each client Iterator<ModelElement> dependencyIterator = client.iterator(); while (dependencyIterator.hasNext()) { Resource clientResource = dependencyIterator.next().eResource(); if (clientResource != null) { if (toRemoveResources.contains(clientResource)) { dependencyIterator.remove(); } } } } return true; } /** * Method "createUsageDependencyOn". * * Example Analysis depends on the exitence of a DataProvider. This method must be called * createUsageDependencyOn(Analysis, DataProvider). The created dependency is added to the DataProvider in its * "client dependencies" and to the Analysis in its "supplier dependencies". See OMG CWM spec paragraph 4.3.2.7. * * The resource in which the dependency is stored is the supplier's resource. * * @param kind the kind of dependency * @param clientElement the element that requires the requiredElement * @param supplierElement the required element * @return the Dependency of clientElement on requiredElement */ Dependency createDependencyOn(String kind, ModelElement clientElement, ModelElement supplierElement) { Dependency dependency = ModelElementHelper.createDependencyOn(kind, clientElement, supplierElement); Resource supplierResource = supplierElement.eResource(); if (supplierResource != null) { supplierResource.getContents().add(dependency); } return dependency; } /** * Method "createUsageDependencyOn". * * @param clientElement the analysis that depends on the data provider. * @param dataManager the data provider * @return a true return code if the dependency has been correctly added to the resource of the supplier element. * Return false otherwise. In any case, the dependency is created and the getObject() method returns it. */ TypedReturnCode<Dependency> createUsageDependencyOn(ModelElement clientElement, ModelElement dataManager) { assert dataManager != null; Dependency dependency = createDependencyOn(USAGE, clientElement, dataManager); TypedReturnCode<Dependency> rc = new TypedReturnCode<Dependency>(); rc.setObject(dependency); return rc; } /** * Method "setDependencyOn" sets the dependency between the analysis and the data manager. * * @param analysis the analysis which requires the data manager * @param dataManager the data manager required by the analysis * @return a true return code if the dependency has been correctly added to the resource of the supplier element. * Return false otherwise. The dependency is created only if needed and the getObject() method returns it. */ public TypedReturnCode<Dependency> setDependencyOn(Analysis analysis, DataManager dataManager) { return setUsageDependencyOn(analysis, dataManager); } /** * Method "setUsageDependencyOn". * * @param client the element which depends on the supplier * @param supplier the element needed by the client element * @return the dependency object between the two given elements */ public TypedReturnCode<Dependency> setUsageDependencyOn(ModelElement client, ModelElement supplier) { // get the supplier's usage dependencies EList<Dependency> supplierDependencies = supplier.getSupplierDependency(); // search for clients into them for (Dependency dependency : supplierDependencies) { if (dependency.getKind() != null && USAGE.compareTo(dependency.getKind()) == 0) { // if exist return true with the dependency EObject resolvedObject = ResourceHelper.resolveObject(dependency.getClient(), client); // check whether the client contains relation dependency, if yes remove the dependency firstly if (resolvedObject == null) { if (checkClientDependencyExist(client, supplier)) { // normal case the code should not come here, except import same project with the second time removeClientDependency(client, supplier); } // if not add analysis to the dependency dependency.getClient().add(client); } TypedReturnCode<Dependency> rc = new TypedReturnCode<Dependency>(); rc.setObject(dependency); return rc; } } // if not exist create a usage dependency return createUsageDependencyOn(client, supplier); } /** * DOC zshen Comment method "removeClientDependency". * * @param client * @param supplier */ public void removeClientDependency(ModelElement client, ModelElement supplier) { for (Dependency dependency : client.getClientDependency()) { if (dependency.getKind() != null && USAGE.compareTo(dependency.getKind()) == 0) { EObject resolvedObject = ResourceHelper.resolveObject(dependency.getSupplier(), supplier); if (resolvedObject != null) { client.getClientDependency().remove(dependency); return; } } } } /** * DOC zshen Comment method "checkClientDependency". * * @param client * @param supplier * @return */ private boolean checkClientDependencyExist(ModelElement client, ModelElement supplier) { for (Dependency dependency : client.getClientDependency()) { if (dependency.getKind() != null && USAGE.compareTo(dependency.getKind()) == 0) { EObject resolvedObject = ResourceHelper.resolveObject(dependency.getSupplier(), supplier); if (resolvedObject != null) { return true; } } } return false; } /** * Method "setDependencyOn" sets the dependency between the report and the analysis. * * @param report * @param analysis * @return a true return code if the dependency has been correctly added to the resource of the supplier element. * Return false otherwise. The dependency is created only if needed and the getObject() method returns it. */ public TypedReturnCode<Dependency> setDependencyOn(TdReport report, Analysis analysis) { return setUsageDependencyOn(report, analysis); } public TypedReturnCode<Dependency> setDependencyOn(Indicator indicator, Pattern pattern) { return setUsageDependencyOn(indicator, pattern); } public TypedReturnCode<Dependency> setDependencyOn(Analysis analysis, Pattern pattern) { return setUsageDependencyOn(analysis, pattern); } public TypedReturnCode<Dependency> setDependencyOn(Analysis analysis, IndicatorDefinition indicatorDefinition) { return setUsageDependencyOn(analysis, indicatorDefinition); } /** * * @param object * @return SupplierDependency * * getSupplierDependency */ public List<IRepositoryViewObject> getSupplierDependency(IRepositoryViewObject object) { List<IRepositoryViewObject> listViewObject = new ArrayList<IRepositoryViewObject>(); ModelElement modelElement = PropertyHelper.getModelElement(object.getProperty()); if (object.getProperty().getItem() instanceof TDQFileItem) { return listViewObject; } if (modelElement instanceof IndicatorDefinition) { listViewObject.addAll(getIndicatorDependency(object)); } else { EList<Dependency> supplierDependency = modelElement.getSupplierDependency(); for (Dependency supplier : supplierDependency) { for (ModelElement depencyModelElement : supplier.getClient()) { if (depencyModelElement.eIsProxy()) { // the depency ModelElement is proxy means it is not exist in current project, so need not to do // anyting, just skip it } else { Property property = PropertyHelper.getProperty(depencyModelElement); IRepositoryViewObject repositoryViewObject = new RepositoryViewObject(property); listViewObject.add(repositoryViewObject); } } } } return listViewObject; } /** * * @param property * @return SupplierDependency * * getClintDependency */ public List<Property> getClintDependency(Property property) { List<Property> listProperty = new ArrayList<Property>(); if (property == null) { return listProperty; } ModelElement modelElement = PropertyHelper.getModelElement(property); // MOD qiongli 2012-5-15 TDQ-5259,avoid NPE. if (modelElement == null) { return listProperty; } if (property.getItem() instanceof TDQSourceFileItem) { return listProperty; } EList<Dependency> clientDependency = modelElement.getClientDependency(); for (Dependency clienter : clientDependency) { for (ModelElement depencyModelElement : clienter.getSupplier()) { Property dependencyProperty = PropertyHelper.getProperty(depencyModelElement); // IRepositoryViewObject repositoryViewObject = new RepositoryViewObject(property); if (dependencyProperty != null) { listProperty.add(dependencyProperty); } } } return listProperty; } /** * get Indicator Dependency. * * @return get the list for analysis which use parameter to be a Indicator */ public List<IRepositoryViewObject> getIndicatorDependency(IRepositoryViewObject viewObject) { Item item = viewObject.getProperty().getItem(); List<IRepositoryViewObject> listAnalysisViewObject = new ArrayList<IRepositoryViewObject>(); if (item instanceof TDQIndicatorDefinitionItemImpl) { TDQIndicatorDefinitionItemImpl tdqIndicatorItem = (TDQIndicatorDefinitionItemImpl) item; IndicatorDefinition newIndicatorDefinition = tdqIndicatorItem.getIndicatorDefinition(); List<IRepositoryViewObject> allAnaList = new ArrayList<IRepositoryViewObject>(); try { allAnaList.addAll(ProxyRepositoryFactory.getInstance().getAll(ERepositoryObjectType.TDQ_ANALYSIS_ELEMENT, true)); } catch (PersistenceException e) { log.error(e, e); } for (IRepositoryViewObject theAna : allAnaList) { List<Indicator> indicators = IndicatorHelper.getIndicators(((TDQAnalysisItem) theAna.getProperty().getItem()) .getAnalysis().getResults()); for (Indicator indicator : indicators) { IndicatorDefinition oldIndicatorDefinition = indicator.getIndicatorDefinition(); if (ModelElementHelper.compareUUID(oldIndicatorDefinition, newIndicatorDefinition)) { listAnalysisViewObject.add(theAna); break; } } } } return listAnalysisViewObject; } /** * get Analysis Dependency (for indicator only). * * @return get the list of indicator which in use by the analysis * */ public List<Property> getAnaDependency(Property property) { Item item = property.getItem(); List<Property> listProperty = new ArrayList<Property>(); if (item instanceof TDQAnalysisItemImpl) { TDQAnalysisItemImpl tdqAnaItem = (TDQAnalysisItemImpl) item; Analysis anaElement = tdqAnaItem.getAnalysis(); List<Indicator> indicators = IndicatorHelper.getIndicators(anaElement.getResults()); for (Indicator indicator : indicators) { boolean isContain = false; IndicatorDefinition newIndicatorDefinition = indicator.getIndicatorDefinition(); // MOD qiongli 2012-5-11 TDQ-5256 if (newIndicatorDefinition == null) { continue; } for (Property containViewObject : listProperty) { Item item2 = containViewObject.getItem(); if (item2 instanceof TDQIndicatorDefinitionItemImpl) { IndicatorDefinition oldIndicatorDefinition = ((TDQIndicatorDefinitionItemImpl) item2) .getIndicatorDefinition(); if (ModelElementHelper.compareUUID(oldIndicatorDefinition, newIndicatorDefinition)) { isContain = true; break; } } } if (!isContain) { Property iniProperty = PropertyHelper.getProperty(indicator.getIndicatorDefinition()); if (iniProperty != null) { listProperty.add(iniProperty); } } } } return listProperty; } /** * get Client Dependency List. * * @param Analysis the analysis which we want to save * @return The list all of client dependency(Pattern UDI Connection DQRule) */ public List<ModelElement> getClientDepListByResult(Analysis analysis) { List<ModelElement> clientDependencyList = new ArrayList<ModelElement>(); DataManager connection = analysis.getContext().getConnection(); // when connection is null mean that no any result can be keep so don't need check result again return empty // list if (connection != null) { // DQRule or UDI case clientDependencyList.addAll(AnalysisHelper.getUserDefinedIndicators(analysis)); // pattern case clientDependencyList.addAll(AnalysisHelper.getPatterns(analysis)); clientDependencyList.add(connection); } return clientDependencyList; } /** * * Comment method "removeDependenciesBetweenModel". * * @param supplier * @param client * @return */ public boolean removeDependenciesBetweenModel(ModelElement supplier, ModelElement client) { // get the supplier's usage dependencies boolean hasFind = false; EList<Dependency> supplierDependencies = supplier.getSupplierDependency(); Iterator<Dependency> suppiterator = supplierDependencies.iterator(); while (suppiterator.hasNext()) { Dependency supplierDep = suppiterator.next(); if (supplierDep.getClient().contains(client)) { supplierDep.getClient().remove(client); hasFind = true; break; } } // clint and supplier ues a same dependency so only need to remove once // there can do another logic to revert supplier and client then we use this method will not consider the order // for the argument if (!hasFind) { EList<Dependency> clientDependency = supplier.getClientDependency(); Iterator<Dependency> clientiterator = clientDependency.iterator(); while (clientiterator.hasNext()) { Dependency clientDep = clientiterator.next(); if (clientDep.getSupplier().contains(client)) { clientiterator.remove(); hasFind = true; break; } } } return hasFind; } /** * * delete the dependency between analysis and connection,then save the connection and analysis. * * @param analysis * @return whether it has been deleted * */ public boolean removeConnDependencyAndSave(TDQAnalysisItem analysisItem) { Analysis analysis = analysisItem.getAnalysis(); Connection oldDataProvider = (Connection) analysis.getContext().getConnection(); ReturnCode rect = new TypedReturnCode<Object>(Boolean.TRUE); // Remove old dependencies. if (oldDataProvider != null) { List<ModelElement> tempList = new ArrayList<ModelElement>(); tempList.add(oldDataProvider); DependenciesHandler.getInstance().removeDependenciesBetweenModels(analysis, tempList); Property property = PropertyHelper.getProperty(oldDataProvider); if (property != null) { rect = ElementWriterFactory.getInstance().createDataProviderWriter().save(property.getItem(), false); } else { rect.setOk(Boolean.FALSE); } if (!rect.isOk()) { rect.setMessage(Messages.getString("DependenciesHandler.removeDependFailed")); //$NON-NLS-1$ log.error(rect.getMessage()); } else { analysis.getContext().setConnection(null); analysis.getClientDependency().clear(); rect = ElementWriterFactory.getInstance().createAnalysisWrite().save(analysisItem, false); } } else { log.warn(Messages.getString("DependenciesHandler.removeDependFailByNull", "oldDataProvider")); //$NON-NLS-1$ //$NON-NLS-2$ } return rect.isOk(); } public static ReturnCode removeUselessDependencies(Item localItem, Item remoteItem) { ReturnCode rc = new ReturnCode(); ModelElement remoteModelElement = PropertyHelper.getModelElement(remoteItem.getProperty()); ModelElement localModelElement = PropertyHelper.getModelElement(localItem.getProperty()); for (Dependency remoteClientDependency : remoteModelElement.getClientDependency()) { // rule2, remote-ana List<Dependency> localClients = localModelElement.getClientDependency();// rule1 list Iterator<Dependency> localClientDependency = localClients.iterator(); boolean isContains = false; while (localClientDependency.hasNext()) { // rule2,rule1 Dependency next = localClientDependency.next(); URI uri = EObjectHelper.getURI(remoteClientDependency); String fileName = uri.lastSegment(); URI nexturi = EObjectHelper.getURI(next); String nextfileName = nexturi.lastSegment(); if (StringUtils.equals(fileName, nextfileName)) { isContains = true; break; } } if (isContains == false) { findClientAndRemoveDependencyInLocalProject(remoteClientDependency, localModelElement); } } return rc; } private static void findClientAndRemoveDependencyInLocalProject(ModelElement modelElement, ModelElement analysis) { URI uri = EObjectHelper.getURI(modelElement).trimFileExtension().appendFileExtension(FactoriesUtil.PROPERTIES_EXTENSION); // get file from filename String fileName = uri.lastSegment(); File foundFile = null; EResourceConstant[] topConstants = EResourceConstant.getTopConstants(); for (EResourceConstant resource : topConstants) { File reportFolder = ResourceManager.getRootProject().getLocation().append(resource.getPath()).toFile(); List<File> fileList = FileUtils.getFilesByExtension(reportFolder, FactoriesUtil.PROPERTIES_EXTENSION); for (File file : fileList) { if (file.getName().equals(fileName)) { foundFile = file; break; } } if (foundFile != null) { break; } } // from file to get model and change it if (foundFile != null) { Property property = PropertyHelper.getProperty(foundFile); ModelElement modelElement2 = PropertyHelper.getModelElement(property); List<ModelElement> dependencyClients = EObjectHelper.getDependencyClients(modelElement2); for (ModelElement model : dependencyClients) { if (StringUtils.equals(model.getName(), analysis.getName())) { dependencyClients.remove(model); break; } } EList<Dependency> supplierDependency = modelElement2.getSupplierDependency(); Iterator<Dependency> iterator = supplierDependency.iterator(); while (iterator.hasNext()) { Dependency model = iterator.next(); EList<ModelElement> clients = model.getClient(); for (ModelElement client : clients) { if (StringUtils.equals(client.getName(), analysis.getName())) { iterator.remove(); break; } } } // change the cache content also Item item = property.getItem(); Resource itemResource = ProxyRepositoryFactory.getInstance().getRepositoryFactoryFromProvider().getResourceManager() .getItemResource(item); EObject toRemove = null; for (EObject obj : itemResource.getContents()) { if (obj != null && obj instanceof Dependency) { EList<ModelElement> clients = ((Dependency) obj).getClient(); for (ModelElement model : clients) { if (StringUtils.equals(model.getName(), analysis.getName())) { toRemove = obj; break; } } } } if (toRemove != null) { itemResource.getContents().remove(toRemove); } // save the node AElementPersistance writer = ElementWriterFactory.getInstance().create(item); writer.save(item, true); } } }