/* * Copyright (c) 2002-2017 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.neo4j.driver.v1.util; import org.rauschig.jarchivelib.ArchiveStream; import org.rauschig.jarchivelib.Archiver; import org.rauschig.jarchivelib.ArchiverFactory; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.URL; import java.nio.file.Files; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Scanner; import java.util.Set; import static java.io.File.createTempFile; public class FileTools { private static final int WINDOWS_RETRY_COUNT = 5; public static void deleteRecursively( File file ) { if ( file.isDirectory() ) { File[] files = file.listFiles(); if ( files != null ) { for ( File sub : files ) { deleteRecursively( sub ); } } } //noinspection ResultOfMethodCallIgnored file.delete(); } @SuppressWarnings("ResultOfMethodCallIgnored") public static File tmpDir() throws IOException { File tmp = createTempFile( "neo", "compliance" ); tmp.delete(); tmp.mkdir(); return tmp; } public static boolean deleteFile( File file ) { if ( !file.exists() ) { return true; } int count = 0; boolean deleted; do { deleted = file.delete(); if ( !deleted ) { count++; waitAndThenTriggerGC(); } } while ( !deleted && count <= WINDOWS_RETRY_COUNT ); return deleted; } public static void moveFile( File toMove, File target ) throws IOException { if ( !toMove.exists() ) { throw new FileNotFoundException( "Source file[" + toMove.getAbsolutePath() + "] not found" ); } if ( target.exists() ) { throw new IOException( "Target file[" + target.getAbsolutePath() + "] already exists" ); } if ( toMove.renameTo( target ) ) { return; } if ( toMove.isDirectory() ) { Files.createDirectories( target.toPath() ); copyRecursively( toMove, target, null ); deleteRecursively( toMove ); } else { copyFile( toMove, target ); deleteFile( toMove ); } } public static void copyRecursively( File fromDirectory, File toDirectory, FileFilter filter) throws IOException { for ( File fromFile : fromDirectory.listFiles( filter ) ) { File toFile = new File( toDirectory, fromFile.getName() ); if ( fromFile.isDirectory() ) { Files.createDirectories( toFile.toPath() ); copyRecursively( fromFile, toFile, filter ); } else { copyFile( fromFile, toFile ); } } } public static void copyFile( File srcFile, File dstFile ) throws IOException { //noinspection ResultOfMethodCallIgnored File parentFile = dstFile.getParentFile(); if (parentFile!=null) { parentFile.mkdirs(); } FileInputStream input = null; FileOutputStream output = null; try { input = new FileInputStream( srcFile ); output = new FileOutputStream( dstFile ); int bufferSize = 1024; byte[] buffer = new byte[bufferSize]; int bytesRead; while ( (bytesRead = input.read( buffer )) != -1 ) { output.write( buffer, 0, bytesRead ); } } catch ( IOException e ) { // Because the message from this cause may not mention which file it's about throw new IOException( "Could not copy '" + srcFile.getCanonicalPath() + "' to '" + dstFile.getCanonicalPath() + "'", e ); } finally { if ( input != null ) { input.close(); } if ( output != null ) { output.close(); } } } /* * See http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4715154. */ private static void waitAndThenTriggerGC() { try { Thread.sleep( 500 ); } catch ( InterruptedException ee ) { Thread.interrupted(); } // ok System.gc(); } public static void updateProperty( File propFile, String key, String value ) throws IOException { Map<String, String> propertiesMap = new HashMap<>( 1 ); propertiesMap.put( key, value ); updateProperties( propFile, propertiesMap, Collections.<String>emptySet() ); } public static void updateProperties( File propFile, Map<String, String> propertiesMap, Set<String> excludes ) throws IOException { Scanner in = new Scanner( propFile ); Set<String> updatedProperties = new HashSet<>( propertiesMap.size() ); File newPropFile = File.createTempFile( propFile.getName(), null ); try { FileOutputStream outStream = new FileOutputStream( newPropFile ); PrintWriter out = new PrintWriter( outStream ); while ( in.hasNextLine() ) { String line = in.nextLine(); if ( !line.trim().startsWith( "#" ) ) { String[] tokens = line.split( "=" ); if ( tokens.length == 2 ) { String name = tokens[0].trim(); if (excludes.contains( name )) { continue; } Object value = propertiesMap.get( name ); if ( value != null && !updatedProperties.contains( name ) ) { // found property and set it to the new value printlnProperty( out, name, value ); updatedProperties.add( name ); } else { // not the property that we are looking for, print it as original out.println( line ); } } else { // not the property that we are looking for, print it as original out.println( line ); } } else { // comments, print as original out.println( line ); } } for ( Map.Entry<String,String> entry : propertiesMap.entrySet() ) { String name = entry.getKey(); Object value = entry.getValue(); if ( value != null && !updatedProperties.contains( name ) ) { // add this as a new prop printlnProperty( out, name, value ); } } in.close(); out.flush(); out.close(); deleteFile( propFile ); moveFile( newPropFile, propFile ); } catch ( IOException | RuntimeException e ) { newPropFile.deleteOnExit(); throw e; } } private static void printlnProperty( PrintWriter out, String name, Object value ) { out.print( name ); out.print( '=' ); out.println( value ); } /** To allow retrieving a runnable neo4j jar from the international webbernets, we have this */ public static void streamFileTo( String url, File target ) throws IOException { if( target.getParentFile()!= null && !target.getParentFile().exists() ) { target.getParentFile().mkdirs(); } try ( FileOutputStream out = new FileOutputStream( target ); InputStream in = new URL( url ).openStream() ) { byte[] buffer = new byte[1024]; int read = in.read( buffer ); while ( read != -1 ) { if ( read > 0 ) { out.write( buffer, 0, read ); } read = in.read( buffer ); } } } public static void extractTarball( File tarball, File untarToDir ) throws IOException { Archiver archiver = ArchiverFactory.createArchiver( "tar", "gz" ); archiver.extract( tarball, untarToDir ); } public static void extractTarball( File tarball, File outputDir, File outputName, Archiver archiver ) throws IOException { archiver.extract( tarball, outputDir ); // Rename the extracted file to something predictable (extracted folder may contain build number, date or so) try ( ArchiveStream stream = archiver.stream( tarball ) ) { new File( outputDir, stream.getNextEntry().getName() ).renameTo( outputName ); } } }