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

org.eclipse.persistence.tools.PackageRenamer Maven / Gradle / Ivy

There is a newer version: 5.0.0-B03
Show newest version
/*
 * Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 1998, 2024 IBM Corporation. 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,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Oracle - initial API and implementation from Oracle TopLink
//     08/29/2016 Jody Grassel
//       - 500441: Eclipselink core has System.getProperty() calls that are not potentially executed under doPriv()
package org.eclipse.persistence.tools;

import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.Objects;
import java.util.Properties;
import java.util.Vector;

/**
 * This class performs package renaming. It demonstrates the following:
 * 

* a) Reading the properties file to be a reference for changing the package * name from your source code. *

* b) Traverse source root directory for creating a corresponding output directory * and finding the java source file(s) to be changing the package name. *

* c) Search and replace the old TopLink package name(s) with new one(s) according to the reference. *

* You will be able to see the logging message at the command line window * where the PackageRenamer is running. * */ public class PackageRenamer { int numberOfTotalFile = 0; int numberOfChangedFile = 0; // contains the option of Log file. boolean specifyLogFile = false; java.io.PrintWriter outLog = null; // contains the Log File String logFileString = null; java.io.File logFile; // contains the source-root-directory java.io.File sourceRootDirFile; // contains the destination-root-directory java.io.File destinationRootDir; // contains the properties file path String sourceProperties; // contains a reference for renaming Properties properties = null; String propertiesFileName; boolean VERBOSE = true; protected static final String SYSTEM_OUT = "System.out"; BufferedReader reader = null; String[] UNSUPPORTED_EXTENSIONS = { "jar", "zip", "ear", "war", "dll", "class", "exe" }; int BUFSIZ = 1024 * 4; final static String CR; static { // bug 2756643 CR = System.lineSeparator(); } /** * The constructor of a PackageRenamer class. */ public PackageRenamer() { this(getDefaultPropertiesFileName()); } public PackageRenamer(String propertiesFileName) { System.out.println(); System.out.println("TopLink Package Renamer"); System.out.println("-----------------------"); System.out.println(bannerText()); sourceRootDirFile = existingDirectoryFromPrompt(); System.out.println(); destinationRootDir = promptForDestinationDirectory(); System.out.println(); this.propertiesFileName = propertiesFileName; outLog = streamForNonExistentFilePrompt(); properties = readChangesFile(propertiesFileName); } public PackageRenamer(String[] args) { this.propertiesFileName = args[0]; sourceRootDirFile = buildAndCheckExistingDirFile(args[1]); destinationRootDir = buildAndCheckDestinationFile(args[2]); if (args.length == 4) { outLog = buildAndCheckLogWriter(args[3]); } else { outLog = buildAndCheckLogWriter(SYSTEM_OUT); } properties = readChangesFile(args[0]); logln(bannerText()); } protected String bannerText() { StringBuilder stringBuilder = new StringBuilder(CR.length()*3+66+42); stringBuilder.append(CR); stringBuilder.append("NOTE: The package renamer is meant to be run on plain text files. "); stringBuilder.append(CR); stringBuilder.append("A rename will NOT be done on binary files."); stringBuilder.append(CR); return stringBuilder.toString(); } /** * Do a binary copy of the file byte buffer by byte buffer. * * @param inFile * The file to copy * @param outFile * The destination file * @throws FileNotFoundException * if either of the two files does not exist * @throws IOException * if any other IO related error occurs */ public void binaryCopy(File inFile, File outFile) throws FileNotFoundException, IOException { byte[] buf = new byte[BUFSIZ]; try (FileInputStream in = new FileInputStream(inFile); FileOutputStream out = new FileOutputStream(outFile)) { int nBytesRead; while ((nBytesRead = in.read(buf)) != -1) { out.write(buf, 0, nBytesRead); } } } protected boolean bufferContainsNullChar(byte[] buffer, int bufferLength) { for (int i = 0; i < bufferLength; i++) { if (buffer[i] == 0) { return true; } } return false; } /** * INTERNAL Creates a destination directory File object under the path * passed, verifying correctness. * * @param aDirString * The path to the directory File object to create * @return The destination directory File object */ public File buildAndCheckDestinationFile(String aDirString) { if (aDirString == null) { throw new PackageRenamerException("Invalid destination directory entered."); } File aDirFile = new File(aDirString); if (aDirFile.exists()) { File[] dirContent = aDirFile.listFiles(); if (dirContent != null && dirContent.length != 0) { throw new PackageRenamerException("Output Directory:" + CR + " '" + aDirString + "'" + CR + "exists and is not empty."); } } if (!aDirFile.isAbsolute()) { throw new PackageRenamerException("A relative destination directory was entered:" + CR + " '" + aDirString + "'" + CR + "The directory must be absolute."); } // Check if the destination directory is within the source directory. This would create an infinite loop. if (directoryIsSubdirectory(sourceRootDirFile, aDirFile)) { throw new PackageRenamerException("Invalid destination directory entered:" + CR + " '" + aDirString + "'" + CR + "It cannot be a sub-directory of the source directory."); } return aDirFile; } public File buildAndCheckExistingDirFile(String aDirString) { if (aDirString == null) { throw new PackageRenamerException("Invalid source directory entered."); } File aDirFile = new File(aDirString); if (!aDirFile.exists() || !aDirFile.isDirectory()) { throw new PackageRenamerException("Input Directory:" + CR + " '" + aDirString + "'" + CR + "does not exist or is not a directory."); } if (!aDirFile.isAbsolute()) { throw new PackageRenamerException("A relative source directory was entered:" + CR + " '" + aDirString + "'" + CR + "The directory must be absolute."); } return aDirFile; } public PrintWriter buildAndCheckLogWriter(String logFileString) { if (logFileString == null) { throw new PackageRenamerException("Invalid log file name entered."); } try { if (logFileString.equals(SYSTEM_OUT)) { return new PrintWriter(System.out); } else { File aLogFile = new File(logFileString); if (aLogFile.exists()) { throw new PackageRenamerException("Specified log file cannot be created:" + CR + " '" + logFileString + "'"); } FileWriter writerLog = new FileWriter(logFileString); return new java.io.PrintWriter(writerLog); } } catch (IOException ioException) { throw new PackageRenamerException("Unhandled IOException occurred while configuring log file: '" + logFileString + "', " + ioException.getMessage()); } } protected void cleanup() { //Closing the Log file in case it is being open. if (outLog != null) { outLog.close(); } } /** * This method creates an output directory for post-rename file(s). * * @param aDirectory * The output directory to create */ public void createDestinationDirectory(File aDirectory) { if (!aDirectory.exists()) { if (!aDirectory.mkdirs()) { throw new PackageRenamerException("Error while creating directory:" + CR + " '" + aDirectory + "'"); } } else { throw new PackageRenamerException("Error directory: '" + aDirectory + "' already exists but shouldn't."); } } /** * Return true if directory2 is contained within directory1. Both * directories must be absolute. * * @param directory1 * The higher level directory * @param directory2 * The lower level directory * @return TRUE if directory2 is a subdirectory of directory1 */ public static boolean directoryIsSubdirectory(File directory1, File directory2) { // System.out.println(directory1 + " contains " + directory2); if (directory2 == null) { return false; } else if (directory1.equals(directory2)) { return true; } else { return directoryIsSubdirectory(directory1, directory2.getParentFile()); } } public File existingDirectoryFromPrompt() { System.out.print("Enter the path of the directory which contains the files to rename:" + CR + "> "); String aLine = null; try { aLine = getReader().readLine(); } catch (IOException exception) { throw new PackageRenamerException("Error while reading the source directory: " + exception.getMessage()); } return buildAndCheckExistingDirFile(aLine); } public static String getDefaultPropertiesFileName() { String currentDirectory = PrivilegedAccessHelper.shouldUsePrivilegedAccess() ? AccessController.doPrivileged(new PrivilegedAction<>() { @Override public String run() { return System.getProperty("user.dir"); } }) : System.getProperty("user.dir"); return currentDirectory + File.separator + "packageRename.properties"; } public synchronized BufferedReader getReader() { if (reader == null) { reader = new BufferedReader(new InputStreamReader(System.in)); } return reader; } /** * Return true if the PackageRenamer should work on the given file * extension. * * @param extension * The file extension to check for being supported * @return TRUE if the extension is supported */ public boolean isExtensionSupported(String extension) { /* This was cut out because the binary check recognize these files and just copy them byte by byte. for (int i=0; i "); String aLine = null; try { aLine = getReader().readLine(); } catch (IOException exception) { throw new PackageRenamerException("Error while reading the destination directory specified: " + exception.getMessage()); } return buildAndCheckDestinationFile(aLine); } /** * This readChangesFile() method reads the given properties file to be a * reference for renaming TopLink package name. * * @param filename * The input file to use for the renaming * @return The Properties object containing the renaming information */ public Properties readChangesFile(String filename) { Properties props = new Properties(); try (InputStream in = new FileInputStream(filename)) { props.load(in); } catch (FileNotFoundException fileNotFoundException) { throw new PackageRenamerException("Properties file was not found:" + CR + " '" + filename + "'"); } catch (IOException ioException) { throw new PackageRenamerException("IO error occurred while reading the properties file:'" + filename + "'" + ioException.getMessage()); } logln("Using properties file: " + filename); return props; } /** * This run() method performs, * reading the properties file into properties variable to be a reference for changing package name. * creating a destination-root-directory. * and, calling traverseSourceDirectory() method. */ public void run() { // Start loging. logln("LOG MESSAGES FROM packageRenamer"); logln("" + new Date()); logln(""); logln("INPUT: -----------------> " + sourceRootDirFile.toString()); logln("OUTPUT: ----------------> " + destinationRootDir.toString()); // logln("PROPERTIES FILE: -------> "+sourceProperties); // logln("LOG FILE: --------------> "+writerLog); logln(""); // Root output directory. logln("Verifying root output directory..."); if (!(destinationRootDir.exists())) { // Create root directory for output first. logln(""); logln("Creating root output directory..."); createDestinationDirectory(destinationRootDir); logln(""); } logln("Verifying root output directory...DONE"); logln(""); // Listing the changed file(s) logln("List of changed file(s): "); logln(""); traverseSourceDirectory(sourceRootDirFile); logln(""); logln("Total Changed File(s): ------> " + numberOfChangedFile); logln("Total File(s): ------> " + numberOfTotalFile); logln(""); } protected PrintWriter streamForNonExistentFilePrompt() { System.out.print("Enter the absolute path of the log file [Hit Enter for SYSTEM.OUT]:" + CR + "> "); String aLine = null; try { aLine = getReader().readLine(); } catch (IOException exception) { throw new PackageRenamerException("Error while reading the name of the log file: " + exception.getMessage()); } if ((aLine != null) && (aLine.isEmpty())) { return buildAndCheckLogWriter(SYSTEM_OUT); } else { return buildAndCheckLogWriter(aLine); } } /** * This runSearchAndReplacePackageName() reads a pre-rename source file all * into string variable and replacing the old package names with the new * ones according to the properties file. * * @param sourceFile * The source file to process */ public void runSearchAndReplacePackageName(java.io.File sourceFile) { String stringContainAllFile = ""; String sourceFileName = sourceFile.toString(); String sourceFileNameWithoutRoot = sourceFile.toString().substring(sourceRootDirFile.toString().length() + 1); // Rename the file name if required. sourceFileNameWithoutRoot = returnNewFileNameIfRequired(sourceFileNameWithoutRoot); String destinationFileName = destinationRootDir.toString() + File.separator + sourceFileNameWithoutRoot; // Reading file into string. // stringContainAllFile = readAllStringsFromFile(sourceFileName); try (FileInputStream fis = new FileInputStream(sourceFileName)) { byte[] buf = new byte[BUFSIZ]; StringBuilder strBuf = new StringBuilder((int) new File(sourceFileName).length()); int i = 0; while ((i = fis.read(buf)) != -1) { if (bufferContainsNullChar(buf, i)) { // This is a binary file, just copy it byte by byte to the new location. Do not do any renaming. fis.close(); binaryCopy(sourceFile, new File(destinationFileName)); return; } String str = new String(buf, 0, i); strBuf.append(str); } fis.close(); stringContainAllFile = new String(strBuf); } catch (IOException ioException) { throw new PackageRenamerException("Unexpected exception was thrown during file manipulation." + ioException.getMessage()); } // Sorting key package name. Vector aVector = new Vector<>(); aVector.addAll(properties.keySet()); String[] aStringArrayOfSortedKeyPackageName = new String[aVector.size()]; aVector.copyInto(aStringArrayOfSortedKeyPackageName); Arrays.sort(aStringArrayOfSortedKeyPackageName); // Starting to rename. boolean alreadyPrint = false; int index = aStringArrayOfSortedKeyPackageName.length; for (Iterator iterator = properties.keySet().iterator(); iterator.hasNext();) { iterator.next(); String key = aStringArrayOfSortedKeyPackageName[index - 1]; String value = (String)properties.get(key); index -= 1; // Printing the changed file. int found = stringContainAllFile.indexOf(key); if ((found != -1) && (!alreadyPrint)) { alreadyPrint = true; logln((numberOfChangedFile + 1) + ". " + destinationFileName); numberOfChangedFile++; } // replacing the old package name. stringContainAllFile = replace(stringContainAllFile, key, value); } // Writing output file. try { FileWriter writer = new FileWriter(destinationFileName); java.io.PrintWriter out = new java.io.PrintWriter(writer); out.print(stringContainAllFile); out.close(); } catch (FileNotFoundException fileNotFoundException) { throw new PackageRenamerException("Could not find file to write:" + CR + " '" + destinationFileName + "'" + CR + fileNotFoundException.getMessage()); } catch (IOException ioException) { throw new PackageRenamerException("Unexpected exception was thrown while writing the file: '" + destinationFileName + "', " + ioException.getMessage()); } } /** * Do a search and replace in a string. * * @param str * The original String * @param oldChars * The character pattern to replace * @param newChars * The character pattern to replace the existing with * @return the modified String */ public static String replace(String str, String oldChars, String newChars) { int len; int pos; int lastPos; len = newChars.length(); pos = str.indexOf(oldChars); lastPos = pos; while (pos > -1) { String firstPart; String lastPart; firstPart = str.substring(0, pos); lastPart = str.substring(pos + oldChars.length()); str = firstPart + newChars + lastPart; lastPos = pos + len; pos = str.indexOf(oldChars, lastPos); } return (str); } /** * Renames a file based on the properties passed. * * @param aSourceFileNameWithoutRoot * The original filename * @return The new filename, regardless of whether it has been changed */ public String returnNewFileNameIfRequired(String aSourceFileNameWithoutRoot) { for (Iterator iterator = properties.keySet().iterator(); iterator.hasNext();) { String key = (String) iterator.next(); if (aSourceFileNameWithoutRoot.contains(key)) { // replacing the old package name. aSourceFileNameWithoutRoot = replace(aSourceFileNameWithoutRoot, key, (String)properties.get(key)); } } // just simply return whether it has been changed. return aSourceFileNameWithoutRoot; } /** * This traverseSourceDirectory() traverse source-root-directory, creating * a corresponding output directory, and calling another method for * replacing old TopLink package name. * * @param aDirectoryString * The source root directory to traverse */ public void traverseSourceDirectory(java.io.File aDirectoryString) { Objects.requireNonNull(aDirectoryString); java.io.File[] filesAndDirectories = aDirectoryString.listFiles(); if (filesAndDirectories == null) { //no content, nothing to work with return; } for (int i = 0; i < filesAndDirectories.length; i++) { java.io.File fileOrDirectory = filesAndDirectories[i]; if (fileOrDirectory.isDirectory()) { String sourceDirectoryName = fileOrDirectory.toString(); String destinationDirectoryName = destinationRootDir.toString() + sourceDirectoryName.substring(sourceRootDirFile.toString().length()); createDestinationDirectory(new java.io.File(destinationDirectoryName)); traverseSourceDirectory(fileOrDirectory); } else { // it is a file. numberOfTotalFile++; // Check that it does not have an unsupported file extension String fileExtension = parseFileExtension(fileOrDirectory); if (isExtensionSupported(fileExtension)) { runSearchAndReplacePackageName(fileOrDirectory); } } } } public static void usage() { System.out.println(); System.out.println("TopLink Package Renamer"); System.out.println("-----------------------"); System.out.println(); System.out.println("The package renamer should be run once on user source code, configuration"); System.out.println("files, and Mapping Workbench project files that have references to"); System.out.println("pre-Oracle 9iAS TopLink 9.0.3 API packages. The package renamer works on"); System.out.println("plain text files and should NOT be run on binary files such as JAR files."); System.out.println(); System.out.println("The package renamer supports two command line usages. A call which specifies"); System.out.println("all the required arguments, and a call which takes only one parameter. In"); System.out.println("this last case, the user is prompted for the missing arguments."); System.out.println(); System.out.println("Usage:"); System.out.println(); System.out.println("java org.eclipse.persistence.tools.PackageRenamer "); System.out.println(); System.out.println("OR"); System.out.println(); System.out.println("java org.eclipse.persistence.tools.PackageRenamer [ ]"); System.out.println(); System.out.println("where:"); System.out.println("\t - File containing a list of old and new package"); System.out.println("\tnames."); System.out.println(); System.out.println("\t - Absolute path name of the directory which"); System.out.println("\tcontains all the file to be converted. The "); System.out.println("\twill be searched recursively for files to convert. This directory"); System.out.println("\tshould contain only the plain text files to be converted."); System.out.println(); System.out.println("\t - Absolute path name of the directory"); System.out.println("\twhere the converted directory structure will be copied. All files"); System.out.println("\twill be copied to the new directory structure whether changes were"); System.out.println("\tmade or not. This directory must either not exist or be empty."); System.out.println(); System.out.println("\t - The logging of the renaming process will be written"); System.out.println("\tto the . If no is specified then logging"); System.out.println("\twill be written to standard output."); System.out.println(); } // Made static final for performance reasons. public static final class PackageRenamerException extends RuntimeException { public PackageRenamerException(String aMessage) { super(aMessage); } } }