All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.resys.hdes.client.spi.envir.ProgramEnvirFactory Maven / Gradle / Ivy

There is a newer version: 3.130.78
Show newest version
package io.resys.hdes.client.spi.envir;

import java.util.ArrayList;

/*-
 * #%L
 * hdes-client-api
 * %%
 * Copyright (C) 2020 - 2021 Copyright 2020 ReSys OÜ
 * %%
 * 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.
 * #L%
 */

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.resys.hdes.client.api.HdesAstTypes;
import io.resys.hdes.client.api.HdesCache;
import io.resys.hdes.client.api.HdesClient.HdesTypesMapper;
import io.resys.hdes.client.api.ast.AstBody.AstBodyType;
import io.resys.hdes.client.api.ast.AstBody.AstSource;
import io.resys.hdes.client.api.ast.AstBody.CommandMessageType;
import io.resys.hdes.client.api.ast.AstDecision;
import io.resys.hdes.client.api.ast.AstFlow;
import io.resys.hdes.client.api.ast.AstService;
import io.resys.hdes.client.api.ast.AstTag;
import io.resys.hdes.client.api.programs.DecisionProgram;
import io.resys.hdes.client.api.programs.FlowProgram;
import io.resys.hdes.client.api.programs.ImmutableProgramEnvir;
import io.resys.hdes.client.api.programs.ImmutableProgramMessage;
import io.resys.hdes.client.api.programs.ImmutableProgramWrapper;
import io.resys.hdes.client.api.programs.ProgramEnvir;
import io.resys.hdes.client.api.programs.ProgramEnvir.ProgramMessage;
import io.resys.hdes.client.api.programs.ProgramEnvir.ProgramStatus;
import io.resys.hdes.client.api.programs.ProgramEnvir.ProgramWrapper;
import io.resys.hdes.client.api.programs.ServiceProgram;
import io.resys.hdes.client.api.programs.TagProgram;
import io.resys.hdes.client.spi.config.HdesClientConfig;
import io.resys.hdes.client.spi.decision.DecisionProgramBuilder;
import io.resys.hdes.client.spi.flow.FlowProgramBuilder;
import io.resys.hdes.client.spi.groovy.ServiceProgramBuilder;
import io.resys.hdes.client.spi.tag.TagProgramBuilder;

public class ProgramEnvirFactory {
  private static final Logger LOGGER = LoggerFactory.getLogger(ProgramEnvirFactory.class);
  private final HdesClientConfig config;
  private final HdesAstTypes hdesTypes;
  private final HdesTypesMapper hdesFactory;
  private final HdesCache cache;
  private final AssociationVisitor tree = new AssociationVisitor();
  private final List visitedIds = new ArrayList<>();
  private final List cachlessIds = new ArrayList<>();
  private final StringBuilder treelog = new StringBuilder();
  private ProgramEnvir baseEnvir;
  
  public ProgramEnvirFactory(HdesAstTypes hdesTypes, HdesTypesMapper hdesFactory, HdesClientConfig config) {
    super();
    this.hdesTypes = hdesTypes;
    this.hdesFactory = hdesFactory;
    this.cache = config.getCache();
    this.config = config;
  }
  
  public ProgramEnvirFactory add(ProgramEnvir envir) {
    this.baseEnvir = envir;
    return this;
  }
  public ProgramEnvirFactory add(AstSource entity, boolean cachless) {
    if(cachless) {
      cachlessIds.add(entity.getId());
    }
    final var wrapper = visitSource(entity);
    visitedIds.add(wrapper.getId());
    tree.add(wrapper);
    return this;
  }
  
