View Javadoc
1   package org.apache.maven.shared.utils.io;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import javax.annotation.Nonnull;
23  import java.io.File;
24  import java.io.IOException;
25  import java.lang.reflect.Array;
26  import java.lang.reflect.InvocationTargetException;
27  import java.lang.reflect.Method;
28  
29  /**
30   * Java7 feature detection
31   *
32   * @author Kristian Rosenvold
33   */
34  public class Java7Support
35  {
36  
37      private static final boolean IS_JAVA7;
38  
39      private static Method isSymbolicLink;
40  
41      private static Method delete;
42  
43      private static Method toPath;
44  
45      private static Method exists;
46  
47      private static Method toFile;
48  
49      private static Method readSymlink;
50  
51      private static Method createSymlink;
52  
53      private static Object emptyLinkOpts;
54  
55      private static Object emptyFileAttributes;
56  
57      static
58      {
59          boolean isJava7x = true;
60          try
61          {
62              ClassLoader cl = Thread.currentThread().getContextClassLoader();
63              Class<?> files = cl.loadClass( "java.nio.file.Files" );
64              Class<?> path = cl.loadClass( "java.nio.file.Path" );
65              Class<?> fa = cl.loadClass( "java.nio.file.attribute.FileAttribute" );
66              Class<?> linkOption = cl.loadClass( "java.nio.file.LinkOption" );
67              isSymbolicLink = files.getMethod( "isSymbolicLink", path );
68              delete = files.getMethod( "delete", path );
69              readSymlink = files.getMethod( "readSymbolicLink", path );
70  
71              emptyFileAttributes = Array.newInstance( fa, 0 );
72              final Object o = emptyFileAttributes;
73              createSymlink = files.getMethod( "createSymbolicLink", path, path, o.getClass() );
74              emptyLinkOpts = Array.newInstance( linkOption, 0 );
75              exists = files.getMethod( "exists", path, emptyLinkOpts.getClass() );
76              toPath = File.class.getMethod( "toPath" );
77              toFile = path.getMethod( "toFile" );
78          }
79          catch ( ClassNotFoundException e )
80          {
81              isJava7x = false;
82          }
83          catch ( NoSuchMethodException e )
84          {
85              isJava7x = false;
86          }
87          IS_JAVA7 = isJava7x;
88      }
89  
90      /**
91       * @param file The file to check for being a symbolic link.
92       * @return true if the file is a symlink false otherwise.
93       */
94      public static boolean isSymLink( @Nonnull File file )
95      {
96          try
97          {
98              Object path = toPath.invoke( file );
99              return (Boolean) isSymbolicLink.invoke( null, path );
100         }
101         catch ( IllegalAccessException e )
102         {
103             throw new RuntimeException( e );
104         }
105         catch ( InvocationTargetException e )
106         {
107             throw new RuntimeException( e );
108         }
109     }
110 
111 
112     /**
113      * @param symlink The sym link.
114      * @return The file.
115      * @throws IOException in case of error.
116      */
117     @Nonnull public static File readSymbolicLink( @Nonnull File symlink )
118         throws IOException
119     {
120         try
121         {
122             Object path = toPath.invoke( symlink );
123             Object resultPath =  readSymlink.invoke( null, path );
124             return (File) toFile.invoke( resultPath );
125         }
126         catch ( IllegalAccessException e )
127         {
128             throw new RuntimeException( e );
129         }
130         catch ( InvocationTargetException e )
131         {
132             throw new RuntimeException( e );
133         }
134     }
135 
136 
137     /**
138      * @param file The file to check.
139      * @return true if exist false otherwise.
140      * @throws IOException in case of failure.
141      */
142     public static boolean exists( @Nonnull File file )
143         throws IOException
144     {
145         try
146         {
147             Object path = toPath.invoke( file );
148             final Object invoke = exists.invoke( null, path, emptyLinkOpts );
149             return (Boolean) invoke;
150         }
151         catch ( IllegalAccessException e )
152         {
153             throw new RuntimeException( e );
154         }
155         catch ( InvocationTargetException e )
156         {
157             throw (RuntimeException) e.getTargetException();
158         }
159 
160     }
161 
162     /**
163      * @param symlink The link name.
164      * @param target The target.
165      * @return The linked file.
166      * @throws IOException in case of an error.
167      */
168     @Nonnull public static File createSymbolicLink( @Nonnull File symlink,  @Nonnull File target )
169         throws IOException
170     {
171         try
172         {
173             if ( !exists( symlink ) )
174             {
175                 Object link = toPath.invoke( symlink );
176                 Object path = createSymlink.invoke( null, link, toPath.invoke( target ), emptyFileAttributes );
177                 return (File) toFile.invoke( path );
178             }
179             return symlink;
180         }
181         catch ( IllegalAccessException e )
182         {
183             throw new RuntimeException( e );
184         }
185         catch ( InvocationTargetException e )
186         {
187             final Throwable targetException = e.getTargetException();
188             if ( targetException instanceof IOException )
189             {
190                 throw (IOException) targetException;
191             }
192             else if ( targetException instanceof RuntimeException )
193             {
194                 // java.lang.UnsupportedOperationException: Symbolic links not supported on this operating system
195                 // java.lang.SecurityException: denies certain permissions see Javadoc
196                 throw ( RuntimeException ) targetException;
197             }
198             else
199             {
200                 throw new IOException( targetException.getClass() + ": " + targetException.getLocalizedMessage() );
201             }
202         }
203 
204     }
205     /**
206      * Performs a nio delete
207      * @param file the file to delete
208      * @throws IOException in case of error.
209      */
210     public static void delete( @Nonnull File file )
211         throws IOException
212     {
213         try
214         {
215             Object path = toPath.invoke( file );
216             delete.invoke( null, path );
217         }
218         catch ( IllegalAccessException e )
219         {
220             throw new RuntimeException( e );
221         }
222         catch ( InvocationTargetException e )
223         {
224             throw (IOException) e.getTargetException();
225         }
226     }
227 
228     /**
229      * @return true in case of Java 7.
230      */
231     public static boolean isJava7()
232     {
233         return IS_JAVA7;
234     }
235 
236     /**
237      * @return true in case of Java7 or greater.
238      */
239     public static boolean isAtLeastJava7()
240     {
241         return IS_JAVA7;
242     }
243 
244 }