// ============================================================================
//
// 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.mdm.repository.core.service;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.talend.core.model.properties.Item;
import org.talend.core.model.repository.ERepositoryObjectType;
import org.talend.core.model.repository.IRepositoryViewObject;
import org.talend.mdm.repository.core.IServerObjectRepositoryType;
import org.talend.mdm.repository.core.command.ICommand;
import org.talend.mdm.repository.core.command.deploy.AbstractDeployCommand;
import org.talend.mdm.repository.core.command.param.DataModelCmdParam;
import org.talend.mdm.repository.core.command.param.ICommandParameter;
import org.talend.mdm.repository.i18n.Messages;
import org.talend.mdm.repository.model.mdmmetadata.MDMServerDef;
import org.talend.mdm.repository.plugin.RepositoryPlugin;
import org.talend.mdm.repository.ui.dialogs.impact.ImpactResultDialog;
import org.talend.mdm.repository.utils.RepositoryResourceUtil;
import com.amalto.workbench.utils.HttpClientUtil;
import com.amalto.workbench.utils.Util;
import com.amalto.workbench.utils.XtentisException;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
/**
* created by HHB on 2014-3-7 Detailled comment
*
*/
public class ModelImpactAnalyseService {
// SEVERITY
public static final int LOW = 1, MEDIUM = 2, HIGH = 3;
public enum ImpactOperation {
RECREATE_TABLE(Messages.ModelImpactAnalyseService_recreateTable),
APPLY_LOW_CHANGE(Messages.ModelImpactAnalyseService_applyChange),
CANCEL(Messages.ModelImpactAnalyseService_cancelDeploying);
private final String description;
private ImpactOperation(String description) {
this.description = description;
}
public static ImpactOperation getOperation(int index) {
EnumSet<ImpactOperation> set = EnumSet.allOf(ImpactOperation.class);
for (ImpactOperation operation : set) {
if (operation.ordinal() == index) {
return operation;
}
}
return null;
}
public String getDescription() {
return this.description;
}
}
public static class Change {
private String message;
private int severity;
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public int getSeverity() {
return this.severity;
}
public void setSeverity(int severity) {
this.severity = severity;
}
}
public static class EntitiesToDrop {
List<String> entities = new ArrayList<String>();
public List<String> getEntities() {
return this.entities;
}
public void addEntity(String entity) {
entities.add(entity);
}
}
static class Severity {
List<Change> changes = new ArrayList<Change>();
public void addChange(Change change) {
changes.add(change);
}
public List<Change> getChanges() {
return this.changes;
}
}
static class SeverityLow extends Severity {
}
static class SeverityMedium extends Severity {
}
static class SeverityHigh extends Severity {
}
public static class Result {
List<Severity> severities = new ArrayList<Severity>();
EntitiesToDrop entitiesToDrop;
public EntitiesToDrop getEntitiesToDrop() {
return this.entitiesToDrop;
}
public void setEntitiesToDrop(EntitiesToDrop entitiesToDrop) {
this.entitiesToDrop = entitiesToDrop;
}
public void addSeverity(Severity severity) {
severities.add(severity);
}
public List<Severity> getSeverities() {
return severities;
}
public List<Change> getChanges() {
List<Change> changes = new ArrayList<ModelImpactAnalyseService.Change>();
if (getSeverities() != null) {
for (Severity severity : getSeverities()) {
if (severity.getChanges() != null) {
for (Change change : severity.getChanges()) {
int s = 0;
if (severity instanceof SeverityHigh) {
s = HIGH;
} else if (severity instanceof SeverityMedium) {
s = MEDIUM;
} else if (severity instanceof SeverityLow) {
s = LOW;
}
change.setSeverity(s);
changes.add(change);
}
}
}
}
return changes;
}
}
private static Logger log = Logger.getLogger(ModelImpactAnalyseService.class);
private static XStream xstream;
private static Result analyzeModelChange(MDMServerDef serverDef, IRepositoryViewObject modelViewObj) throws XtentisException {
String responseMsg = invokeService(serverDef, modelViewObj, false, null);
if (responseMsg != null) {
return readResponseMessage(responseMsg);
}
return null;
}
private static Map<IRepositoryViewObject, Result> analyzeModelChanges(MDMServerDef serverDef,
List<IRepositoryViewObject> modelViewObjs) throws XtentisException {
Map<IRepositoryViewObject, Result> result = new HashMap<IRepositoryViewObject, Result>();
for (IRepositoryViewObject viewObj : modelViewObjs) {
if (viewObj.getRepositoryObjectType() == IServerObjectRepositoryType.TYPE_DATAMODEL) {
Result analyzeResult = analyzeModelChange(serverDef, viewObj);
if (analyzeResult != null) {
List<Change> changes = analyzeResult.getChanges();
if (changes != null && changes.size() > 0) {
result.put(viewObj, analyzeResult);
}
}
}
}
return result;
}
public static Map<IRepositoryViewObject, ImpactOperation> analyzeCommandImpact(MDMServerDef serverDef,
List<AbstractDeployCommand> commands) throws InterruptedException {
List<IRepositoryViewObject> viewObjs = new LinkedList<IRepositoryViewObject>();
for (AbstractDeployCommand cmd : commands) {
int commandType = cmd.getCommandType();
if ((commandType == ICommand.CMD_MODIFY || commandType == ICommand.CMD_ADD) && cmd.getViewObject() != null) {
viewObjs.add(cmd.getViewObject());
}
}
return analyzeModelImpact(serverDef, viewObjs);
}
public static Map<IRepositoryViewObject, ImpactOperation> analyzeModelImpact(MDMServerDef serverDef,
List<IRepositoryViewObject> modelViewObjs) throws InterruptedException {
try {
Map<IRepositoryViewObject, Result> changes = analyzeModelChanges(serverDef, modelViewObjs);
if (!changes.isEmpty()) {
Shell shell = Display.getDefault().getActiveShell();
ImpactResultDialog dialog = new ImpactResultDialog(shell, changes);
if (dialog.open() == IDialogConstants.OK_ID) {
Map<IRepositoryViewObject, ImpactOperation> configuration = dialog.getImpactConfiguration();
return configuration;
} else {
Map<IRepositoryViewObject, ImpactOperation> configuration = new HashMap<IRepositoryViewObject, ModelImpactAnalyseService.ImpactOperation>(
changes.size());
for (IRepositoryViewObject viewObj : changes.keySet()) {
configuration.put(viewObj, ImpactOperation.CANCEL);
}
return configuration;
}
}
} catch (XtentisException e) {
log.error(e.getMessage(), e);
}
return null;
}
public static void updateModel(MDMServerDef serverDef, IRepositoryViewObject modelViewObj, Boolean force)
throws XtentisException {
invokeService(serverDef, modelViewObj, true, force);
}
private static String invokeService(MDMServerDef serverDef, IRepositoryViewObject modelViewObj, boolean isUpdateModel,
Boolean force) throws XtentisException {
String xsd = getModelContent(modelViewObj);
if (xsd != null) {
String contextPath = Util.getContextPath(serverDef.getPath());
String result = HttpClientUtil.invokeModelService(serverDef.getProtocol(), serverDef.getHost(), serverDef.getPort(),
contextPath, serverDef.getUser(), serverDef.getPasswd(), modelViewObj.getLabel(), xsd, isUpdateModel, force);
return result;
}
return null;
}
private static String getModelContent(IRepositoryViewObject viewObj) {
Item item = viewObj.getProperty().getItem();
IFile file = RepositoryResourceUtil.findReferenceFile(IServerObjectRepositoryType.TYPE_DATAMODEL, item, "xsd"); //$NON-NLS-1$
InputStream xsdFileStream = null;
try {
xsdFileStream = file.getContents();
byte[] bytes = IOUtils.toByteArray(xsdFileStream);
String xsd = new String(bytes);
return xsd;
} catch (IOException e) {
log.error(e.getMessage(), e);
} catch (CoreException e) {
log.error(e.getMessage(), e);
} finally {
if (xsdFileStream != null) {
try {
xsdFileStream.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
return null;
}
private static XStream getParser() {
if (xstream == null) {
xstream = new XStream(new DomDriver());
xstream.alias("result", Result.class); //$NON-NLS-1$
xstream.alias("change", Change.class); //$NON-NLS-1$
xstream.alias("medium", SeverityMedium.class); //$NON-NLS-1$
xstream.alias("low", SeverityLow.class); //$NON-NLS-1$
xstream.alias("high", SeverityHigh.class); //$NON-NLS-1$
xstream.alias("entitiesToDrop", EntitiesToDrop.class); //$NON-NLS-1$
xstream.alias("entity", String.class); //$NON-NLS-1$
xstream.addImplicitCollection(Result.class, "severities"); //$NON-NLS-1$
xstream.addImplicitCollection(Severity.class, "changes"); //$NON-NLS-1$
xstream.addImplicitCollection(EntitiesToDrop.class, "entities"); //$NON-NLS-1$
}
return xstream;
}
public static Result readResponseMessage(String message) {
if (message != null) {
if (message.trim().isEmpty()) {
// first time deploy
return null;
}
Thread cur = Thread.currentThread();
ClassLoader save = cur.getContextClassLoader();
cur.setContextClassLoader(RepositoryPlugin.getDefault().getClass().getClassLoader());
try {
Result result = (Result) getParser().fromXML(message);
return result;
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
} finally {
cur.setContextClassLoader(save);
}
}
return null;
}
public static void shrinkDeployCommands(Map<IRepositoryViewObject, ImpactOperation> impactResult,
List<AbstractDeployCommand> commands) {
Set<IRepositoryViewObject> toRemoveKeys = new HashSet<IRepositoryViewObject>();
Iterator<AbstractDeployCommand> il = commands.iterator();
while (il.hasNext()) {
AbstractDeployCommand cmd = il.next();
IRepositoryViewObject viewObject = cmd.getViewObject();
if (viewObject != null) {
ERepositoryObjectType type = viewObject.getRepositoryObjectType();
if (type == IServerObjectRepositoryType.TYPE_DATAMODEL) {
ImpactOperation operation = impactResult.get(viewObject);
if (operation == ImpactOperation.CANCEL) {
il.remove();
toRemoveKeys.add(viewObject);
}
} else if (type == IServerObjectRepositoryType.TYPE_MATCH_RULE_MAPINFO) {
String label = viewObject.getLabel();
for (IRepositoryViewObject modelViewObj : impactResult.keySet()) {
if (modelViewObj.getLabel().equals(label)) {
ImpactOperation operation = impactResult.get(modelViewObj);
if (operation == ImpactOperation.CANCEL) {
il.remove();
}
}
}
}
}
}
for (IRepositoryViewObject key : toRemoveKeys) {
impactResult.remove(key);
}
}
public static Map<IRepositoryViewObject, ICommandParameter> convertToParameters(
Map<IRepositoryViewObject, ImpactOperation> impactResult) {
Map<IRepositoryViewObject, ICommandParameter> paramMap = new HashMap<IRepositoryViewObject, ICommandParameter>();
for (IRepositoryViewObject viewObj : impactResult.keySet()) {
ImpactOperation impactOperation = impactResult.get(viewObj);
ICommandParameter param = new DataModelCmdParam(impactOperation);
paramMap.put(viewObj, param);
}
return paramMap;
}
}