  @SuppressWarnings("unchecked")
  public ProgramEnvir build() {
    final var envir = ImmutableProgramEnvir.builder();
    if(baseEnvir != null) {
      baseEnvir.getValues().values().stream()
        .filter(wrapper -> !visitedIds.contains(wrapper.getId()))
        .forEach(tree::add);
    }
    
    tree.build().forEach(e -> {

      visitTreeLog(e);
      
      envir.putValues(e.getId(), e);
      
      final var ast = e.getAst().orElse(null);
      if(ast == null) {
        return;
      }
      
      switch (ast.getBodyType()) {
      case DT: envir.putDecisionsByName(ast.getName(), (ProgramWrapper) e); break;
      case FLOW_TASK: envir.putServicesByName(ast.getName(), (ProgramWrapper) e); break;
      case FLOW: envir.putFlowsByName(ast.getName(), (ProgramWrapper) e); break;
      case TAG: envir.putTagsByName(ast.getName(), (ProgramWrapper) e); break;
      default: break;
      
      }
    });
    if(LOGGER.isDebugEnabled()) {
      LOGGER.debug(new StringBuilder()
          .append("Envir status: " + treelog.length()).append(System.lineSeparator())
          .append(treelog.toString())
          .toString());
    }
    return envir.build();
  }
  
  public void visitTreeLog(ProgramWrapper wrapper) {
    if(LOGGER.isDebugEnabled()) {
      final String name = wrapper.getAst().map(w -> w.getName()).orElseGet(() -> wrapper.getId());
      treelog.append("  - ").append(name).append(": ").append(wrapper.getStatus()).append(System.lineSeparator());
      if(wrapper.getStatus() != ProgramStatus.UP) {
      
        for(final var error : wrapper.getErrors()) {
          treelog.append("    - ").append(error.getId()).append(": ").append(error.getMsg()).append(System.lineSeparator());
          if(error.getException() != null) {
            treelog.append("      ").append(ExceptionUtils.getStackTrace(error.getException())).append(System.lineSeparator());
          }
        }
      }
    }

  }
  
  private ProgramWrapper visitSource(AstSource entity) {
    ProgramWrapper result = null;
    switch (entity.getBodyType()) {
    case DT: result = visitDecision(entity); break;
    case FLOW: result = visitFlow(entity); break;
    case FLOW_TASK: result = visitFlowTask(entity); break;
    case TAG: result = visitTag(entity); break;
    default: throw new IllegalArgumentException("unknown command format type: '" + entity.getBodyType() + "'!");
    }
    return result;
  }

  private ProgramWrapper visitDecision(AstSource src) {
    final ImmutableProgramWrapper.Builder builder = ImmutableProgramWrapper.builder();
    builder.status(ProgramStatus.UP);
    AstDecision ast = null;
    try {
      
      if(cachlessIds.contains(src.getId())) {
        ast = hdesTypes.decision().src(src.getCommands()).build();
      } else {
        final var cached = cache.getAst(src);
        if(cached.isPresent()) {
          ast = (AstDecision) cached.get();
        } else {
          ast = hdesTypes.decision().src(src.getCommands()).build();
          cache.setAst(ast, src);
        }
      }
      
      final var errors = ast.getMessages().stream()
        .filter(m -> m.getType() == CommandMessageType.ERROR)
        .map(error -> ImmutableProgramMessage.builder()
            .id("ast-error")
            .msg("line: " + error.getLine() + ": " + error.getValue())
            .build())
        .collect(Collectors.toList());
      builder.addAllErrors(errors);
      
      if(!errors.isEmpty()) {
        builder.status(ProgramStatus.AST_ERROR);
      }
    } catch(Exception e) {
      LOGGER.error(new StringBuilder()
          .append(e.getMessage()).append(System.lineSeparator())
          .append("  - decision source: ").append(this.hdesFactory.commandsString(src.getCommands()))
          .toString(), e);
      builder.status(ProgramStatus.AST_ERROR).addAllErrors(visitException(e));
    }
    
    DecisionProgram program = null;
    if(ast != null) {
      try {
        if(cachlessIds.contains(src.getId())) {
          program = new DecisionProgramBuilder(hdesFactory).build(ast);
        } else {
          final var cached = cache.getProgram(src);
          if(cached.isPresent()) {
            program = (DecisionProgram) cached.get();
          } else {
            program = new DecisionProgramBuilder(hdesFactory).build(ast);
            cache.setProgram(program, src);          
          }
        }
      } catch(Exception e) {
        LOGGER.error(new StringBuilder()
            .append(e.getMessage()).append(System.lineSeparator())
            .append("  - decision source: ").append(this.hdesFactory.commandsString(src.getCommands()))
            .toString(), e);
        builder.status(ProgramStatus.PROGRAM_ERROR).addAllErrors(visitException(e));
      }
    }
    
    return builder.id(src.getId())
        .type(AstBodyType.DT)
        .ast(Optional.ofNullable(ast))
        .program(Optional.ofNullable(program))
        .source(src)
        .build();
  }
  
