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

com.progress.xref.CrossReferenceUtils Maven / Gradle / Ivy

There is a newer version: 2.29.1
Show newest version
/********************************************************************************
 * Copyright (c) 2015-2024 Riverside Software
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the Eclipse
 * Public License, v. 2.0 are satisfied: GNU Lesser General Public License v3.0
 * which is available at https://www.gnu.org/licenses/lgpl-3.0.txt
 *
 * SPDX-License-Identifier: EPL-2.0 OR LGPL-3.0
 ********************************************************************************/
package com.progress.xref;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.sax.SAXSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;

import com.progress.xref.CrossReference.Source;
import com.progress.xref.CrossReference.Source.Reference;

public class CrossReferenceUtils {
  private static final Logger LOGGER = LoggerFactory.getLogger(CrossReferenceUtils.class);
  private static final SAXParserFactory SAX_PARSER_FACTORY;
  private static final JAXBContext CONTEXT;
  private static final Unmarshaller UNMARSHALLER;
  private static final CrossReference EMPTY_XREF = new EmptyCrossReference();

  static {
    SAX_PARSER_FACTORY = SAXParserFactory.newInstance();
    SAX_PARSER_FACTORY.setNamespaceAware(false);
    try {
      SAX_PARSER_FACTORY.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
      CONTEXT = JAXBContext.newInstance("com.progress.xref", CrossReference.class.getClassLoader());
      UNMARSHALLER = CONTEXT.createUnmarshaller();
    } catch (ParserConfigurationException | SAXNotRecognizedException | SAXNotSupportedException
        | JAXBException caught) {
      throw new IllegalStateException(caught);
    }
  }

  private CrossReferenceUtils() {
    // No-op
  }

  public static CrossReference parseXREF(File xref) {
    if (xref != null)
      LOGGER.debug("XREF file: {} - Found: {}", xref.getAbsolutePath(), xref.exists());
    else
      LOGGER.debug("Null XREF reference");
    return ((xref != null) && xref.exists()) ? parseXREF(xref.toPath()) : EMPTY_XREF;
  }

  public static CrossReference parseXREF(Path xref) {
    CrossReference doc = EMPTY_XREF;
    if ((xref != null) && Files.exists(xref)) {
      // Detect if file is plain text or XML
      boolean xml = false;
      String plainTextCodepage = null;
      try (InputStream inpStream = Files.newInputStream(xref)) {
        // Start with  Remove double quotes
    src.reference.add(ref);
  }

  private static void handleRunReference(Source src, Reference ref) {
    if (ref.objectIdentifier.endsWith(" PERSISTENT") //
        || ref.objectIdentifier.endsWith(" REMOTE") //
        || ref.objectIdentifier.endsWith(" SINGLE-RUN") //
        || ref.objectIdentifier.endsWith(" SINGLETON") //
        || ref.objectIdentifier.endsWith(" SUPER") //
        || ref.objectIdentifier.endsWith(" STORED-PROC")) {
      int pos = ref.objectIdentifier.lastIndexOf(' ');
      ref.objectContext = ref.objectIdentifier.substring(pos + 1);
      ref.objectIdentifier = ref.objectIdentifier.substring(0, pos);
    }
    src.reference.add(ref);
  }

  private static void handleSortAccessReference(Source src, Reference ref) {
    if (ref.objectIdentifier.endsWith(" WORKFILE") || ref.objectIdentifier.endsWith(" TEMPTABLE")) {
      int pos = ref.objectIdentifier.lastIndexOf(' ');
      ref.tempRef = "T";
      ref.objectIdentifier = ref.objectIdentifier.substring(0, pos);
    }
    int pos = ref.objectIdentifier.lastIndexOf(' ');
    ref.objectContext = ref.objectIdentifier.substring(pos + 1);
    ref.objectIdentifier = ref.objectIdentifier.substring(0, pos);
    src.reference.add(ref);
  }

  private static void handleSearchReference(Source src, Reference ref) {
    String part1 = ref.objectIdentifier.substring(0, ref.objectIdentifier.indexOf(' '));
    if ("DATA-MEMBER".equalsIgnoreCase(part1) || "INHERITED-DATA-MEMBER".equalsIgnoreCase(part1)
        || (part1.indexOf(':') != -1)) {
      ref.objectIdentifier = ref.objectIdentifier.substring(ref.objectIdentifier.indexOf(':') + 1);
    }
    if (ref.objectIdentifier.endsWith("WORKFILE")) {
      ref.tempRef = "T";
      ref.objectIdentifier = part1;
    } else {
      if (ref.objectIdentifier.endsWith(" WHOLE-INDEX") || ref.objectIdentifier.endsWith(" TABLE-SCAN")) {
        int pos = ref.objectIdentifier.lastIndexOf(' ');
        ref.detail = ref.objectIdentifier.substring(pos + 1);
        ref.objectIdentifier = ref.objectIdentifier.substring(0, pos);
      }
      if (ref.objectIdentifier.endsWith(" TEMPTABLE")) {
        int pos = ref.objectIdentifier.lastIndexOf(' ');
        ref.tempRef = "T";
        ref.objectIdentifier = ref.objectIdentifier.substring(0, pos);
      }
      int pos = ref.objectIdentifier.lastIndexOf(' ');
      ref.objectContext = ref.objectIdentifier.substring(pos + 1);
      ref.objectIdentifier = ref.objectIdentifier.substring(0, pos);
    }
    src.reference.add(ref);
  }

  private static void handleInvokeReference(Source src, Reference ref) {
    int pos = ref.objectIdentifier.indexOf(',');
    ref.objectIdentifier = pos == -1 ? ref.objectIdentifier : ref.objectIdentifier.substring(0, pos);
    src.reference.add(ref);
  }

  private static void handleNewSharedReference(Source src, Reference ref) {
    int pos = ref.objectIdentifier.indexOf(',');
    ref.objectIdentifier = pos == -1 ? ref.objectIdentifier : ref.objectIdentifier.substring(0, pos);
    src.reference.add(ref);
  }

  private static CrossReference parsePlainTextXref(String fName, InputStream input, Charset charset) throws IOException {
    CrossReference doc = new CrossReference();
    doc.source = new ArrayList<>();

    Map sources = new HashMap<>();
    try (InputStream inpStream = new InvalidXMLFilterStream(input);
        InputStreamReader reader = new InputStreamReader(inpStream, charset);
        BufferedReader reader2 = new BufferedReader(reader)) {
      Source currSrc = null;
      String currSrcStr = null;
      String ln = null;
      int lineNum = 0;
      final AtomicInteger fileNum = new AtomicInteger(1);
      final AtomicInteger seqNum = new AtomicInteger(1);
      while ((ln = reader2.readLine()) != null) {
        lineNum++;
        try {
          String[] line = parseLine(ln);
          if ((currSrc == null) || (currSrcStr == null) || !currSrcStr.equals(line[1])) {
            currSrcStr = line[1];
            currSrc = sources.computeIfAbsent(line[1], key -> {
              Source src = new Source();
              src.fileNum = fileNum.getAndIncrement();
              src.fileName = key;
              src.reference = new ArrayList<>();
              doc.source.add(src);
              return src;
            });
          }
  
          Reference ref = new Reference();
          ref.referenceType = line[3];
          ref.fileNum = currSrc.fileNum;
          ref.refSeq = seqNum.getAndIncrement();
          // Line-number can be 'IMPLICIT' or 'NONE'
          ref.lineNum = !Character.isDigit(line[2].charAt(0)) ? 0 : Integer.parseInt(line[2]);
          ref.objectIdentifier = (line[4].length() > 2) && (line[4].charAt(0) == '"')
              && (line[4].charAt(line[4].length() - 1) == '"') ? line[4].substring(1, line[4].length() - 1) : line[4];
  
          switch (line[3]) {
            case "INCLUDE":
              handleIncludeReference(currSrc, ref);
              break;
            case "RUN":
              handleRunReference(currSrc, ref);
              break;
            case "SORT-ACCESS":
              handleSortAccessReference(currSrc, ref);
              break;
            case "SEARCH":
              handleSearchReference(currSrc, ref);
              break;
            case "INVOKE":
            case "NEW":
              handleInvokeReference(currSrc, ref);
              break;
            case "NEW-SHR-TEMPTABLE":
            case "NEW-SHR-DATASET":
            case "NEW-SHR-VARIABLE":
              handleNewSharedReference(currSrc, ref);
              break;
          }
        } catch (Exception caught) {
          LOGGER.debug("File '{}' - Unable to parse XREF line {}: '{}' -- Msg: {}", fName, lineNum, ln,
              caught.getMessage());
        }
      }
    }

    return doc;
  }

  private static String[] parseLine(String line) {
    String[] retVal = {"", "", "", "", ""};
    int currPos = 0;
    if (line.charAt(currPos) == '"') {
      int endIndex = line.indexOf('"', 1);
      retVal[0] = line.substring(1, endIndex);
      currPos = endIndex + 2;
    } else {
      int endIndex = line.indexOf(' ', 1);
      retVal[0] = line.substring(0, endIndex);
      currPos = endIndex + 1;
    }

    if (line.charAt(currPos) == '"') {
      int endIndex = line.indexOf('"', currPos + 1);
      retVal[1] = line.substring(currPos + 1, endIndex);
      currPos = endIndex + 2;
    } else {
      int endIndex = line.indexOf(' ', currPos + 1);
      retVal[1] = line.substring(currPos, endIndex);
      currPos = endIndex + 1;
    }

    retVal[2] = line.substring(currPos, line.indexOf(' ', currPos));
    currPos = line.indexOf(' ', currPos) + 1;
    retVal[3] = line.substring(currPos, line.indexOf(' ', currPos));
    currPos = line.indexOf(' ', currPos) + 1;
    retVal[4] = line.substring(currPos);

    return retVal;
  }

  /**
   * Return charset to be used when writing files in Java to be read by Progress session (thus according to cpstream,
   * parameter files, ...) and dealing with OE encodings (such as undefined or 1252). Imported from PCT
   */
  private static Charset getCharset(String charset) {
    if (charset == null) {
      return StandardCharsets.UTF_8;
    }

    try {
      if ("1250".equals(charset))
        return Charset.forName("windows-1250");
      else if ("1251".equals(charset))
        return Charset.forName("windows-1251");
      else if ("1252".equals(charset))
        return Charset.forName("windows-1252");
      else if ("1253".equals(charset))
        return Charset.forName("windows-1253");
      else if ("1254".equals(charset))
        return Charset.forName("windows-1254");
      else if ("1255".equals(charset))
        return Charset.forName("windows-1255");
      else if ("1256".equals(charset))
        return Charset.forName("windows-1256");
      else if ("1257".equals(charset))
        return Charset.forName("windows-1257");
      else if ("1258".equals(charset))
        return Charset.forName("windows-1258");
      else if ("big-5".equalsIgnoreCase(charset))
        return Charset.forName("Big5");
      else
        return Charset.forName(charset);
    } catch (IllegalArgumentException caught) {
      return StandardCharsets.UTF_8;
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy