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

com.meluzin.tibcobwutils.earcomparer.FullConfigChecker Maven / Gradle / Ivy

package com.meluzin.tibcobwutils.earcomparer;

import java.io.IOException;
import java.io.StringReader;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.xml.sax.SAXException;

import com.meluzin.fluentxml.xml.builder.NodeBuilder;
import com.meluzin.fluentxml.xml.builder.XmlBuilderFactory;
import com.meluzin.functional.FileSearcher;
import com.meluzin.functional.Lists;
import com.meluzin.functional.T;
import com.meluzin.functional.T.V2;
import com.meluzin.tibcobwutils.deploymentrepository.analyzer.FullConfigAnalyzer;
import com.meluzin.tibcobwutils.deploymentrepository.structure.GlobalVariable;
import com.meluzin.tibcobwutils.deploymentrepository.structure.GlobalVariables;
import com.meluzin.tibcobwutils.deploymentrepository.structure.ItemType;
import com.meluzin.tibcobwutils.deploymentrepository.structure.Repository;
import com.meluzin.tibcobwutils.deploymentrepository.structure.impl.ConfigImpl;
import com.meluzin.tibcobwutils.deploymentrepository.structure.impl.RepositoryImpl;
import com.meluzin.tibcobwutils.earcomparer.fullconfig.model.SDKPropertiesLoader;

import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.inf.ArgumentParser;
import net.sourceforge.argparse4j.inf.Namespace;

public class FullConfigChecker {
	private static final String INSTANCE_RUNTIME_VARIABLES = "INSTANCE_RUNTIME_VARIABLES";
	private static final String RUNTIME_VARIABLES = "Runtime Variables";
	
	public static void main(String[] args) {
		ArgumentParser argParser = ArgumentParsers.newArgumentParser("Full config checker", true, "-")
				.description("Checks full config global variables against tibco bw code.");
		argParser.addArgument("-prefs").type(String.class).required(true).help("Path to .TIBCO prefs file. Ex: C:\\Users\\Jirka\\.TIBCO\\Designer5.prefs.R170903");
		argParser.addArgument("-source").type(String.class).required(true).help("Path to directory with code. Ex: T:\\source\\R170903 or T:\\source\\R170903\\CRM");
		argParser.addArgument("-export").type(String.class).required(true).help("Path to directory with exported full configs. Ex: T:\\temp\\compare\\_deployed");
		argParser.addArgument("-config").type(String.class).required(true).help("Path to directory with full configs. Ex: T:\\source\\R170903\\_config");
		argParser.addArgument("-tibcohome").type(String.class).required(false).help("Path to tibco home. Ex: T:/tib/app/tibco");
		
		Namespace res = argParser.parseArgsOrFail(args);
		try {
			Path prefFilePath = Paths.get((String)res.get("prefs"));
			Path sourcePath = Paths.get((String)res.get("source"));
			Path configPath = Paths.get((String)res.get("config"));
			Path exportPath = Paths.get((String)res.get("export"));
			Path branchPath = sourcePath;
			Path tibcoHome = Paths.get(res.getString("tibcohome") == null ? "t:/tib/app/tibco" : res.getString("tibcohome"));
			SDKPropertiesLoader sdkLoader = new SDKPropertiesLoader(tibcoHome);
			Path deploymentListPath = configPath.resolve("deploymentList.xml");
			NodeBuilder deploymentList = new XmlBuilderFactory().loadFromFile(deploymentListPath);
			new FileSearcher().searchFiles(branchPath, "glob:**/vcrepo.dat", true).stream().
				parallel().
				map(p -> checkVariables(sdkLoader, p.getParent(), prefFilePath, branchPath, configPath, exportPath, deploymentList)).
				flatMap(s -> s).
				forEach(s -> System.err.println(s));
				
				; 
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}

	}

