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

com.github.loicoudot.java4cpp.FileManager Maven / Gradle / Ivy

package com.github.loicoudot.java4cpp;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Formatter;
import java.util.List;
import java.util.Properties;
import java.util.regex.Pattern;

import javax.xml.bind.JAXB;

import com.github.loicoudot.java4cpp.configuration.Symbols;

/**
 * Manager for all interractions between java4cpp and the file system.
 * 

* There are two log files: *

    *
  • {@code java4cpp.log} inside the target directory along the C++ proxies, * which contains the dependency tree of class.
  • *
  • maven plugin log, for logging informations and errors to the console.
  • *
* Other file are the C++ proxies, and {@code java4cpp.hash} also inside the * target directory, which contains the MD5 hash value of the files. * * @author Loic Oudot * */ final class FileManager { private static final String JAVA4CPP_HASH = "java4cpp.hash"; private static final String JAVA4CPP_LOG = "java4cpp.log"; private static final int BUFFER_SIZE = 1024; private final Context context; private final ThreadLocal indent = new ThreadLocal() { @Override protected String initialValue() { return ""; }; }; private FileWriter java4cppLog; private File java4cppHash; private final Symbols imports = new Symbols(); private final Symbols export = new Symbols(); private List oldFiles = new ArrayList(); private final Properties oldHashes = new Properties(); private final Properties newHashes = new Properties(); private int generated; private int skipped; private int deleted; private int imported; /** * A {@code FilenameFilter} to filter files other than {@code java4cpp.log} * and {@code java4cpp.hash} * * @author Loic Oudot * */ final class SourceFilter implements FilenameFilter { @Override public boolean accept(File dir, String name) { return !(name.equalsIgnoreCase(FileManager.JAVA4CPP_LOG) || name.equalsIgnoreCase(FileManager.JAVA4CPP_HASH)); } } public FileManager(Context context) { this.context = context; } /** * Called before starting generating proxies files. Create the * {@code java4cpp.log} log file, and manage the {@code clean} and * {@code useHash} settings. */ public void start() { addSymbolsFromSettings(); File rep = new File(context.getSettings().getTargetPath()); rep.mkdirs(); try { java4cppLog = new FileWriter(new File(getPath(JAVA4CPP_LOG))); } catch (IOException e) { System.err.println("Can't create log file: " + e.getMessage()); } try { File[] existings = rep.listFiles(new SourceFilter()); if (existings != null) { oldFiles = new ArrayList(Arrays.asList(existings)); } java4cppHash = new File(getPath(JAVA4CPP_HASH)); BufferedInputStream in = new BufferedInputStream(new FileInputStream(java4cppHash)); oldHashes.load(in); in.close(); java4cppHash.delete(); } catch (IOException e) { logInfo("no java4cpp.hash file, regenerating all files"); } } /** * Reads the imports files to construct the list of import symbols to use. */ private void addSymbolsFromSettings() { if (!Utils.isNullOrEmpty(context.getSettings().getImportsFile())) { Symbols imported = new Symbols(); for (String name : context.getSettings().getImportsFile().split(";")) { try { InputStream is = Utils.getFileOrResource(name); Symbols symbol = JAXB.unmarshal(is, Symbols.class); is.close(); imported.getSymbols().addAll(symbol.getSymbols()); } catch (IOException e) { throw new RuntimeException("Failed to read imports: " + e.getMessage()); } } if (Utils.isNullOrEmpty(context.getSettings().getImportFilter())) { imports.getSymbols().addAll(imported.getSymbols()); } else { Pattern regex = Pattern.compile(context.getSettings().getImportFilter()); for (String symbol : imported.getSymbols()) { if (regex.matcher(symbol).matches()) { imports.getSymbols().add(symbol); } } } } } /** * Called after all the proxies are generated. Delete all the remaining * files in the target directory. */ public void stop() { if (!Utils.isNullOrEmpty(context.getSettings().getExportFile())) { if (Utils.isNullOrEmpty(context.getSettings().getExportFilter())) { JAXB.marshal(export, new File(context.getSettings().getExportFile())); } else { Symbols exportFiltered = new Symbols(); Pattern regexp = Pattern.compile(context.getSettings().getExportFilter()); for (String symbol : export.getSymbols()) { if (regexp.matcher(symbol).matches()) { exportFiltered.getSymbols().add(symbol); } } JAXB.marshal(exportFiltered, new File(context.getSettings().getExportFile())); } } if (context.getSettings().isClean()) { for (File file : oldFiles) { logInfo("deleting " + file.getName()); if (!file.delete()) { logInfo("failed"); } ++deleted; } } try { final BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(java4cppHash)); newHashes.store(out, "Generated by java4cpp"); out.close(); } catch (IOException e) { throw new RuntimeException("Failed to generate java4cpp.hash " + e.getMessage()); } logInfo(String.format("generated: %d, imported: %d, skipped: %d, deleted: %d", generated, imported, skipped, deleted)); } public void enter(String message) { synchronized (java4cppLog) { try { java4cppLog.append('[').append(Thread.currentThread().getName()).append("] "); java4cppLog.append(indent.get()).append(message).append('\n'); java4cppLog.flush(); } catch (IOException e) { } } indent.set(indent.get() + " "); } public void leave() { indent.set(indent.get().substring(2)); } /** * Write {@code message} inside the {@code java4cpp.log} file. * * @param message * the message to log */ public void logInfo(String message) { synchronized (java4cppLog) { try { java4cppLog.append('[').append(Thread.currentThread().getName()).append("] "); java4cppLog.append(indent.get()).append(message).append('\n'); java4cppLog.flush(); } catch (IOException e) { } } } public void writeSourceFile(String fileName, StringWriter sw) { saveFile(new String(sw.getBuffer()), new File(getPath(fileName))); } public void copyFile(String fileName) throws IOException { String content = readFile(Utils.getFileOrResource(fileName)); saveFile(content, new File(getPath(fileName))); } public Symbols getSymbols() { return export; } /** * Write the file {@code fileName} in the target directory with * {@code fileContent}. If {@code useHash} is true, then the file is save if * it's doesn't exist or if the content has changed. */ private synchronized void saveFile(String fileContent, File fileName) { try { if (imports.getSymbols().contains(fileName.getName())) { logInfo(" imported " + fileName); ++imported; } else { export.getSymbols().add(fileName.getName()); MessageDigest algo = MessageDigest.getInstance("MD5"); algo.update(fileContent.getBytes()); String md5 = bytesToHexString(algo.digest()); newHashes.put(fileName.getName(), md5); if (!context.getSettings().isUseHash() || !oldFiles.contains(fileName) || !md5.equals(oldHashes.getProperty(fileName.getName()))) { fileName.setWritable(true); BufferedOutputStream writer = new BufferedOutputStream(new FileOutputStream(fileName)); writer.write(fileContent.getBytes()); fileName.setWritable(false); writer.close(); ++generated; logInfo(" generated " + fileName); } else { ++skipped; logInfo(" skipped " + fileName); } oldFiles.remove(fileName); } } catch (Exception e) { throw new RuntimeException("Failed to save file " + e.getMessage()); } } private String getPath(String fileName) { return String.format("%s%s%s", context.getSettings().getTargetPath(), File.separator, fileName); } private String readFile(InputStream input) throws IOException { Appendable sb = new StringBuilder(BUFFER_SIZE); Reader reader = new InputStreamReader(input); char[] chars = new char[BUFFER_SIZE]; int numRead; while ((numRead = reader.read(chars)) > -1) { sb.append(String.valueOf(chars, 0, numRead)); } reader.close(); return sb.toString(); } private static String bytesToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 2); Formatter formatter = new Formatter(sb); for (byte b : bytes) { formatter.format("%02X", b); } formatter.close(); return sb.toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy