private String compare(Node actual, Node expected) {
    List<Node> actualChildren =
        CorePlugin.getInstance()
            .getNodeService()
            .getChildren(actual, new ServiceContext<>(CorePlugin.getInstance().getNodeService()));
    List<Node> expectedChildren =
        CorePlugin.getInstance()
            .getNodeService()
            .getChildren(expected, new ServiceContext<>(CorePlugin.getInstance().getNodeService()));

    // check number of children
    if (actualChildren.size() != expectedChildren.size()) {
      return ResourcesPlugin.getInstance()
          .getMessage(
              "regex.test.compare.result.error.childrenCount", actual.getPropertyValue(NAME));
    }

    for (int i = 0; i < actualChildren.size(); i++) {
      Node actualChild = actualChildren.get(i);
      Node expectedChild = expectedChildren.get(i);
      // compare child properties
      String propertiesCompare = compareProperties(actualChild, expectedChild);
      if (propertiesCompare != null) {
        return propertiesCompare;
      }
      // recurse
      String childrenCompare = compare(actualChild, expectedChild);
      if (childrenCompare != null) {
        return childrenCompare;
      }
    }
    return null;
  }
  private Node createResourceRoot(Node technology, String resourceName, String testResourceUri) {
    NodeService nodeService = CorePlugin.getInstance().getNodeService();

    // create resource file
    ServiceContext<NodeService> context = new ServiceContext<NodeService>(nodeService);
    context.getContext().put(NAME, resourceName);
    context.getContext().put(CoreConstants.FILE_IS_DIRECTORY, false);
    context.getContext().put(CoreConstants.OVERWRITE_IF_NECESSARY, true);
    Node resourceNode = new Node(null, CoreConstants.FILE_NODE_TYPE);
    nodeService.addChild(technology, resourceNode, context);

    // subscribe to resource
    String matchUri = resourceNode.getNodeUri().replaceFirst(FILE_SCHEME, "fpp");
    new ResourceServiceRemote().subscribeToParentResource(matchUri);

    CorePlugin.getInstance()
        .getResourceSetService()
        .reload(matchUri, new ServiceContext<ResourceSetService>());
    Node root = CorePlugin.getInstance().getResourceService().getNode(matchUri);
    nodeService.setProperty(
        root, RESOURCE_URI, testResourceUri, new ServiceContext<NodeService>(nodeService));
    nodeService.setProperty(
        root, SHOW_GROUPED_BY_REGEX, false, new ServiceContext<NodeService>(nodeService));
    return root;
  }
  /**
   * @param nodeUri
   * @throws Exception
   * @author Elena Posea
   * @author Mariana Gheorghe
   */
  public void generateMatches(String nodeUri, boolean all) throws Exception {
    IFileAccessController fileController = FileControllerUtils.getFileAccessController();

    // get repo and technology from node
    VirtualNodeResourceHandler virtualNodeHandler =
        CorePlugin.getInstance().getVirtualNodeResourceHandler();
    String repo = Utils.getRepo(nodeUri);
    String[] typeSpecificPart =
        virtualNodeHandler.getTypeSpecificPartFromNodeUri(nodeUri).split("\\$");
    String technology = typeSpecificPart[0];
    String regexUri =
        FileControllerUtils.createFileNodeUri(
            repo, REGEX_CONFIGS_FOLDER + "/" + technology + "/" + REGEX_CONFIG_FILE);
    regexUri = regexUri.replaceFirst(CoreConstants.FILE_SCHEME, "fpp");

    // get regex configuration file
    new ResourceServiceRemote().subscribeToParentResource(regexUri);
    Node regex = CorePlugin.getInstance().getResourceService().getResourceNode(regexUri);

    // create regEx configuration
    RegexConfiguration regexConfig = new RegexConfiguration();
    new ConfigProcessor().processConfigHierarchy(regex, regexConfig);

    regexConfig.compile(Pattern.DOTALL);

    String technologyPath = REGEX_CONFIGS_FOLDER + "/" + technology;
    Node technologyNode =
        CorePlugin.getInstance()
            .getResourceService()
            .getNode(FileControllerUtils.createFileNodeUri(repo, technologyPath));
    if (all) {
      // parse files contained in the test files directory
      Object file = fileController.getFile(FileControllerUtils.getFilePathWithRepo(regex));
      Object parentFile = fileController.getParentFile(file);
      Object testFilesFolder = fileController.getFile(parentFile, REGEX_TEST_FILES_FOLDER);
      List<Object> testFiles = getTestFiles(testFilesFolder);
      for (Object testFile : testFiles) {
        String relativePath = fileController.getPathRelativeToFile(testFile, testFilesFolder);
        parseFile(technologyNode, testFile, relativePath, regex, regexConfig);
      }
    } else {
      // parse only selected file
      String relativePath = typeSpecificPart[1];
      Object testFile =
          fileController.getFile(
              repo + "/" + technologyPath + "/" + REGEX_TEST_FILES_FOLDER + "/" + relativePath);
      parseFile(technologyNode, testFile, relativePath, regex, regexConfig);
    }
  }
  private String compareForTestFile(String testFileUri, String actual, String expected) {
    String actualNodeUri = testFileUri.replaceFirst(REGEX_TEST_FILE_NODE_TYPE, actual);
    String expectedNodeUri = testFileUri.replaceFirst(REGEX_TEST_FILE_NODE_TYPE, expected);

    ResourceServiceRemote rsr = new ResourceServiceRemote();
    rsr.subscribeToParentResource(actualNodeUri);
    rsr.subscribeToParentResource(expectedNodeUri);

    Node actualNode = CorePlugin.getInstance().getResourceService().getNode(actualNodeUri);
    Node expectedNode = CorePlugin.getInstance().getResourceService().getNode(expectedNodeUri);
    String result = compare(actualNode, expectedNode);
    return result != null
        ? result
        : ResourcesPlugin.getInstance().getMessage("regex.test.compare.result.ok");
  }
  /**
   * @param nodeUri
   * @return compare results
   * @throws Exception
   * @author Elena Posea
   */
  public String testMatchesForAll(String nodeUri) {
    VirtualNodeResourceHandler virtualNodeHandler =
        CorePlugin.getInstance().getVirtualNodeResourceHandler();
    String technology = virtualNodeHandler.getTypeSpecificPartFromNodeUri(nodeUri);
    String repo = CoreUtils.getRepoFromNodeUri(nodeUri);
    String compareResult = "";

    String testFilesNodeUri =
        virtualNodeHandler.createVirtualNodeUri(repo, REGEX_TEST_FILES_NODE_TYPE, technology);
    Node testFilesNode = CorePlugin.getInstance().getResourceService().getNode(testFilesNodeUri);
    List<Node> testFilesNodeChildren =
        CorePlugin.getInstance()
            .getNodeService()
            .getChildren(
                testFilesNode, new ServiceContext<>(CorePlugin.getInstance().getNodeService()));

    for (Node testFileNode : testFilesNodeChildren) {
      compareResult += compareForTestFile(testFileNode);
    }
    return compareResult;
  }
  @SuppressWarnings({"unchecked", "rawtypes"})
  private void parseFile(
      Node technology,
      Object testFile,
      String testFilePath,
      Node regex,
      RegexConfiguration regexConfig)
      throws Exception {
    NodeService nodeService = CorePlugin.getInstance().getNodeService();
    IFileAccessController fileController = FileControllerUtils.getFileAccessController();

    // get test file node and test file resource uri
    Node testNode =
        CorePlugin.getInstance()
            .getResourceService()
            .getNode(
                FileControllerUtils.createFileNodeUri(
                    Utils.getRepo(technology.getNodeUri()), fileController.getPath(testFile)));
    List subscribableResources =
        (List) testNode.getPropertyValue(CoreConstants.SUBSCRIBABLE_RESOURCES);
    String testResourceUri = (String) ((Pair) subscribableResources.get(0)).a;

    // start session
    String testFileContent = IOUtils.toString((InputStream) fileController.getContent(testFile));
    RegexProcessingSession session = regexConfig.startSession(testFileContent);

    // prepare to collect model tree
    Node resultRoot =
        createResourceRoot(
            technology,
            String.format(REGEX_RESULT_FILES_FOLDER + "/%s.result", testFilePath),
            testResourceUri);
    ArrayList<Object> stateStack = new ArrayList<Object>();
    stateStack.add(0, new State(0, resultRoot));
    session.context.put(CodeSyncRegexConstants.STATE_STACK, stateStack);

    // prepare to collect match tree
    Node matchRoot =
        createResourceRoot(
            technology,
            String.format(REGEX_MATCH_FILES_FOLDER + "/%s.regexMatches", testFilePath),
            testResourceUri);
    session.find(new CodeSyncRegexMatcher(nodeService, session, testFileContent, matchRoot));

    // everything worked ok => save matches and result
    CorePlugin.getInstance()
        .getResourceService()
        .save(
            matchRoot.getNodeUri(),
            new ServiceContext<ResourceService>(CorePlugin.getInstance().getResourceService()));
    CorePlugin.getInstance()
        .getResourceService()
        .save(
            resultRoot.getNodeUri(),
            new ServiceContext<ResourceService>(CorePlugin.getInstance().getResourceService()));
  }
  /**
   * @param folder
   * @return a list of all files in that folder
   */
  public List<Object> getTestFiles(Object folder) {
    IFileAccessController controller = CorePlugin.getInstance().getFileAccessController();
    Object[] files = controller.listFiles(folder);
    if (files == null) {
      return Collections.emptyList();
    }

    List<Object> result = new ArrayList<Object>();
    for (Object file : files) {
      if (controller.isDirectory(file)) {
        // recurse for directories
        result.addAll(getTestFiles(file));
      } else {
        // keep child file
        result.add(file);
      }
    }
    return result;
  }
  private String compareProperties(Node actual, Node expected) {
    // check type
    if (!actual.getType().equals(expected.getType())) {
      return ResourcesPlugin.getInstance()
          .getMessage("regex.test.compare.result.eror.type", actual.getPropertyValue(NAME));
    }

    // check properties
    ServiceContext<NodeService> context =
        new ServiceContext<>(CorePlugin.getInstance().getNodeService());
    Map<String, Object> expectedProperties = expected.getOrPopulateProperties(context);
    Map<String, Object> actualProperties = actual.getOrPopulateProperties(context);

    // check properties size
    if (actualProperties.size() != expectedProperties.size()) {
      return ResourcesPlugin.getInstance()
          .getMessage(
              "regex.test.compare.result.error.propertiesCount", actual.getPropertyValue(NAME));
    }

    // iterate properties
    for (Entry<String, Object> entry : expectedProperties.entrySet()) {
      if (!actualProperties.containsKey(entry.getKey())) {
        return ResourcesPlugin.getInstance()
            .getMessage(
                "regex.test.compare.result.propertyNotFound",
                entry.getKey(),
                actual.getPropertyValue(NAME));
      }
      Object expectedPropertyValue = entry.getValue();
      Object actualPropertyValue = actualProperties.get(entry.getKey());
      if (!Utils.safeEquals(actualPropertyValue, expectedPropertyValue)) {
        return ResourcesPlugin.getInstance()
            .getMessage(
                "regex.test.compare.result.error.propertyValue",
                entry.getKey(),
                actual.getPropertyValue(NAME),
                expectedPropertyValue,
                actualPropertyValue);
      }
    }
    return null;
  }
 /**
  * @param nodeUri
  * @return compare results
  * @throws Exception
  * @author Elena Posea
  */
 public String testMatchesForSelection(String testFileUri) {
   return compareForTestFile(CorePlugin.getInstance().getResourceService().getNode(testFileUri));
 }