  private ProgramWrapper visitFlow(AstSource src) {
    final ImmutableProgramWrapper.Builder builder = ImmutableProgramWrapper.builder();
    builder.status(ProgramStatus.UP);
    
    AstFlow ast = null;
    try {
      if(cachlessIds.contains(src.getId())) {
        ast = hdesTypes.flow().src(src.getCommands()).build();
      } else {
        final var cached = cache.getAst(src);
        if(cached.isPresent()) {
          ast = (AstFlow) cached.get();
        } else {
          ast = hdesTypes.flow().src(src.getCommands()).build();
          cache.setAst(ast, src);
        }
      }
      final var errors = ast.getMessages().stream()
        .filter(m -> m.getType() == CommandMessageType.ERROR)
        .map(error -> ImmutableProgramMessage.builder()
            .id("ast-error")
            .msg("line: " + error.getLine() + ": " + error.getValue())
            .build())
        .collect(Collectors.toList());
      builder.addAllErrors(errors);
      
      if(!errors.isEmpty()) {
        builder.status(ProgramStatus.AST_ERROR);
      }
      
    } catch(Exception e) {
      LOGGER.error(new StringBuilder()
          .append(e.getMessage()).append(System.lineSeparator())
          .append("  - flow source: ").append(this.hdesFactory.commandsString(src.getCommands()))
          .toString(), e);
      builder.status(ProgramStatus.AST_ERROR).addAllErrors(visitException(e));
    }
    
    FlowProgram program = null;
    if(ast != null) {
      try {
        if(cachlessIds.contains(src.getId())) {
          program = new FlowProgramBuilder(hdesFactory).build(ast);
        } else {
          final var cached = cache.getProgram(src);
          if(cached.isPresent()) {
            program = (FlowProgram) cached.get();
          } else {
            program = new FlowProgramBuilder(hdesFactory).build(ast);
            cache.setProgram(program, src);
          }
        }
      } catch(Exception e) {
        LOGGER.error(new StringBuilder()
            .append(e.getMessage()).append(System.lineSeparator())
            .append("  - flow source: ").append(this.hdesFactory.commandsString(src.getCommands()))
            .toString(), e);
        builder.status(ProgramStatus.PROGRAM_ERROR).addAllErrors(visitException(e));
      }
    }
    return builder.id(src.getId())
        .ast(Optional.ofNullable(ast)).program(Optional.ofNullable(program))
        .source(src)
        .type(AstBodyType.FLOW).build(); 
  }
  
