/*******************************************************************************
* Copyright 2017 Capital One Services, LLC and Bitwise, Inc.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package hydrograph.ui.graph.execution.tracking.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.ui.parts.GraphicalEditor;
import org.eclipse.swt.widgets.Display;
import org.slf4j.Logger;
import hydrograph.ui.common.util.Constants;
import hydrograph.ui.graph.Messages;
import hydrograph.ui.graph.controller.ComponentEditPart;
import hydrograph.ui.graph.editor.ELTGraphicalEditor;
import hydrograph.ui.graph.execution.tracking.datastructure.ComponentStatus;
import hydrograph.ui.graph.execution.tracking.datastructure.ExecutionStatus;
import hydrograph.ui.graph.execution.tracking.datastructure.SubjobDetails;
import hydrograph.ui.graph.execution.tracking.logger.ExecutionTrackingFileLogger;
import hydrograph.ui.graph.execution.tracking.replay.ViewExecutionHistoryUtility;
import hydrograph.ui.graph.execution.tracking.windows.ExecutionTrackingConsole;
import hydrograph.ui.graph.job.JobManager;
import hydrograph.ui.graph.model.Component;
import hydrograph.ui.graph.model.ComponentExecutionStatus;
import hydrograph.ui.graph.model.Container;
import hydrograph.ui.graph.model.Link;
import hydrograph.ui.logging.factory.LogFactory;
/**
* The Class TrackingDisplayUtils.
*/
public class TrackingStatusUpdateUtils {
/** The logger. */
private Logger logger = LogFactory.INSTANCE.getLogger(TrackingStatusUpdateUtils.class);
/** The instance. */
public static TrackingStatusUpdateUtils INSTANCE = new TrackingStatusUpdateUtils();
private String CLONE_COMPONENT_TYPE ="CloneComponent";
/**
* Instantiates a new tracking display utils.
*/
private TrackingStatusUpdateUtils() {
}
/**
* Update component status and processed record
* @param executionStatus
* @param editor
*/
public void updateEditorWithCompStatus(ExecutionStatus executionStatus, ELTGraphicalEditor editor,boolean isReplay) {
if (executionStatus != null) {
/**
* Push the tracking log in tracking console
*/
if(!isReplay){
pushExecutionStatusToExecutionTrackingConsole(executionStatus);
ExecutionTrackingFileLogger.INSTANCE.log(executionStatus.getJobId(), executionStatus, JobManager.INSTANCE.isLocalMode());
ExecutionTrackingConsoleUtils.INSTANCE.readFile(executionStatus, null, JobManager.INSTANCE.isLocalMode());
}
GraphicalViewer graphicalViewer = (GraphicalViewer) ((GraphicalEditor) editor).getAdapter(GraphicalViewer.class);
for (Iterator<EditPart> ite = graphicalViewer.getEditPartRegistry().values().iterator(); ite.hasNext();) {
EditPart editPart = (EditPart) ite.next();
if (editPart instanceof ComponentEditPart) {
Component component = ((ComponentEditPart) editPart).getCastedModel();
if(isReplay){
Map<String, String> componentNameAndLink = new HashMap();
if(Constants.SUBJOB_COMPONENT.equals(component.getComponentName())){
ViewExecutionHistoryUtility.INSTANCE.subjobParams(componentNameAndLink, component, new StringBuilder(component.getComponentId()+"."), true);
componentNameAndLink.forEach((compId, compName)->{
ViewExecutionHistoryUtility.INSTANCE.addUnusedCompLabel(compId, compName);
});
}
}
/**
* Updating status and record count of subjob
* component in main job.
*/
if (Constants.SUBJOB_COMPONENT.equals(component.getComponentName())) {
if((component.getProperties().get(Constants.TYPE).equals(Constants.INPUT)||component.getProperties().get(Constants.TYPE).equals(Constants.OPERATION))){
Map<String, SubjobDetails> componentNameAndLink = new HashMap();
StringBuilder subjobPrefix = new StringBuilder("");
populateSubjobRecordCount(componentNameAndLink, component,subjobPrefix,true);
applyRecordCountOnSubjobComponent(component, componentNameAndLink, executionStatus);
}
updateStatusCountForSubjobComponent(executionStatus, component, isReplay);
}else{
updateStatusCountForComponent(executionStatus, component, isReplay);
}
}
}
}
}
/**
* Updating status and count for canvas component according to received status.
* @param executionStatus
* @param component
*/
private void updateStatusCountForComponent(
ExecutionStatus executionStatus, Component component, boolean isReplay) {
if(isReplay){
ViewExecutionHistoryUtility.INSTANCE.addUnusedCompLabel(component.getComponentId(), component.getComponentId());
}
for( ComponentStatus componentStatus: executionStatus.getComponentStatus()){
if(componentStatus.getComponentId().substring(componentStatus.getComponentId().lastIndexOf(".")+1).equals(component.getComponentId())){
logger.debug("Updating normal component {} status {}",component.getComponentId(), componentStatus.getCurrentStatus());
component.updateStatus(componentStatus.getCurrentStatus());
for(Link link: component.getSourceConnections()){
if(componentStatus.getComponentId().substring(componentStatus.getComponentId().lastIndexOf(".")+1).equals(link.getSource().getComponentId())){
if(componentStatus.getProcessedRecordCount().get(link.getSourceTerminal()) == null){
ViewExecutionHistoryUtility.INSTANCE.addUnusedCompLabel(link.getSource().getComponentId()+"_"+link.getSourceTerminal(), link.getSource().getComponentId()+"_"+link.getSourceTerminal());
}else{
link.updateRecordCount(componentStatus.getProcessedRecordCount().get(link.getSourceTerminal()).toString());
}
}
}
}
}
}
private void updateStatusCountForSubjobComponent(ExecutionStatus executionStatus,Component component, boolean isReplay) {
ComponentExecutionStatus status=component.getStatus();
if(status==null || StringUtils.equalsIgnoreCase(ComponentExecutionStatus.BLANK.value(),status.value())){
boolean isPending =applyPendingStatus(component, executionStatus);
if(isPending){
component.updateStatus(ComponentExecutionStatus.PENDING.value());
}
}
if(status!=null && !StringUtils.equalsIgnoreCase(ComponentExecutionStatus.SUCCESSFUL.value(),status.value())){
boolean isRunning =applyRunningStatus(component, executionStatus);
if(isRunning){
component.updateStatus(ComponentExecutionStatus.RUNNING.value());
}
}
boolean isFail =applyFailStatus(component, executionStatus);
if(isFail){
component.updateStatus(ComponentExecutionStatus.FAILED.value());
}
if((status!=null && (StringUtils.equalsIgnoreCase(ComponentExecutionStatus.RUNNING.value(),status.value()) || StringUtils.equalsIgnoreCase(ComponentExecutionStatus.PENDING.value(),status.value()))) || isReplay){
boolean isSuccess=applySuccessStatus(component, executionStatus);
if(isSuccess)
component.updateStatus(ComponentExecutionStatus.SUCCESSFUL.value());
}
}
private void applyRecordCountOnSubjobComponent( Component component,Map<String, SubjobDetails> componentNameAndLink, ExecutionStatus executionStatus){
if (!componentNameAndLink.isEmpty()) {
for (Map.Entry<String, SubjobDetails> entry : componentNameAndLink.entrySet()) {
for (ComponentStatus componentStatus : executionStatus.getComponentStatus()) {
if (entry.getKey().contains(componentStatus.getComponentId())) {
List<String> portList = new ArrayList(componentStatus.getProcessedRecordCount().keySet());
for (String port : portList) {
if ((((SubjobDetails) entry.getValue()).getSourceTerminal()).equals(port)) {
for (Link link : component.getSourceConnections()) {
if (link.getSourceTerminal().toString()
.equals(((SubjobDetails) entry.getValue()).getTargetTerminal())) {
link.updateRecordCount(componentStatus.getProcessedRecordCount()
.get(((SubjobDetails) entry.getValue()).getSourceTerminal())
.toString());
break;
}
}
}
}
} else {
continue;
}
}
}
}
}
/**
*
* Populate the map for subjob status and record count.
*
* @param componentNameAndLink map to hold port vs count
* @param component
* @param subjobPrefix use to identify inner subjob components
*/
private void populateSubjobRecordCount(Map<String, SubjobDetails> componentNameAndLink, Component component,StringBuilder subjobPrefix,boolean isParent) {
Component outputSubjobComponent=(Component) component.getProperties().get(Messages.OUTPUT_SUBJOB_COMPONENT);
if(outputSubjobComponent!=null){
for(Link link:outputSubjobComponent.getTargetConnections()){
Component componentPrevToOutput = link.getSource();
if(Constants.SUBJOB_COMPONENT.equals(componentPrevToOutput.getComponentName())){
subjobPrefix.append(component.getComponentId()+".");
populateSubjobRecordCount(componentNameAndLink, componentPrevToOutput,subjobPrefix,false);
}else{
String portNumber = link.getTargetTerminal().replace(Messages.IN_PORT_TYPE, Messages.OUT_PORT_TYPE);
SubjobDetails subjobDetails = new SubjobDetails(link.getSourceTerminal(), portNumber);
if(CLONE_COMPONENT_TYPE.equalsIgnoreCase(componentPrevToOutput.getComponentName())){
componentNameAndLink.put(subjobPrefix+component.getComponentId()+"."+componentPrevToOutput.getComponentId()+"."+portNumber, subjobDetails);
}else{
if(isParent)
componentNameAndLink.put(component.getComponentId()+"."+componentPrevToOutput.getComponentId()+"."+portNumber, subjobDetails);
else
componentNameAndLink.put(subjobPrefix+component.getComponentId()+"."+componentPrevToOutput.getComponentId()+"."+portNumber, subjobDetails);
}
}
}
}
}
private boolean applyPendingStatus(Component component, ExecutionStatus executionStatus) {
boolean isPending = false;
Container container=(Container)component.getProperties().get(Constants.SUBJOB_CONTAINER);
for (Component innerSubComponent : container.getUIComponentList()) {
if(!(innerSubComponent.getComponentName().equals(Messages.INPUT_SUBJOB_COMPONENT)) &&
!(innerSubComponent.getComponentName().equals(Messages.OUTPUT_SUBJOB_COMPONENT))){
for( ComponentStatus componentStatus: executionStatus.getComponentStatus()){
if(Constants.SUBJOB_COMPONENT.equals(innerSubComponent.getComponentName())){
isPending=applyPendingStatus(innerSubComponent, executionStatus);
}else{
String compName = component.getComponentId()+"."+innerSubComponent.getComponentId();
if(componentStatus.getComponentId().contains(compName) && componentStatus.getCurrentStatus().equals(ComponentExecutionStatus.PENDING.value())){
return true;
}
}
}
}
}
return isPending;
}
private boolean applyRunningStatus(Component component, ExecutionStatus executionStatus) {
boolean isRunning = false;
Container container = (Container) component.getProperties().get(Constants.SUBJOB_CONTAINER);
for (Component innerSubComponent : container.getUIComponentList()) {
for( ComponentStatus componentStatus: executionStatus.getComponentStatus()){
if (Constants.SUBJOB_COMPONENT.equals(innerSubComponent.getComponentName())) {
isRunning = applyRunningStatus(innerSubComponent, executionStatus);
} else {
String compName = component.getComponentId() + "."+ innerSubComponent.getComponentId();
if (componentStatus.getComponentId().contains(compName)&& componentStatus.getCurrentStatus().equals(ComponentExecutionStatus.RUNNING.value())) {
return true;
}
}
}
}
return isRunning;
}
private boolean applyFailStatus(Component component, ExecutionStatus executionStatus) {
boolean isFail = false;
Container container = (Container) component.getProperties().get(Constants.SUBJOB_CONTAINER);
for (Component innerSubComponent : container.getUIComponentList()) {
for( ComponentStatus componentStatus: executionStatus.getComponentStatus()){
if (Constants.SUBJOB_COMPONENT.equals(innerSubComponent.getComponentName())) {
isFail =applyFailStatus(innerSubComponent, executionStatus);
} else {
String compName = component.getComponentId() + "."+ innerSubComponent.getComponentId();
if (componentStatus.getComponentId().contains(compName)&& componentStatus.getCurrentStatus().equals(ComponentExecutionStatus.FAILED.value())) {
return true;
}
}
}
}
return isFail;
}
private boolean applySuccessStatus(Component component, ExecutionStatus executionStatus) {
boolean isSuccess = true;
Container container = (Container) component.getProperties().get(Constants.SUBJOB_CONTAINER);
boolean isSubjobComponentStatusAvailable= isSubjobAllComponentsStatusAvailable(container,executionStatus,component);
if(!isSubjobComponentStatusAvailable){
isSuccess = false;
return isSuccess;
}
for (ComponentStatus componentStatus : executionStatus.getComponentStatus()) {
for (Component innerSubComponent : container.getUIComponentList()) {
if (Constants.SUBJOB_COMPONENT.equals(innerSubComponent.getComponentName())) {
isSuccess = applySuccessStatus(innerSubComponent, executionStatus);
} else {
String compName = component.getComponentId() + "."+ innerSubComponent.getComponentId();
if (componentStatus.getComponentId().contains(compName)){
if(!componentStatus.getCurrentStatus().equals(ComponentExecutionStatus.SUCCESSFUL.value())){
return false;
}
}
}
}
}
return isSuccess;
}
/**
* Check for received status response contains status for all subjob component
*@param container
*@param executionStatus
*@param component
*/
private boolean isSubjobAllComponentsStatusAvailable(Container container,ExecutionStatus executionStatus,Component component){
int subjobSocketCount=0;
int subjobComponentCount=0;
for (Component innerSubComponent : container.getUIComponentList()) {
if (Constants.INPUT_SUBJOB.equals(innerSubComponent.getComponentName()) || Constants.OUTPUT_SUBJOB.equals(innerSubComponent.getComponentName())) {
subjobSocketCount++;
}
for (ComponentStatus componentStatus : executionStatus.getComponentStatus()) {
String compName = component.getComponentId() + "."+ innerSubComponent.getComponentId();
if (componentStatus.getComponentId().contains(compName)){
subjobComponentCount++;
break;
}
}
}
if(container.getUIComponentList().size()-subjobSocketCount==subjobComponentCount)
{
return true;
}else{
return false;
}
}
/**
* Push execution status to execution tracking console.
*
* @param executionStatus the execution status
*/
private void pushExecutionStatusToExecutionTrackingConsole(
ExecutionStatus executionStatus) {
String jobId = executionStatus.getJobId();
ExecutionTrackingConsole console = JobManager.INSTANCE.getExecutionTrackingConsoles().get(jobId);
if(console!=null){
updateExecutionTrackingConsole(executionStatus, console,jobId);
}
}
/**
* Update execution tracking console.
*
* @param executionStatus the execution status
* @param console the console
* @param jobId
*/
private void updateExecutionTrackingConsole(
final ExecutionStatus executionStatus,
final ExecutionTrackingConsole console, final String jobId) {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
console.clearConsole();
ExecutionStatus[] status = ExecutionTrackingConsoleUtils.INSTANCE.readFile(executionStatus, null, JobManager.INSTANCE.isLocalMode());
console.setStatus(ExecutionTrackingConsoleUtils.getHeader(jobId));
for(int i=0;i<status.length;i++){
console.setStatus(ExecutionTrackingConsoleUtils.INSTANCE.getExecutionStatusInString(status[i]));
}
}
});
}
}