	private static Stream checkVariables(SDKPropertiesLoader loader, Path projectPath, Path prefFilePath, Path branchPath, Path configPath, Path exportPath, NodeBuilder deploymentList) {
		List messages = new ArrayList<>();
		Repository r = new RepositoryImpl(projectPath, new ConfigImpl(prefFilePath));
		NormalizeConfig normalizeConfig = new NormalizeConfig(loader);

		r.findAll(i -> i.getItemType() == ItemType.Archive).forEach(archive -> {
			NodeBuilder archiveXML = archive.loadAsXml();
			NodeBuilder archiveNameElement = archiveXML.searchFirst(true, n -> "name".equals(n.getName()));
			String archiveName = archiveNameElement == null ?  archive.getName().replace(ItemType.Archive.getExtension(), "") : archiveNameElement.getTextContent();
			
			deploymentList.search(n -> projectPath.getFileName().toString().equals(n.getAttribute("project")) && archiveName.equals(n.getAttribute("name"))).forEach(deployment -> {
				deployment.search(true, en -> "environment".equals(en.getName())).forEach(env -> {
					Path fullConfigsPath = configPath.resolve(env.getAttribute("domain"));
					Path fullConfigPath = fullConfigsPath.resolve(archiveName + ".xml");
					Path fullConfigsExportPath = exportPath.resolve(env.getAttribute("domain"));
					Path fullConfigExportPath = fullConfigsExportPath.resolve(archiveName + ".xml");
					
					if (!fullConfigPath.toFile().exists()) {
						messages.add(fullConfigPath + " does not exists! " + projectPath);				
					} else {
						NodeBuilder fullConfig = normalizeConfig.removeRedundants(new XmlBuilderFactory().loadFromFile(fullConfigPath));
						Optional validationResult = validateFullConfig(fullConfig);
						if (validationResult.isPresent()) {
							messages.add(r.getDeployment().getName() + "\t" + archiveName + "\t" + env.getAttribute("domain") + "\t"+ "fullconfig XML validation error" + "\t" + validationResult.get());									
						}
						List validateFullConfigSemantic = validateFullConfigSemanticDuplicatedServiceNVPairs(fullConfig);
						validateFullConfigSemantic.forEach(v -> {
							messages.add(r.getDeployment().getName() + "\t" + archiveName + "\t" + env.getAttribute("domain") + "\t"+ "fullconfig contains duplicate service NVPairs" + "\t" + v);									
							
						});
						List validateFullConfigSemanticInstance = validateFullConfigSemanticDuplicatedServiceInstanceNVPairs(fullConfig);
						validateFullConfigSemanticInstance.forEach(v -> {
							messages.add(r.getDeployment().getName() + "\t" + archiveName + "\t" + env.getAttribute("domain") + "\t"+ "fullconfig contains duplicate service NVPairs" + "\t" + v);									
							
						});
						Optional fullConfigExport = fullConfigExportPath.toFile().exists() ? Optional.of(normalizeConfig.removeRedundants(new XmlBuilderFactory().loadFromFile(fullConfigExportPath))) : Optional.empty();
//						System.out.println(archive.getDeploymentReference());
						GlobalVariables rootGlobalVariables = r.getRootGlobalVariables();
						Set starters = new FullConfigAnalyzer(r).findBWProcessStarters(archive);
						synchronized (FullConfigChecker.class) {
							//fullConfig.search(true, n -> "NVPairs".equals(n.getName())).forEach(n -> System.out.println(n.getAttribute("name") + "\t" + n.getXPath()));
							//fullConfigExport.search(true, n -> "NVPairs".equals(n.getName())).forEach(n -> System.out.println(n.getAttribute("name") + "\t" + n.getXPath()));

							fullConfig.searchFirstByName("NVPairs").search(true, "name").
								map(n -> n.getTextContent()).
								collect(Collectors.groupingBy(Function.identity())).values().stream().
								filter(l -> l.size() > 1).
								forEach(x -> {
									messages.add(r.getDeployment().getName() + "\t" + archiveName + "\t" + env.getAttribute("domain") + "\t"+ "duplicate global variable in fullconfig" + "\t" + x.get(0));									
								});
							
							checkVariables(fullConfig, rootGlobalVariables, r, env.getAttribute("domain"), archiveName, messages);
							fullConfig.searchFirstByName("NVPairs").search(true, n -> "name".equals(n.getName())).forEach(checkAvailableDeploymentSettableVariables(r, archiveName, env, rootGlobalVariables, messages));	
							
							//System.out.println(archive.getDeploymentReference());
							checkServiceVariables(fullConfig, fullConfigExport, rootGlobalVariables, r, env.getAttribute("domain"), archiveName, messages);
							NodeBuilder bw = fullConfig.searchFirst(true, n -> "bw".equals(n.getName()));
							if (bw != null) {
								bw.search(true, n -> "NVPairs".equals(n.getName()) &&  RUNTIME_VARIABLES.equals(n.getAttribute("name"))).forEach(nvPairs -> {
									nvPairs.search(true, n -> "name".equals(n.getName())).forEach(checkAvailableServiceSettableVariables(r, archiveName, env, rootGlobalVariables, messages));
								});
							}
						/*NodeBuilder processesProperty = archiveXML.searchFirstByName(true, "processProperty");
						if (processesProperty != null) {
							String[] processes = processesProperty.getTextContent().split(",");
							List processesList = Arrays.asList(processes).stream().map(p -> p.charAt(0) == '/' ? p.substring(1) : p).collect(Collectors.toList());*/
							starters.stream().
								//map(p -> p.charAt(0) == '/' ? p.substring(1) : p).
								filter(p -> !fullConfig.hasChild(true, n -> "bwprocess".equals(n.getName()) && p.equals(n.getAttribute("name")))).
								map(p -> r.findItem(p).get()).
								filter(i -> i.getItemType() != ItemType.Process || i.loadAsXml().searchFirstByName("starter") != null).
								forEach(p -> {
									messages.add(r.getDeployment().getName() + "\t" + archiveName + "\t" + env.getAttribute("domain") + "\t"+ "missing bwprocess config in fullconfig" + "\t" + p.getDeploymentReference().replace("\\", "/").substring(1));
								});

							fullConfig.search(true, "bwprocess").
								map(n -> n.getAttribute("name")).
								map(p -> p.charAt(0) == '/' ? p.substring(1) : p).
								collect(Collectors.groupingBy(Function.identity())).values().stream().
								filter(l -> l.size() > 1).
								forEach(x -> {
									messages.add(r.getDeployment().getName() + "\t" + archiveName + "\t" + env.getAttribute("domain") + "\t"+ "duplicate bwprocess config in fullconfig" + "\t" + x.get(0));									
								});

							fullConfig.search(true, "bwprocess").
								map(n -> n.getAttribute("name")).
								map(p -> p.charAt(0) == '/' ? p.substring(1) : p).
								filter(p -> !starters.contains(p)).
								forEach(x -> {
									//System.out.println(processesList);
									messages.add(r.getDeployment().getName() + "\t" + archiveName + "\t" + env.getAttribute("domain") + "\t"+ "bwprocess config should be removed from fullconfig" + "\t" + x);									
								});
							
							starters.stream().
								//map(p -> p.charAt(0) == '/' ? p.substring(1) : p).
								map(p -> T.V(p, fullConfig.search(true, n -> "bwprocess".equals(n.getName()) && p.equals(n.getAttribute("name"))).findAny())).
								filter(v -> v.getB().isPresent()).
								forEach(p -> {
									checkMaxJob(r, archiveName, env, p, "maxJob", messages);
									checkMaxJob(r, archiveName, env, p, "flowLimit", messages);
								});
						}
						//}
					}		
				});

			});
			
		});
		return messages.stream().sorted();
	}