  private ProgramWrapper visitTag(AstSource src) {
    final ImmutableProgramWrapper.Builder builder = ImmutableProgramWrapper.builder();
    builder.status(ProgramStatus.UP);
    AstTag ast = null;
    try {      
      if(cachlessIds.contains(src.getId())) {
        ast = hdesTypes.tag().src(src.getCommands()).build();
      } else {
        final var cached = cache.getAst(src);
        if(cached.isPresent()) {
          ast = (AstTag) cached.get();
        } else {
          ast = hdesTypes.tag().src(src.getCommands()).build();
          cache.setAst(ast, src);
        }
      }
      
      final var errors = ast.getMessages().stream()
          .filter(m -> m.getType() == CommandMessageType.ERROR)
          .map(error -> ImmutableProgramMessage.builder()
              .id("ast-error")
              .msg("line: " + error.getLine() + ": " + error.getValue())
              .build())
          .collect(Collectors.toList());
        builder.addAllErrors(errors);
      if(!errors.isEmpty()) {
        LOGGER.error(new StringBuilder()
            .append(String.join(System.lineSeparator(), errors.stream().map(e -> e.getMsg()).collect(Collectors.toList())))
            .append("  - tag source: ").append(this.hdesFactory.commandsString(src.getCommands()))
            .toString());
        builder.status(ProgramStatus.AST_ERROR);
      }
    } catch(Exception e) {
      LOGGER.error(new StringBuilder()
          .append(e.getMessage()).append(System.lineSeparator())
          .append("  - tag source: ").append(this.hdesFactory.commandsString(src.getCommands()))
          .toString(), e);
      builder.status(ProgramStatus.AST_ERROR).addAllErrors(visitException(e));
    }
    
    TagProgram program = null;
    if(ast != null) {
      try {
        if(cachlessIds.contains(src.getId())) {
          program = new TagProgramBuilder(config).build(ast);          
        } else {
          final var cached = cache.getProgram(src);
          if(cached.isPresent()) {
            program = (TagProgram) cached.get();
          } else {
            program = new TagProgramBuilder(config).build(ast);
            cache.setProgram(program, src);
          }
        }
      } catch(Exception e) {
        LOGGER.error(new StringBuilder()
            .append(e.getMessage()).append(System.lineSeparator())
            .append("  - tag source: ").append(this.hdesFactory.commandsString(src.getCommands()))
            .toString(), e);
        builder.status(ProgramStatus.PROGRAM_ERROR).addAllErrors(visitException(e));
      }
    }
    
    return builder.id(src.getId()).type(AstBodyType.TAG)
        .ast(Optional.ofNullable(ast)).program(Optional.ofNullable(program))
        .source(src)
        .build(); 
  }
  
  
  private ProgramWrapper visitFlowTask(AstSource src) {
    final ImmutableProgramWrapper.Builder builder = ImmutableProgramWrapper.builder();
    builder.status(ProgramStatus.UP);
    AstService ast = null;
    try {      
      if(cachlessIds.contains(src.getId())) {
        ast = hdesTypes.service().src(src.getCommands()).build();
      } else {
        final var cached = cache.getAst(src);
        if(cached.isPresent()) {
          ast = (AstService) cached.get();
        } else {
          ast = hdesTypes.service().src(src.getCommands()).build();
          cache.setAst(ast, src);
        }
      }
      
      final var errors = ast.getMessages().stream()
          .filter(m -> m.getType() == CommandMessageType.ERROR)
          .map(error -> ImmutableProgramMessage.builder()
              .id("ast-error")
              .msg("line: " + error.getLine() + ": " + error.getValue())
              .build())
          .collect(Collectors.toList());
        builder.addAllErrors(errors);
      if(!errors.isEmpty()) {
        LOGGER.error(new StringBuilder()
            .append(String.join(System.lineSeparator(), errors.stream().map(e -> e.getMsg()).collect(Collectors.toList())))
            .append("  - service source: ").append(this.hdesFactory.commandsString(src.getCommands()))
            .toString());
        builder.status(ProgramStatus.AST_ERROR);
      }
    } catch(Exception e) {
      LOGGER.error(new StringBuilder()
          .append(e.getMessage()).append(System.lineSeparator())
          .append("  - service source: ").append(this.hdesFactory.commandsString(src.getCommands()))
          .toString(), e);
      builder.status(ProgramStatus.AST_ERROR).addAllErrors(visitException(e));
    }
    
    ServiceProgram program = null;
    if(ast != null) {
      try {
        if(cachlessIds.contains(src.getId())) {
          program = new ServiceProgramBuilder(config).build(ast);          
        } else {
          final var cached = cache.getProgram(src);
          if(cached.isPresent()) {
            program = (ServiceProgram) cached.get();
          } else {
            program = new ServiceProgramBuilder(config).build(ast);
            cache.setProgram(program, src);
          }
        }
      } catch(Exception e) {
        LOGGER.error(new StringBuilder()
            .append(e.getMessage()).append(System.lineSeparator())
            .append("  - service source: ").append(this.hdesFactory.commandsString(src.getCommands()))
            .toString(), e);
        builder.status(ProgramStatus.PROGRAM_ERROR).addAllErrors(visitException(e));
      }
    }
    
    return builder.id(src.getId()).type(AstBodyType.FLOW_TASK)
        .ast(Optional.ofNullable(ast)).program(Optional.ofNullable(program))
        .source(src)
        .build(); 
  }
  
  private List visitException(Exception e) {
    return Arrays.asList(ImmutableProgramMessage.builder()
          .id("exception")
          .msg(e.getMessage() == null ? "no-desc-available": e.getMessage().replaceAll("\"", "'"))
          .exception(e)
          .build()
        );
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy