blob: 550de2f4f8d82c401846672dcb1c442d7d998a62 [file] [log] [blame]
package org.apache.maven.shared.utils.io;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import javax.annotation.Nonnull;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Java7 feature detection
*
* @author Kristian Rosenvold
*/
public class Java7Support
{
private static final boolean IS_JAVA7;
private static Method isSymbolicLink;
private static Method delete;
private static Method toPath;
private static Method exists;
private static Method toFile;
private static Method readSymlink;
private static Method createSymlink;
private static Object emptyLinkOpts;
private static Object emptyFileAttributes;
static
{
boolean isJava7x = true;
try
{
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class<?> files = cl.loadClass( "java.nio.file.Files" );
Class<?> path = cl.loadClass( "java.nio.file.Path" );
Class<?> fa = cl.loadClass( "java.nio.file.attribute.FileAttribute" );
Class<?> linkOption = cl.loadClass( "java.nio.file.LinkOption" );
isSymbolicLink = files.getMethod( "isSymbolicLink", path );
delete = files.getMethod( "delete", path );
readSymlink = files.getMethod( "readSymbolicLink", path );
emptyFileAttributes = Array.newInstance( fa, 0 );
final Object o = emptyFileAttributes;
createSymlink = files.getMethod( "createSymbolicLink", path, path, o.getClass() );
emptyLinkOpts = Array.newInstance( linkOption, 0 );
exists = files.getMethod( "exists", path, emptyLinkOpts.getClass() );
toPath = File.class.getMethod( "toPath" );
toFile = path.getMethod( "toFile" );
}
catch ( ClassNotFoundException e )
{
isJava7x = false;
}
catch ( NoSuchMethodException e )
{
isJava7x = false;
}
IS_JAVA7 = isJava7x;
}
/**
* @param file The file to check for being a symbolic link.
* @return true if the file is a symlink false otherwise.
*/
public static boolean isSymLink( @Nonnull File file )
{
try
{
Object path = toPath.invoke( file );
return (Boolean) isSymbolicLink.invoke( null, path );
}
catch ( IllegalAccessException e )
{
throw new RuntimeException( e );
}
catch ( InvocationTargetException e )
{
throw new RuntimeException( e );
}
}
/**
* @param symlink The sym link.
* @return The file.
* @throws IOException in case of error.
*/
@Nonnull public static File readSymbolicLink( @Nonnull File symlink )
throws IOException
{
try
{
Object path = toPath.invoke( symlink );
Object resultPath = readSymlink.invoke( null, path );
return (File) toFile.invoke( resultPath );
}
catch ( IllegalAccessException e )
{
throw new RuntimeException( e );
}
catch ( InvocationTargetException e )
{
throw new RuntimeException( e );
}
}
/**
* @param file The file to check.
* @return true if exist false otherwise.
* @throws IOException in case of failure.
*/
public static boolean exists( @Nonnull File file )
throws IOException
{
try
{
Object path = toPath.invoke( file );
final Object invoke = exists.invoke( null, path, emptyLinkOpts );
return (Boolean) invoke;
}
catch ( IllegalAccessException e )
{
throw new RuntimeException( e );
}
catch ( InvocationTargetException e )
{
throw (RuntimeException) e.getTargetException();
}
}
/**
* @param symlink The link name.
* @param target The target.
* @return The linked file.
* @throws IOException in case of an error.
*/
@Nonnull public static File createSymbolicLink( @Nonnull File symlink, @Nonnull File target )
throws IOException
{
try
{
if ( !exists( symlink ) )
{
Object link = toPath.invoke( symlink );
Object path = createSymlink.invoke( null, link, toPath.invoke( target ), emptyFileAttributes );
return (File) toFile.invoke( path );
}
return symlink;
}
catch ( IllegalAccessException e )
{
throw new RuntimeException( e );
}
catch ( InvocationTargetException e )
{
final Throwable targetException = e.getTargetException();
if ( targetException instanceof IOException )
{
throw (IOException) targetException;
}
else if ( targetException instanceof RuntimeException )
{
// java.lang.UnsupportedOperationException: Symbolic links not supported on this operating system
// java.lang.SecurityException: denies certain permissions see Javadoc
throw ( RuntimeException ) targetException;
}
else
{
throw new IOException( targetException.getClass() + ": " + targetException.getLocalizedMessage() );
}
}
}
/**
* Performs a nio delete
* @param file the file to delete
* @throws IOException in case of error.
*/
public static void delete( @Nonnull File file )
throws IOException
{
try
{
Object path = toPath.invoke( file );
delete.invoke( null, path );
}
catch ( IllegalAccessException e )
{
throw new RuntimeException( e );
}
catch ( InvocationTargetException e )
{
throw (IOException) e.getTargetException();
}
}
/**
* @return true in case of Java 7.
*/
public static boolean isJava7()
{
return IS_JAVA7;
}
/**
* @return true in case of Java7 or greater.
*/
public static boolean isAtLeastJava7()
{
return IS_JAVA7;
}
}