	private static Optional validateFullConfig(NodeBuilder fullConfig) {

		SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
		URL resource = FullConfigChecker.class.getResource("/ApplicationManagement.xsd");
		try {
			Schema schema = schemaFactory.newSchema(resource);
			Validator  validator = schema.newValidator();
			validator.validate(new StreamSource(new StringReader(fullConfig.toString())));			
			return Optional.empty();
		} catch (SAXException | IOException e) {
			return Optional.of(e.toString());
		}
	}

	private static List validateFullConfigSemanticDuplicatedServiceNVPairs(NodeBuilder fullConfig) {
		return fullConfig.search("services").map(n -> n.getChildren().stream()).flatMap(s -> s).filter(n -> n.search("NVPairs").filter(nn ->  RUNTIME_VARIABLES.contains(nn.getAttribute("name"))).count() > 1).map(n -> n.getXPath()).collect(Collectors.toList());
	}
	private static List validateFullConfigSemanticDuplicatedServiceInstanceNVPairs(NodeBuilder fullConfig) {
		return fullConfig.search(true, "binding").filter(n -> n.search("NVPairs").filter(nn ->  RUNTIME_VARIABLES.contains(nn.getAttribute("name"))).count() > 1).map(n -> n.getXPath()).collect(Collectors.toList());
	}

