// ============================================================================
//
// 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.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
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 javax.xml.ws.WebServiceException;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.progress.IProgressService;
import org.talend.core.GlobalServiceRegister;
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.CommandManager;
import org.talend.mdm.repository.core.command.CompoundCommand;
import org.talend.mdm.repository.core.command.ICommand;
import org.talend.mdm.repository.core.command.common.PushCmdCommand;
import org.talend.mdm.repository.core.command.common.UpdateLastServerCommand;
import org.talend.mdm.repository.core.command.deploy.AbstractDeployCommand;
import org.talend.mdm.repository.core.command.deploy.DeployCompoundCommand;
import org.talend.mdm.repository.core.command.deploy.job.BatchDeployJobCommand;
import org.talend.mdm.repository.core.command.param.ICommandParameter;
import org.talend.mdm.repository.core.service.ConsistencyService.ConsistencyCheckResult;
import org.talend.mdm.repository.core.service.IModelValidationService.IModelValidateResult;
import org.talend.mdm.repository.core.service.ModelImpactAnalyseService.ImpactOperation;
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.deploy.DeployStatusDialog;
import org.talend.mdm.repository.ui.dialogs.message.MultiStatusDialog;
import org.talend.mdm.repository.ui.preferences.PreferenceConstants;
import org.talend.mdm.repository.utils.RepositoryResourceUtil;
import org.talend.mdm.repository.utils.UIUtil;
import com.amalto.workbench.utils.XtentisException;
/**
* DOC hbhong class global comment. Detailled comment
*/
public class DeployService {
private static Logger log = Logger.getLogger(DeployService.class);
public static class DeployCategoryStatus extends MultiStatus {
public DeployCategoryStatus(String pluginId, int code, String message, Throwable exception) {
super(pluginId, code, message, exception);
}
}
public static class DeployStatus extends Status {
ICommand command;
public ICommand getCommand() {
return this.command;
}
/**
* DOC hbhong DeployStatus constructor comment.
*
* @param severity
* @param pluginId
* @param message
* @param exception
*/
DeployStatus(int severity, String message, Throwable exception, ICommand command) {
super(severity, RepositoryPlugin.PLUGIN_ID, message, exception);
this.command = command;
}
public static DeployStatus getOKStatus(ICommand command, String msg) {
return new DeployStatus(Status.OK, msg, null, command);
}
public static DeployStatus getInfoStatus(ICommand command, String msg) {
return new DeployStatus(Status.INFO, msg, null, command);
}
public static DeployStatus getErrorStatus(ICommand command, Throwable exception) {
return new DeployStatus(Status.ERROR, exception.getMessage(), exception, command);
}
public static DeployStatus getErrorStatus(ICommand command, String errMsg) {
return new DeployStatus(Status.ERROR, errMsg, null, command);
}
public static DeployStatus getErrorStatus(ICommand command, String errMsg, Throwable exception) {
return new DeployStatus(Status.ERROR, errMsg, exception, command);
}
}
private static DeployService instance = new DeployService();
private DeployService() {
}
public static DeployService getInstance() {
return instance;
}
class DeployProcess implements IRunnableWithProgress {
private List<ICommand> commands;
MultiStatus mStatus = new MultiStatus(RepositoryPlugin.PLUGIN_ID, Status.OK, "", null); //$NON-NLS-1$
public MultiStatus getStatus() {
return this.mStatus;
}
public DeployProcess(List<ICommand> commands) {
this.commands = commands;
}
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
if (commands != null) {
monitor.beginTask(Messages.DeployService_processTitle, commands.size());
for (ICommand cmd : commands) {
if (cmd.getToRunPhase() == ICommand.PHASE_DEPLOY) {
IStatus status = cmd.execute(null, monitor);
mStatus.add(status);
}
monitor.worked(1);
}
monitor.done();
}
}
}
public IStatus deploy(MDMServerDef serverDef, List<IRepositoryViewObject> viewObjs, int defaultCmdType, boolean removeLocked) {
if (removeLocked) {
removeLockedViewObj(viewObjs);
}
IModelValidateResult validateResult = validateModel(viewObjs);
int selectedButton = validateResult.getSelectedButton();
if (selectedButton == IModelValidationService.BUTTON_CANCEL) {
return Status.CANCEL_STATUS;
}
List<IRepositoryViewObject> validObjects = validateResult.getValidObjects(selectedButton);
List<IRepositoryViewObject> invalidObjects = validateResult.getInvalidObjects(selectedButton);
try {
// consistency check
ConsistencyCheckResult consistencyCheckResult = ConsistencyService.getInstance().checkConsistency(serverDef,
validObjects);
if (consistencyCheckResult == null || consistencyCheckResult.isCanceled()) {
return Status.CANCEL_STATUS;
}
validObjects = consistencyCheckResult.getToDeployObjects();
//
CommandManager manager = CommandManager.getInstance();
List<AbstractDeployCommand> commands = manager.getDeployCommands(validObjects, defaultCmdType);
// insert impact dialog
List<AbstractDeployCommand> canceledCommandAfterImpactAnalysis = new LinkedList<AbstractDeployCommand>(commands);
if (UIUtil.isWorkInUI()) {
try {
Map<IRepositoryViewObject, ImpactOperation> analyzeModelImpact = ModelImpactAnalyseService
.analyzeCommandImpact(serverDef, commands);
Map<IRepositoryViewObject, ICommandParameter> paramMap = null;
if (analyzeModelImpact != null) {
ModelImpactAnalyseService.shrinkDeployCommands(analyzeModelImpact, commands);
paramMap = ModelImpactAnalyseService.convertToParameters(analyzeModelImpact);
manager.attachParameterToCommand(commands, paramMap);
}
canceledCommandAfterImpactAnalysis.removeAll(commands);
} catch (InterruptedException ex) {
return Status.CANCEL_STATUS;
}
}
IStatus mainStatus = runCommands(commands, serverDef);
// update consistency value
try {
updateServerConsistencyStatus(serverDef, mainStatus);
} catch (XtentisException e) {
log.error(e.getMessage(), e);
} catch (WebServiceException e) {
log.error(e.getMessage(), e);
}
//
generateValidationFailedDeployStatus(mainStatus, invalidObjects);
if (UIUtil.isWorkInUI()) {
generateConsistencyCancelDeployStatus(mainStatus,
consistencyCheckResult.getToSkipObjects().toArray(new IRepositoryViewObject[0]));
for (AbstractDeployCommand cmd : canceledCommandAfterImpactAnalysis) {
generateConsistencyCancelDeployStatus(mainStatus, cmd.getViewObject());
}
}
return mainStatus;
} catch (Exception e) {
log.error(e.getMessage(), e);
String url = serverDef.getProtocol() + serverDef.getHost() + ":" + serverDef.getPort() //$NON-NLS-1$
+ serverDef.getPath();
String title = Messages.bind(Messages.Server_cannot_connected, url);
MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), title,
Messages.AbstractDataClusterAction_ConnectFailed);
return Status.CANCEL_STATUS;
}
}
public void updateServerConsistencyStatus(MDMServerDef serverDef, IStatus mainStatus) throws XtentisException,
WebServiceException {
if (!UIUtil.isWorkInUI()) {
return;
}
if (mainStatus.isMultiStatus()) {
Set<IRepositoryViewObject> viewObjs = new HashSet<IRepositoryViewObject>();
for (IStatus childStatus : mainStatus.getChildren()) {
DeployStatus deployStatus = null;
if (childStatus instanceof DeployStatus) {
deployStatus = (DeployStatus) childStatus;
if (deployStatus.isOK()) {
AbstractDeployCommand command = (AbstractDeployCommand) deployStatus.getCommand();
if (command instanceof BatchDeployJobCommand) {
for (ICommand subCmd : ((BatchDeployJobCommand) command).getSubCmds()) {
if (subCmd instanceof AbstractDeployCommand) {
IRepositoryViewObject viewObj = ((AbstractDeployCommand) subCmd).getViewObject();
if (viewObj != null) {
viewObjs.add(viewObj);
}
}
}
} else {
IRepositoryViewObject viewObj = command.getViewObject();
if (viewObj != null) {
viewObjs.add(viewObj);
}
}
}
} else if (childStatus instanceof MultiStatus) {
updateServerConsistencyStatus(serverDef, childStatus);
}
}
updateServerConsistencyStatus(serverDef, viewObjs);
}
}
private void updateServerConsistencyStatus(MDMServerDef serverDef, Collection<IRepositoryViewObject> viewObjs)
throws XtentisException, WebServiceException {
ConsistencyService consistencyService = ConsistencyService.getInstance();
for (IRepositoryViewObject viewObj : viewObjs) {
consistencyService.updateDigestValue(serverDef, viewObj);
}
}
public void generateValidationFailedDeployStatus(IStatus mainStatus, List<IRepositoryViewObject> cancelViewObjs) {
for (IRepositoryViewObject viewObj : cancelViewObjs) {
ICommand cancelCmd = CommandManager.getInstance().getNewCommand(ICommand.CMD_NOP);
cancelCmd.updateViewObject(viewObj);
DeployStatus cancelStatus = DeployStatus.getInfoStatus(cancelCmd,
Messages.bind(Messages.Deploy_cancel_text, viewObj.getLabel()));
((MultiStatus) mainStatus).add(cancelStatus);
}
}
public void generateConsistencyCancelDeployStatus(IStatus mainStatus, IRepositoryViewObject... cancelViewObjs) {
if (cancelViewObjs != null) {
for (IRepositoryViewObject viewObj : cancelViewObjs) {
ICommand cancelCmd = CommandManager.getInstance().getNewCommand(ICommand.CMD_NOP);
cancelCmd.updateViewObject(viewObj);
DeployStatus cancelStatus = DeployStatus.getInfoStatus(cancelCmd, Messages.DeployService_conflictCancelStatus
+ viewObj.getLabel());
((MultiStatus) mainStatus).add(cancelStatus);
}
}
}
/**
* work for updater server operation.
*
* @param serverDef
* @param viewObjs
* @param selectededCommands
* @return
* @throws XtentisException
*/
public ConsistencyCheckResult checkConsistency(MDMServerDef serverDef, List<IRepositoryViewObject> viewObjs,
List<AbstractDeployCommand> selectededCommands) throws XtentisException {
Map<IRepositoryViewObject, Integer> viewObCmdOpjMap = new HashMap<IRepositoryViewObject, Integer>();
for (AbstractDeployCommand cmd : selectededCommands) {
IRepositoryViewObject viewObj = cmd.getViewObject();
if (viewObj != null && viewObjs.contains(viewObj)) {
viewObCmdOpjMap.put(viewObj, cmd.getCommandType());
}
}
return ConsistencyService.getInstance().checkConsistency(serverDef, viewObCmdOpjMap);
}
public IModelValidateResult validateModel(List<IRepositoryViewObject> viewObjs) {
IModelValidationService service = (IModelValidationService) GlobalServiceRegister.getDefault().getService(
IModelValidationService.class);
IModelValidateResult validateResult = service.validate(viewObjs, IModelValidationService.VALIDATE_BEFORE_DEPLOY);
return validateResult;
}
public IStatus deployAnotherVersion(MDMServerDef serverDef, List<IRepositoryViewObject> viewObjs) {
CommandManager manager = CommandManager.getInstance();
List<AbstractDeployCommand> commands = manager.getDeployCommandsWithoutHistory(viewObjs);
try {
// insert impact dialog
Map<IRepositoryViewObject, ImpactOperation> analyzeModelImpact = ModelImpactAnalyseService.analyzeCommandImpact(
serverDef, commands);
Map<IRepositoryViewObject, ICommandParameter> paramMap = null;
if (analyzeModelImpact != null) {
ModelImpactAnalyseService.shrinkDeployCommands(analyzeModelImpact, commands);
paramMap = ModelImpactAnalyseService.convertToParameters(analyzeModelImpact);
manager.attachParameterToCommand(commands, paramMap);
}
} catch (InterruptedException ex) {
return Status.CANCEL_STATUS;
}
return runCommands(commands, serverDef);
}
public IStatus deploy(MDMServerDef serverDef, List<IRepositoryViewObject> viewObjs, int defaultCmdType) {
return deploy(serverDef, viewObjs, defaultCmdType, false);
}
private void removeLockedViewObj(List<IRepositoryViewObject> viewObjs) {
if (viewObjs != null) {
for (java.util.Iterator<IRepositoryViewObject> il = viewObjs.iterator(); il.hasNext();) {
if (RepositoryResourceUtil.isLockedAndEdited(il.next())) {
il.remove();
}
}
}
}
public boolean isAutoDeploy() {
return PlatformUI.getPreferenceStore().getBoolean(PreferenceConstants.P_AUTO_DEPLOY);
}
public List<IRepositoryViewObject> getAssociatedObjects(IRepositoryViewObject viewObject) {
List<IRepositoryViewObject> viewObjs = new LinkedList<IRepositoryViewObject>();
if (viewObject != null) {
ERepositoryObjectType type = viewObject.getRepositoryObjectType();
if (type != null) {
IInteractiveHandler handler = InteractiveService.findHandler(type);
if (handler != null) {
List<IRepositoryViewObject> associatedObjects = handler.getAssociatedObjects(viewObject);
if (associatedObjects != null) {
for (IRepositoryViewObject associatedObj : associatedObjects) {
viewObjs.add(associatedObj);
}
}
}
}
}
return viewObjs;
}
public void autoDeploy(Shell shell, IRepositoryViewObject viewObj) {
if (shell == null || viewObj == null) {
throw new IllegalArgumentException();
}
MDMServerDef serverDef = RepositoryResourceUtil.getLastServerDef(viewObj);
if (serverDef != null) {
if (!serverDef.isEnabled()) {
MessageDialog.openWarning(shell, null, Messages.DeployService_CanNotDeployToDisabledServer);
return;
}
List<IRepositoryViewObject> viewObjs = getAssociatedObjects(viewObj);
viewObjs.add(0, viewObj);
IStatus status = deploy(serverDef, viewObjs, ICommand.CMD_MODIFY, false);
if (!status.isOK()) {
return;
}
updateAutoStatus(status);
if (status.isMultiStatus()) {
showDeployStatus(shell, status);
}
} else {
boolean warnUser = PlatformUI.getPreferenceStore().getBoolean(PreferenceConstants.P_WARN_USER_AUTO_DEPLOY);
if (warnUser) {
MessageDialog.openWarning(shell, Messages.Warning_text, Messages.NeverDeploy_text);
}
}
}
public List<IRepositoryViewObject> getDeployViewObject(List<AbstractDeployCommand> selectededCommands) {
List<IRepositoryViewObject> viewObjs = new ArrayList<IRepositoryViewObject>(selectededCommands.size());
for (AbstractDeployCommand command : selectededCommands) {
IRepositoryViewObject viewObject = command.getViewObject();
if (viewObject != null && !viewObjs.contains(viewObject)) {
viewObjs.add(viewObject);
}
}
return viewObjs;
}
public void removeInvalidCommands(List<IRepositoryViewObject> invalidObjects, List<AbstractDeployCommand> selectededCommands) {
if (invalidObjects == null || invalidObjects.isEmpty()) {
return;
}
for (Iterator<AbstractDeployCommand> il = selectededCommands.iterator(); il.hasNext();) {
AbstractDeployCommand cmd = il.next();
IRepositoryViewObject viewObject = cmd.getViewObject();
if (viewObject != null && invalidObjects.contains(viewObject)) {
il.remove();
}
}
}
protected void updateAutoStatus(IStatus status) {
if (status.isMultiStatus()) {
for (IStatus childStatus : status.getChildren()) {
DeployStatus deployStatus = null;
if (childStatus instanceof DeployStatus) {
deployStatus = (DeployStatus) childStatus;
} else if (childStatus instanceof MultiStatus) {
deployStatus = (DeployStatus) ((MultiStatus) childStatus).getChildren()[0];
}
ICommand command = deployStatus.getCommand();
CommandManager manager = CommandManager.getInstance();
manager.removeCommandStack(command, ICommand.PHASE_DEPLOY);
}
}
}
private void showDeployStatus(Shell shell, IStatus status) {
MultiStatusDialog dialog = new DeployStatusDialog(shell, status);
dialog.open();
}
public IStatus runCommands(List<AbstractDeployCommand> commands, MDMServerDef serverDef) {
reorderCommandObjects(commands);
CommandManager manager = CommandManager.getInstance();
List<ICommand> compundCommands = manager.convertToDeployCompundCommands(commands, serverDef);
manager.arrangeForJobCommands(compundCommands);
//
try {
IProgressService progressService = null;
if (PlatformUI.isWorkbenchRunning()) {
progressService = PlatformUI.getWorkbench().getProgressService();
} else {
progressService = ConsoleProgressService.getInstance();
}
DeployProcess runnable = new DeployProcess(compundCommands);
progressService.run(true, true, runnable);
return runnable.getStatus();
} catch (InvocationTargetException e) {
log.error(e.getMessage(), e);
} catch (InterruptedException e) {
}
return Status.CANCEL_STATUS;
}
private void reorderCommandObjects(List<AbstractDeployCommand> commands) {
List<AbstractDeployCommand> dataModelCommands = new LinkedList<AbstractDeployCommand>();
for (Iterator<AbstractDeployCommand> il = commands.iterator(); il.hasNext();) {
AbstractDeployCommand command = il.next();
IRepositoryViewObject viewObj = command.getViewObject();
if (viewObj != null && viewObj.getRepositoryObjectType() == IServerObjectRepositoryType.TYPE_DATAMODEL) {
dataModelCommands.add(command);
il.remove();
}
}
if (!dataModelCommands.isEmpty()) {
commands.addAll(0, dataModelCommands);
}
}
private void pushRestoreCommand(CommandManager manager, List<ICommand> subCmds, MDMServerDef serverDef) {
if (subCmds != null && subCmds.size() > 0) {
for (ICommand command : subCmds) {
pushRestoreCommand(manager, command, serverDef);
}
}
}
public void updateLastServer(IStatus status, IProgressMonitor monitor) {
CommandManager manager = CommandManager.getInstance();
Map<String, List<ICommand>> commandMap = manager.getAllCommandsByPhase(ICommand.PHASE_AFTER_DEPLOY);
Set<String> ids = getValidUpdateIds(status);
for (String id : commandMap.keySet()) {
boolean canRun = false;
if (ids == null) {
canRun = true;
} else {
canRun = ids.contains(id);
}
if (canRun) {
List<ICommand> cmds = commandMap.get(id);
for (ICommand cmd : cmds) {
cmd.execute(null, monitor);
}
manager.removeCommandStack(id, ICommand.PHASE_AFTER_DEPLOY);
}
}
}
private Set<String> getValidUpdateIds(IStatus status) {
if (status == null || !(status.isMultiStatus())) {
return null;
}
Set<String> ids = new HashSet<String>();
for (IStatus childStatus : status.getChildren()) {
DeployStatus deployStatus = null;
if (childStatus instanceof DeployStatus) {
deployStatus = (DeployStatus) childStatus;
} else if (childStatus instanceof MultiStatus) {
if (((MultiStatus) childStatus).getChildren().length > 0) {
deployStatus = (DeployStatus) ((MultiStatus) childStatus).getChildren()[0];
}
}
if (deployStatus != null && deployStatus.isOK()) {
ICommand command = deployStatus.getCommand();
if (command instanceof BatchDeployJobCommand) {
BatchDeployJobCommand deployJobCommand = (BatchDeployJobCommand) command;
for (ICommand subCmd : deployJobCommand.getSubCmds()) {
ids.add(subCmd.getCommandId());
}
} else {
ids.add(command.getCommandId());
}
}
}
return ids;
}
public void updateChangedStatus(IStatus status) {
updateChangedStatus(status, true);
}
public void updateChangedStatus(IStatus status, boolean isUpdateServer) {
if (status.isMultiStatus()) {
for (IStatus childStatus : status.getChildren()) {
List<DeployStatus> deployStatuses = new ArrayList<DeployStatus>();
if (childStatus instanceof DeployStatus) {
deployStatuses.add((DeployStatus) childStatus);
} else if (childStatus instanceof MultiStatus) {
IStatus[] childrenStatus = ((MultiStatus) childStatus).getChildren();
if (childrenStatus.length > 0) {
for (IStatus cstatus : childrenStatus) {
if (cstatus instanceof DeployStatus) {
deployStatuses.add((DeployStatus) cstatus);
if (((DeployStatus) cstatus).getCommand() instanceof BatchDeployJobCommand) {
break;
}
}
}
}
}
updateForStatus(isUpdateServer, deployStatuses);
}
}
}
private void updateForStatus(boolean isUpdateServer, List<DeployStatus> deployStatuses) {
if (deployStatuses == null || deployStatuses.size() == 0) {
return;
}
for (DeployStatus deployStatus : deployStatuses) {
if (deployStatus != null && deployStatus.isOK()) {
ICommand command = deployStatus.getCommand();
CommandManager manager = CommandManager.getInstance();
manager.removeCommandStack(command, ICommand.PHASE_DEPLOY);
if (isUpdateServer) {
MDMServerDef serverDef = null;
if (command instanceof AbstractDeployCommand) {
serverDef = ((AbstractDeployCommand) command).getServerDef();
} else if (command instanceof DeployCompoundCommand) {
serverDef = ((DeployCompoundCommand) command).getServerDef();
}
if (command instanceof BatchDeployJobCommand) {
BatchDeployJobCommand deployJobCommand = (BatchDeployJobCommand) command;
pushRestoreCommand(manager, deployJobCommand.getSubCmds(), serverDef);
pushRestoreCommand(manager, deployJobCommand.getSubDeleteCmds(), serverDef);
} else {
// updateserver
pushRestoreCommand(manager, command, serverDef);
}
}
}
}
}
public void pushRestoreCommand(CommandManager manager, ICommand command, MDMServerDef serverDef) {
// updateserver
if (command.getCommandType() != ICommand.CMD_DELETE) {
Item item = command.getViewObject().getProperty().getItem();
UpdateLastServerCommand updateLastServerCommand = new UpdateLastServerCommand(item, serverDef);
updateLastServerCommand.setToRunPhase(ICommand.PHASE_AFTER_DEPLOY);
updateLastServerCommand.init(command.getCommandId(), command.getObjLastName());
manager.pushCommand(updateLastServerCommand);
}
//
if (command.getCommandType() == ICommand.CMD_DELETE && !(command instanceof CompoundCommand)) {
UpdateLastServerCommand emptyLastServerCommand = new UpdateLastServerCommand();
PushCmdCommand pushCmd = new PushCmdCommand();
pushCmd.setPushCmdType(ICommand.CMD_ADD);
pushRestoreCommand(manager, command, emptyLastServerCommand);
pushRestoreCommand(manager, command, pushCmd);
}
}
private void pushRestoreCommand(CommandManager manager, ICommand command, ICommand cmd) {
cmd.init(command.getCommandId(), command.getObjLastName());
cmd.setToRunPhase(ICommand.PHASE_RESTORE);
manager.pushCommand(cmd);
}
}