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

ee.jakarta.tck.jsonp.signaturetest.PackageList Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 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 General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

/*
 * $Id$
 */

package ee.jakarta.tck.jsonp.signaturetest;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Logger;


/**
 * This class represents a package list file. A package list file is used in
 * conjunction with a set of signature files to execute API signature tests.
 * Users specify which set of package APIs are verified. Each package's
 * signature is verified independently. As such all valid sub-packages must be
 * excluded while a package's signature is being verified. This allows API check
 * to determine incompatible additional packages included in a distribution.
 * 

* This class builds a package list file when signatures are recorded and * provides an API to provide valid sub-package lists when signatures are played * back (verified). *

* In record mode, this class reads the existing package list file, if one * exists, and removes the package (as well as sub-packages) that are currently * being recorded. All package names read from the existing package list file * are held in a tree set which sorts the package names and keeps duplicate * package names from ocurring. The user can then instruct this class to write * out the package list file. At this point this class reads the currently * recorded signature file and extracts each package names and adds it to the * tree set. After this step the previous package list file is saved as a backup * and the new package list file is written to disk. *

* In playback mode, this class reads the contents of the package list file and * stores each package name in a tree set. Users can then invoke the * getSubPackages method to retrieve the valid sub-packages for any given * package. This is done by simply examining the package names in the tree set * and returning any package name that starts with the parent package name and a * trailing period character. */ class PackageList { private static final Logger LOGGER = Logger.getLogger(PackageList.class.getName()); // Any line in the packageFile starting with this character is a comment private static final char COMMENT_CHAR = '#'; private static final String BACKUP_EXT = ".bak"; // File containing the list of packages and sub-packages private File packageFile; // Signature file where the package signatures were recorded private File sigFile; // Name of the package being recorded private String additionalPackageName; // Name of packages and sub-packages in the private Set packageNames = new TreeSet(); /** * Creates an instance of the PackageList class. The PackageList instance * reads the specified package file and populates it's internal state with the * package names found in this file. Users should use this c'tor when playing * back signature files. Users can init the PackageList instance then use the * "String[] getSubPackages(String packageName)" method to get the list of * valid sub-packages for every package who's signature is being verified. * * @param packageFileName * The name of the file that contains the package list. This file * contains the names of all the packages that exist across all the * signature files that makeup this deliverable. This file is used to * generate a list of valid sub-packages that must be exclued when * testing theor parent package's signature. * * @throws Exception * when the packageFileName does not exist. */ public PackageList(String packageFileName) throws Exception { packageFile = new File(packageFileName); if (packageFile.exists() && packageFile.isFile()) { extractExistingPackageNames(); } else { throw new FileNotFoundException(packageFileName); } } /** * Creates an instance of the PackageList class. The PackageList instance * reads the contents of the packageFileName and stores it in it's internal * state. Next, any packages whos name starts with the specified packageName * are removed from the internal package list. This is done because this is * the package being recorded and we need to remove any previously recorded * package names in case any sub-packages have been removed since the last * time the signatures were recorded. Users should use this c'tor when they * are recording signature files never during playback. * * @param packageName * The name of the package whos signatures are being recorded (along * with sub-packages). * @param sigFileName * The name of the file that contains the recored signatures. * @param packageFileName * The name of the file that contains the package list. This file * contains the names of all the packages that exist across all the * signature files that makeup this deliverable. This file is used to * generate a list of valid sub-packages that must be exclued when * testing their parent package's signature. * * @throws Exception * when an error occurs reading the packageFileName or the * sigFileName does not exist. */ public PackageList(String packageName, String sigFileName, String packageFileName) throws Exception { this.additionalPackageName = packageName; sigFile = new File(sigFileName); if (!sigFile.exists() || !sigFile.isFile()) { throw new FileNotFoundException(sigFileName); } packageFile = new File(packageFileName); if (packageFile.exists() && packageFile.isFile()) { extractExistingPackageNames(); removeExistingPackage(); } } /** * Read the package names stored in the package list file. Each package name * found in the package list file is added to the internal tree set. * * @throws Exception * if there is an error opening or reading the package list file. */ private void extractExistingPackageNames() throws Exception { BufferedReader in = new BufferedReader(new FileReader(packageFile)); String line; String trimLine; try { while ((line = in.readLine()) != null) { trimLine = line.trim(); if (isComment(trimLine) || "".equals(trimLine)) { continue; } packageNames.add(trimLine); } } finally { try { in.close(); } catch (Exception e) { } } } /** * Returns true if the specified string starts with a comment character as * denoted by the COMMENT_CHAR constant. * * @param line * Determins of this line is a comment line * * @return boolean True if the specified line is a comment line else false. */ private boolean isComment(String line) { if (line == null) { return false; } String theLine = line.trim(); if (theLine.length() > 0) { return (theLine.charAt(0) == COMMENT_CHAR); } return false; } /** * Removes package names from the package list file. The packages that are * removed are the ones currently being recorded. The packages being recorded * is denoted by this.additionalPackageName. This includes any sub-packages of * the additionalPackageName. This step is necessary in the cases where a * sub-package has been removed from a parent package in between signature * recordings. */ private void removeExistingPackage() { String delPackage = this.additionalPackageName; String packageName; List delPkgs = new ArrayList(); // iterate over package set and find package names to remove for (Iterator i = packageNames.iterator(); i.hasNext();) { packageName = (String) i.next(); if (packageName.startsWith(delPackage)) { delPkgs.add(packageName); } } // actually remove the package names from the set for (int i = 0; i < delPkgs.size(); i++) { packageName = (String) (delPkgs.get(i)); packageNames.remove(packageName); LOGGER.info( "PackageList.removeExistingPackage() \"" + packageName + "\""); } } /** * Write the package list out to the package list file. This is done by * reading all the package names in the specified signature file and adding * them to the internal tree set. Then the old package list file is removed * and the new package list file is written out. * * @throws Exception * if there is a problem removing the existing package file or * writting the new package list file. */ public void writePkgListFile() throws Exception { readPkgsFromSigFile(); removePkgFile(); writePkgFile(); } /** * Extract the package name from the specified string. The specified string * should have the form: "package jakarta.ejb;" * * @param packageLine * The string containing the package name. * * @return String The extracted package name. * * @throws Exception * if the specified string does not conform to the expected format. */ private String parsePackageName(String packageLine) throws Exception { // sig test framework doesn't have the concept of package entries // as the ApiCheck signature format does. // Instead, we need to parse an entry similar to this: // CLSS public jakarta.some.package.SomeClass return packageLine.substring(packageLine.lastIndexOf(' ') + 1, packageLine.lastIndexOf('.')); } /** * Reads the package names from the signature file. Each package name that is * read is added to this classes internal tree set. * * @throws Exception * if there is an error opening or reading the signature file. */ private void readPkgsFromSigFile() throws Exception { BufferedReader in = new BufferedReader(new FileReader(sigFile)); String line; String trimLine; try { while ((line = in.readLine()) != null) { trimLine = line.trim(); if (trimLine.startsWith("CLSS")) { packageNames.add(parsePackageName(trimLine)); } } } finally { try { in.close(); } catch (Exception e) { } } } /** * Removes the existing package list file. The package list file is actually * moved to a backup file if it exists. The old backup is lost. * * @throws Exception * if there is an error moving the current package list file to a * backup file. */ private void removePkgFile() throws Exception { File backupPkgFile = new File(packageFile.getPath() + BACKUP_EXT); if (backupPkgFile.exists() && backupPkgFile.isFile()) { backupPkgFile.delete(); } if (packageFile.isFile() && packageFile.exists()) { File copyPackageFile = new File(packageFile.getPath()); copyPackageFile.renameTo(backupPkgFile); } } /** * Write a simple header to the package list file to explain what the file is. * * @param out * The BufferedWriter to dump the header to. * * @throws Exception * if there is any errors writing the header to the specified * BufferedWriter. */ private void writeHeader(BufferedWriter out) throws Exception { out.write(COMMENT_CHAR); out.write(COMMENT_CHAR); out.newLine(); out.write(COMMENT_CHAR + " This file contains a list of all the packages"); out.newLine(); out.write(COMMENT_CHAR + " contained in the signature files for this"); out.newLine(); out.write( COMMENT_CHAR + " deliverable. This file is used to exclude valid"); out.newLine(); out.write(COMMENT_CHAR + " sub-packages from being verified when their"); out.newLine(); out.write(COMMENT_CHAR + " parent package's signature is checked."); out.newLine(); out.write(COMMENT_CHAR); out.write(COMMENT_CHAR); out.newLine(); out.newLine(); } /** * Write the list of package names out to a package list file. * * @throws Exception * if there is an error creating and writting the package list file. */ private void writePkgFile() throws Exception { BufferedWriter out = null; try { out = new BufferedWriter(new FileWriter(packageFile)); writeHeader(out); for (Iterator i = packageNames.iterator(); i.hasNext();) { String packageName = (String) i.next(); out.write(packageName); out.newLine(); LOGGER.info("PackageList.writePkgFile() \"" + packageName + "\""); } } finally { if (out != null) { out.close(); } } } /** * Returns the list of sub-packages that exist in the specified package name. * * @param pkgName * The name of the package we want the sub-package list for. * * @return String[] The sub-packages that live under the specified parent * package. */ public String[] getSubPackages(String pkgName) { List result = new ArrayList(); String subPackageName = pkgName + "."; for (Iterator i = packageNames.iterator(); i.hasNext();) { String packageName = (String) i.next(); if (packageName.startsWith(subPackageName)) { result.add(packageName); } } return (String[]) (result.toArray(new String[result.size()])); } /** * Returns the list of sub-packages that exist in the specified package name. * The returned string matches the API check format of specifying multiple * packages with a single string. Each package name is separated with the "+" * character. * * @param pkgName * The name of the package we want the sub-package list for. * * @return String The sub-packages that live under the specified parent * package. */ public String getSubPackagesFormatted(String pkgName) { StringBuffer formattedResult = new StringBuffer(); String[] result = getSubPackages(pkgName); for (int i = 0; i < result.length; i++) { formattedResult.append(result[i]); if (i < (result.length - 1)) { formattedResult.append("+"); } } return formattedResult.toString(); } /* * Test Driver */ public static void main(String[] args) throws Exception { LOGGER.info("\n\n*** Creating package list file ***\n\n"); PackageList list = new PackageList("jakarta.ejb", "/home/ryano/cts-tools-master/tools/api-check/test/jakarta.ejb.sig_2.1", "/home/ryano/cts-tools-master/tools/api-check/test/pkg-list.txt"); list.writePkgListFile(); LOGGER.info("\n\n*** Reading sub-packages from package list file ***\n\n"); PackageList readList = new PackageList( "/home/ryano/cts-tools-master/tools/api-check/test/pkg-list.txt"); LOGGER.info(readList.getSubPackages("jakarta.ejb").toString()); LOGGER.info(readList.getSubPackagesFormatted("jakarta.ejb").toString()); } } // end class PackageList





© 2015 - 2024 Weber Informatics LLC | Privacy Policy