	private static void checkMaxJob(Repository r, String archiveName, NodeBuilder env,
			V2> p, String property, List messages) {
		NodeBuilder maxJob = p.getB().get().searchFirstByName(property);
		if (maxJob == null || maxJob.getTextContent() == null) {
			messages.add(r.getDeployment().getName() + "\t" + archiveName + "\t" + env.getAttribute("domain") + "\t"+ "missing or missing value of "+property+" in bwprocess config in fullconfig" + "\t" + p.getA());										
		} else {
			Optional tryParse = tryParse(maxJob.getTextContent());
			if (!tryParse.isPresent()) {		
				messages.add(r.getDeployment().getName() + "\t" + archiveName + "\t" + env.getAttribute("domain") + "\t"+ property + " in bwprocess config in fullconfig is not a number (" + maxJob.getTextContent() + ")" + "\t" + p.getA());										
			} else if (tryParse.get() < 0) {
				messages.add(r.getDeployment().getName() + "\t" + archiveName + "\t" + env.getAttribute("domain") + "\t"+ property + " in bwprocess config in fullconfig is not a non-negative number (" + maxJob.getTextContent() + ")" + "\t" + p.getA());				
			}
		}
	}
	
	private static Optional tryParse(String num) {
		  try {
			  return Optional.of(Integer.parseInt(num));
		  } catch (NumberFormatException nfe) {
			  return Optional.empty();
		  }
	}

	private static Consumer checkAvailableDeploymentSettableVariables(Repository r, String archiveName,
			NodeBuilder env, GlobalVariables rootGlobalVariables, List messages) {
		return n -> {
			Optional x = rootGlobalVariables.resolve(n.getTextContent());
			if (!x.isPresent() || !x.get().isDeploymentSettable()) {
				messages.add(r.getDeployment().getName() + "\t" + archiveName + "\t" + env.getAttribute("domain") + "\t" + "global variable should be removed from fullconfig" + "\t" + n.getTextContent() + "\t" + n.getXPath());								
			}
		};
	}
	private static Consumer checkAvailableServiceSettableVariables(Repository r, String archiveName,
			NodeBuilder env, GlobalVariables rootGlobalVariables, List messages) {
		return n -> {
			Optional x = rootGlobalVariables.resolve(n.getTextContent());
			if (!x.isPresent() || !x.get().isServiceSettable()) {
				messages.add(r.getDeployment().getName() + "\t" + archiveName + "\t" + env.getAttribute("domain") + "\t" + "service variable should be removed from fullconfig" + "\t" + n.getTextContent() + "\t" + n.getXPath());								
			}
		};
	}

	private static void checkVariables(NodeBuilder fullConfig, GlobalVariables rootGlobalVariables, Repository repo, String env, String archiveName, List messages) {
		rootGlobalVariables.getAllVariables().entrySet().stream().filter(v -> v.getValue().size() > 0)
				.filter(v -> v.getValue().get(0).isDeploymentSettable()).forEach(e -> {
					String key = parseKey(rootGlobalVariables, e.getKey());
					/*boolean hasVariable = */
					Optional xmlVariable = fullConfig
							.searchFirst(true, c -> "NVPairs".equals(c.getName()) && "Global Variables".equals(c.getAttribute("name")))
							.search(true, "name").filter(name -> key.equals(name.getTextContent())).findFirst();
					if (!xmlVariable.isPresent() && !Lists.asList("Deployment", "Domain").contains(key))
						messages.add(repo.getDeployment().getName() + "\t" + archiveName + "\t" + env + "\t" + "missing global variable in fullconfig" + "\t" + key);
					if (xmlVariable.isPresent()) {
						GlobalVariable childVariable = getChildVariable(rootGlobalVariables, e.getKey());
						String name = xmlVariable.get().getParent().getName();
						String xmlVariableType = name.replace("NameValuePair", "");
						if ("".equals(xmlVariableType)) {
							xmlVariableType = "String";
						}
						if (!xmlVariableType.equals(childVariable.getType())) {
							messages.add(repo.getDeployment().getName() + "\t" + archiveName + "\t" + env + "\t" + "variable has wrong type (fullconfig contains " +xmlVariableType + " but " + childVariable.getType() + " is defined in deployment)"+ "\t" + key);
						}

					}

				});
		rootGlobalVariables.getChildVariables().forEach(c -> checkVariables(fullConfig, c, repo, env, archiveName, messages));
	}
	private static void checkServiceVariables(NodeBuilder fullConfig, Optional fullConfigExport, GlobalVariables rootGlobalVariables, Repository repo, String env, String archiveName, List messages) {
		rootGlobalVariables.getAllVariables().entrySet().stream().filter(v -> v.getValue().size() > 0)
				.filter(v -> v.getValue().get(0).isServiceSettable()).forEach(e -> {
					String key = parseKey(rootGlobalVariables, e.getKey());
					fullConfig.search(true, n -> (n.hasParent() && "services".equals(n.getParent().getName())) || "binding".equals(n.getName())).forEach(parent -> {
						NodeBuilder nvPairs = parent.searchFirst(c -> "NVPairs".equals(c.getName()) && Lists.asList(RUNTIME_VARIABLES,INSTANCE_RUNTIME_VARIABLES).contains(c.getAttribute("name")));
						if (nvPairs != null) {
							boolean hasVariable = nvPairs != null && nvPairs.hasChild(c -> c.hasChild(name -> "name".equals(name.getName()) && key.equals(name.getTextContent())));
							if (!hasVariable && !Lists.asList("Deployment", "Domain").contains(key)) {
								if (fullConfigExport.isPresent()) {
									if ("services".equals(parent.getParent().getName())) {
										Optional serviceVariableFullConEx = fullConfigExport.get().search(true, "bw").map(n -> n.search("NVPairs")).flatMap(n -> n).map(n -> n.search(true, c -> "name".equals(c.getName()) && key.equals(c.getTextContent()))).flatMap(c -> c).findAny();
										if (serviceVariableFullConEx.isPresent()) {
											messages.add(repo.getDeployment().getName() + "\t" + archiveName + "\t" + env + "\t" + "missing service variable in fullconfig which is defined in exported fullconfig" + "\t" + key + "\t" + serviceVariableFullConEx.get().getXPath() + " exported value is: " + serviceVariableFullConEx.get().getParent().searchFirstByName("value").getTextContent());
										}
									} else if ("binding".equals(parent.getName())) {
										String bindingMachineName = nvPairs.getParent().getAttribute("name");
										Optional serviceInstanceVariableFullConEx = fullConfigExport.get().search(true, "binding").filter(binding -> bindingMachineName.equals(binding.getAttribute("name"))).map(n -> n.search("NVPairs")).flatMap(n -> n).map(n -> n.search(true, c -> "name".equals(c.getName()) && key.equals(c.getTextContent()))).flatMap(c -> c).findAny();
										if (serviceInstanceVariableFullConEx.isPresent()) {
											messages.add(repo.getDeployment().getName() + "\t" + archiveName + "\t" + env + "\t" + "missing service instance variable in fullconfig which is defined in exported fullconfig" + "\t" + key + "\t" + bindingMachineName + "\t" + serviceInstanceVariableFullConEx.get().getXPath() + " exported value is: " + serviceInstanceVariableFullConEx.get().getParent().searchFirstByName("value").getTextContent());
										}
									} 
								} else {
									if ("services".equals(parent.getParent().getName())) {
										messages.add(repo.getDeployment().getName() + "\t" + archiveName + "\t" + env + "\t" + "missing service variable in fullconfig" + "\t" + key + "\t" + nvPairs.getXPath());
									} else if ("binding".equals(parent.getName())) {
										String bindingMachineName = nvPairs.getParent().getAttribute("name");
										messages.add(repo.getDeployment().getName() + "\t" + archiveName + "\t" + env + "\t" + "missing service instance variable in fullconfig" + "\t" + key + "\t" + bindingMachineName + "\t" + nvPairs.getXPath());								
									}									
								}
								//messages.add(repo.getDeployment().getName() + "\t" + archiveName + "\t" + env + "\t" + "missing service variable" + "\t" + key + "\t" + parent.getXPath());
							}
						} else {
							if ("services".equals(parent.getParent().getName())) {
								messages.add(repo.getDeployment().getName() + "\t" + archiveName + "\t" + env + "\t" + "missing service variable in fullconfig, whole NVPairs with name = ("+RUNTIME_VARIABLES+") element missing" + "\t" + key + "\t" + parent.getXPath());
							} else if ("binding".equals(parent.getName())) {
								String bindingMachineName = parent.getAttribute("name");
								messages.add(repo.getDeployment().getName() + "\t" + archiveName + "\t" + env + "\t" + "missing service instance variable in fullconfig, whole NVPairs with name = ("+ RUNTIME_VARIABLES + " or " + INSTANCE_RUNTIME_VARIABLES +") element missing" + "\t" + key + "\t" + bindingMachineName + "\t" + parent.getXPath());								
							}
						}
					});

				});
		rootGlobalVariables.getChildVariables().forEach(c -> checkServiceVariables(fullConfig, fullConfigExport, c, repo, env, archiveName, messages));
	}

	private static String parseKey(GlobalVariables parentGlobalVariables, String childVariableName) {
		return getChildVariable(parentGlobalVariables, childVariableName).getPath();
	}

	public static GlobalVariable getChildVariable(GlobalVariables parentGlobalVariables, String childVariableName) {
		return parentGlobalVariables.resolve(childVariableName).get();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy