OSDN Git Service

Merge branch 'Branch_release-'
[jindolf/Jindolf.git] / src / main / java / jp / sfjp / jindolf / config / FileUtils.java
-/*\r
- * file utilities\r
- *\r
- * Copyright(c) 2009 olyutorskii\r
- * $Id: FileUtils.java 952 2009-12-06 14:29:10Z olyutorskii $\r
- */\r
-\r
-package jp.sourceforge.jindolf;\r
-\r
-import java.io.File;\r
-import java.lang.reflect.InvocationTargetException;\r
-import java.lang.reflect.Method;\r
-import java.lang.reflect.Modifier;\r
-import java.net.URI;\r
-import java.net.URISyntaxException;\r
-import java.net.URL;\r
-import java.security.CodeSource;\r
-import java.security.ProtectionDomain;\r
-import java.util.Locale;\r
-\r
-/**\r
- * 諸々のファイル操作ユーティリティ。\r
- * JRE1.6 API へのリフレクションアクセスを含む。\r
- */\r
-public final class FileUtils{\r
-\r
-    private static final String SCHEME_FILE = "file";\r
-\r
-    /** JRE1.6のjava.io.File#setReadableに相当。 */\r
-    private static final Method METHOD_SETREADABLE;\r
-    /** JRE1.6のjava.io.File#setWritableに相当。 */\r
-    private static final Method METHOD_SETWRITABLE;\r
-    /** Locale.ROOT代替品。 */\r
-    private static final Locale ROOT = new Locale("", "", "");\r
-\r
-    static{\r
-        Method method;\r
-        int modifiers;\r
-\r
-        try{\r
-            method = File.class.getMethod(\r
-                    "setReadable", Boolean.TYPE, Boolean.TYPE);\r
-            modifiers = method.getModifiers();\r
-            if( ! Modifier.isPublic(modifiers) ){\r
-                method = null;\r
-            }\r
-        }catch(NoSuchMethodException e){\r
-            method = null;\r
-        }catch(SecurityException e){\r
-            method = null;\r
-        }\r
-        METHOD_SETREADABLE = method;\r
-\r
-        try{\r
-            method = File.class.getMethod(\r
-                    "setWritable", Boolean.TYPE, Boolean.TYPE);\r
-            modifiers = method.getModifiers();\r
-            if( ! Modifier.isPublic(modifiers) ){\r
-                method = null;\r
-            }\r
-        }catch(NoSuchMethodException e){\r
-            method = null;\r
-        }catch(SecurityException e){\r
-            method = null;\r
-        }\r
-        METHOD_SETWRITABLE = method;\r
-\r
-        assert ! ( isMacOSXFs() && isWindowsOSFs() );\r
-    }\r
-\r
-    /**\r
-     * なるべく自分にだけ許可を与え自分以外には許可を与えないように\r
-     * ファイル属性を操作する。\r
-     * @param method setReadableかsetWritableのいずれかのメソッド。\r
-     * nullならなにもしない。\r
-     * @param file 操作対象のファイル。\r
-     * @return 成功すればtrue\r
-     * @throws SecurityException セキュリティ上の許可が無い場合\r
-     */\r
-    private static boolean invokeOwnerOnly(Method method, File file)\r
-            throws SecurityException{\r
-        if(method == null) return false;\r
-        if(file == null) throw new NullPointerException();\r
-\r
-        Object result1;\r
-        Object result2;\r
-        try{\r
-            result1 = method.invoke(file, false, false);\r
-            result2 = method.invoke(file, true,  true);\r
-        }catch(IllegalAccessException e){\r
-            assert false;\r
-            return false;\r
-        }catch(IllegalArgumentException e){\r
-            assert false;\r
-            return false;\r
-        }catch(ExceptionInInitializerError e){\r
-            assert false;\r
-            return false;\r
-        }catch(InvocationTargetException e){\r
-            Throwable cause = e.getCause();\r
-            if(cause instanceof SecurityException){\r
-                throw (SecurityException) cause;\r
-            }else if(cause instanceof RuntimeException){\r
-                throw (RuntimeException) cause;\r
-            }else if(cause instanceof Error){\r
-                throw (Error) cause;\r
-            }else{\r
-                assert false;\r
-            }\r
-            return false;\r
-        }\r
-\r
-        assert result1 instanceof Boolean;\r
-        assert result2 instanceof Boolean;\r
-        Boolean bresult1 = (Boolean) result1;\r
-        Boolean bresult2 = (Boolean) result2;\r
-\r
-        return bresult1 && bresult2;\r
-    }\r
-\r
-    /**\r
-     * なるべく自分にだけ読み書き許可を与え\r
-     * 自分以外には読み書き許可を与えないように\r
-     * ファイル属性を操作する。\r
-     * JRE1.6環境でなければなにもしない。\r
-     * @param file 操作対象ファイル\r
-     * @return 成功すればtrue\r
-     * @throws SecurityException セキュリティ上の許可が無い場合\r
-     */\r
-    public static boolean setOwnerOnlyAccess(File file)\r
-            throws SecurityException{\r
-        boolean readresult  = invokeOwnerOnly(METHOD_SETREADABLE, file);\r
-        boolean writeresult = invokeOwnerOnly(METHOD_SETWRITABLE, file);\r
-        return readresult & writeresult;\r
-    }\r
-\r
-    /**\r
-     * 任意の絶対パスの祖先の内、存在するもっとも近い祖先を返す。\r
-     * @param file 任意の絶対パス\r
-     * @return 存在するもっとも近い祖先。一つも存在しなければnull。\r
-     * @throws IllegalArgumentException 引数が絶対パスでない\r
-     */\r
-    public static File findExistsAncestor(File file)\r
-            throws IllegalArgumentException{\r
-        if(file == null) return null;\r
-        if( ! file.isAbsolute() ) throw new IllegalArgumentException();\r
-        if(file.exists()) return file;\r
-        File parent = file.getParentFile();\r
-        return findExistsAncestor(parent);\r
-    }\r
-\r
-    /**\r
-     * 任意の絶対パスのルートファイルシステムもしくはドライブレターを返す。\r
-     * @param file 任意の絶対パス\r
-     * @return ルートファイルシステムもしくはドライブレター\r
-     * @throws IllegalArgumentException 引数が絶対パスでない\r
-     */\r
-    public static File findRootFile(File file)\r
-            throws IllegalArgumentException{\r
-        if( ! file.isAbsolute() ) throw new IllegalArgumentException();\r
-        File parent = file.getParentFile();\r
-        if(parent == null) return file;\r
-        return findRootFile(parent);\r
-    }\r
-\r
-    /**\r
-     * 相対パスの絶対パス化を試みる。\r
-     * @param file 対象パス\r
-     * @return 絶対パス。絶対化に失敗した場合は元の引数。\r
-     */\r
-    public static File supplyFullPath(File file){\r
-        if(file.isAbsolute()) return file;\r
-\r
-        File absFile;\r
-\r
-        try{\r
-            absFile = file.getAbsoluteFile();\r
-        }catch(SecurityException e){\r
-            return file;\r
-        }\r
-\r
-        return absFile;\r
-    }\r
-\r
-    /**\r
-     * 任意のディレクトリがアクセス可能な状態にあるか判定する。\r
-     * アクセス可能の条件を満たすためには、与えられたパスが\r
-     * 存在し、\r
-     * かつディレクトリであり、\r
-     * かつ読み込み可能であり、\r
-     * かつ書き込み可能\r
-     * でなければならない。\r
-     * @param path 任意のディレクトリ\r
-     * @return アクセス可能ならtrue\r
-     */\r
-    public static boolean isAccessibleDirectory(File path){\r
-        if(path == null) return false;\r
-\r
-        if( ! path.exists() )      return false;\r
-        if( ! path.isDirectory() ) return false;\r
-        if( ! path.canRead() )     return false;\r
-        if( ! path.canWrite() )    return false;\r
-\r
-        return true;\r
-    }\r
-\r
-    /**\r
-     * クラスがローカルファイルからロードされたのであれば\r
-     * そのファイルを返す。\r
-     * @param klass 任意のクラス\r
-     * @return ロード元ファイル。見つからなければnull。\r
-     */\r
-    public static File getClassSourceFile(Class<?> klass){\r
-        ProtectionDomain domain;\r
-        try{\r
-            domain = klass.getProtectionDomain();\r
-        }catch(SecurityException e){\r
-            return null;\r
-        }\r
-\r
-        CodeSource src = domain.getCodeSource();\r
-\r
-        URL location = src.getLocation();\r
-        String scheme = location.getProtocol();\r
-        if( ! scheme.equals(SCHEME_FILE) ) return null;\r
-\r
-        URI uri;\r
-        try{\r
-            uri = location.toURI();\r
-        }catch(URISyntaxException e){\r
-            assert false;\r
-            return null;\r
-        }\r
-\r
-        File file = new File(uri);\r
-\r
-        return file;\r
-    }\r
-\r
-    /**\r
-     * すでに存在するJARファイルか判定する。\r
-     * @param file 任意のファイル\r
-     * @return すでに存在するJARファイルであればtrue\r
-     */\r
-    public static boolean isExistsJarFile(File file){\r
-        if(file == null) return false;\r
-        if( ! file.exists() ) return false;\r
-        if( ! file.isFile() ) return false;\r
-\r
-        String name = file.getName();\r
-        if( ! name.matches("^.+\\.[jJ][aA][rR]$") ) return false;\r
-\r
-        // TODO ファイル先頭マジックナンバーのテストも必要?\r
-\r
-        return true;\r
-    }\r
-\r
-    /**\r
-     * クラスがローカルJARファイルからロードされたのであれば\r
-     * その格納ディレクトリを返す。\r
-     * @param klass 任意のクラス\r
-     * @return ロード元JARファイルの格納ディレクトリ。\r
-     * JARが見つからない、もしくはロード元がJARファイルでなければnull。\r
-     */\r
-    public static File getJarDirectory(Class<?> klass){\r
-        File jarFile = getClassSourceFile(klass);\r
-        if(jarFile == null) return null;\r
-\r
-        if( ! isExistsJarFile(jarFile) ){\r
-            return null;\r
-        }\r
-\r
-        return jarFile.getParentFile();\r
-    }\r
-\r
-    /**\r
-     * ホームディレクトリを得る。\r
-     * システムプロパティuser.homeで示されたホームディレクトリを返す。\r
-     * @return ホームディレクトリ。何らかの事情でnullを返す場合もあり。\r
-     */\r
-    public static File getHomeDirectory(){\r
-        String homeProp;\r
-        try{\r
-            homeProp = System.getProperty("user.home");\r
-        }catch(SecurityException e){\r
-            return null;\r
-        }\r
-\r
-        File homeFile = new File(homeProp);\r
-\r
-        return homeFile;\r
-    }\r
-\r
-    /**\r
-     * MacOSX環境か否か判定する。\r
-     * @return MacOSX環境ならtrue\r
-     */\r
-    public static boolean isMacOSXFs(){\r
-        if(File.separatorChar != '/') return false;\r
-\r
-        String osName;\r
-        try{\r
-            osName = System.getProperty("os.name");\r
-        }catch(SecurityException e){\r
-            return false;\r
-        }\r
-\r
-        if(osName == null) return false;\r
-\r
-        osName = osName.toLowerCase(ROOT);\r
-\r
-        if(osName.startsWith("mac os x")){\r
-            return true;\r
-        }\r
-\r
-        return false;\r
-    }\r
-\r
-    /**\r
-     * Windows環境か否か判定する。\r
-     * @return Windows環境ならtrue\r
-     */\r
-    public static boolean isWindowsOSFs(){\r
-        if(File.separatorChar != '\\') return false;\r
-\r
-        String osName;\r
-        try{\r
-            osName = System.getProperty("os.name");\r
-        }catch(SecurityException e){\r
-            return false;\r
-        }\r
-\r
-        if(osName == null) return false;\r
-\r
-        osName = osName.toLowerCase(ROOT);\r
-\r
-        if(osName.startsWith("windows")){\r
-            return true;\r
-        }\r
-\r
-        return false;\r
-    }\r
-\r
-    /**\r
-     * アプリケーション設定ディレクトリを返す。\r
-     * 存在の有無、アクセスの可否は関知しない。\r
-     * @return アプリケーション設定ディレクトリ\r
-     */\r
-    public static File getAppSetDir(){\r
-        File home = getHomeDirectory();\r
-        if(home == null) return null;\r
-\r
-        File result = home;\r
-\r
-        if(isMacOSXFs()){\r
-            result = new File(result, "Library");\r
-            result = new File(result, "Application Support");\r
-        }\r
-\r
-        // TODO Win環境での%APPDATA%サポート\r
-\r
-        return result;\r
-    }\r
-\r
-    /**\r
-     * ファイル名を表示するためのJLabel用HTML文字列を生成する。\r
-     * Windows日本語環境では、バックスラッシュ記号が円通貨記号に置換される。\r
-     * @param file 対象ファイル\r
-     * @return HTML文字列断片\r
-     */\r
-    public static String getHtmledFileName(File file){\r
-        String pathName = file.getPath();\r
-\r
-        Locale locale = Locale.getDefault();\r
-        String lang = locale.getLanguage();\r
-\r
-        if( FileUtils.isWindowsOSFs() && lang.equals("ja") ){\r
-            pathName = pathName.replace(File.separator, "&yen;");\r
-        }\r
-\r
-        return "<code>" + pathName + "</code>";\r
-    }\r
-\r
-    /**\r
-     * 隠しコンストラクタ。\r
-     */\r
-    private FileUtils(){\r
-        assert false;\r
-        throw new AssertionError();\r
-    }\r
-\r
-}\r
+/*
+ * file utilities
+ *
+ * License : The MIT License
+ * Copyright(c) 2009 olyutorskii
+ */
+
+package jp.sfjp.jindolf.config;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.security.CodeSource;
+import java.security.ProtectionDomain;
+import java.util.Locale;
+
+/**
+ * 諸々のファイル操作ユーティリティ。
+ */
+public final class FileUtils{
+
+    private static final Class<?> THISKLASS = FileUtils.class;
+
+    private static final String LANG_JA = "ja";
+    private static final String SYSPROP_OSNAME = "os.name";
+    private static final String SCHEME_FILE = "file";
+    private static final String ENTITY_YEN = "&yen;";
+
+    static{
+        assert ! ( isMacOSXFs() && isWindowsOSFs() );
+        new FileUtils().hashCode();
+    }
+
+
+    /**
+     * 隠しコンストラクタ。
+     */
+    private FileUtils(){
+        super();
+        assert this.getClass() == THISKLASS;
+        return;
+    }
+
+
+    /**
+     * なるべく自分にだけ読み書き許可を与え
+     * 自分以外には読み書き許可を与えないように
+     * ファイル属性を操作する。
+     *
+     * @param file 操作対象ファイル
+     * @return 成功すればtrue
+     * @throws SecurityException セキュリティ上の許可が無い場合
+     */
+    public static boolean setOwnerOnlyAccess(File file)
+            throws SecurityException{
+        boolean result = true;
+
+        result &= file.setReadable(false, false);
+        result &= file.setReadable(true,  true);
+
+        result &= file.setWritable(false, false);
+        result &= file.setWritable(true, true);
+
+        return result;
+    }
+
+    /**
+     * 任意の絶対パスの祖先の内、存在するもっとも近い祖先を返す。
+     *
+     * @param file 任意の絶対パス
+     * @return 存在するもっとも近い祖先。一つも存在しなければnull。
+     * @throws IllegalArgumentException 引数が絶対パスでない
+     */
+    public static File findExistsAncestor(File file)
+            throws IllegalArgumentException{
+        if(file == null) return null;
+        if( ! file.isAbsolute() ) throw new IllegalArgumentException();
+        if(file.exists()) return file;
+        File parent = file.getParentFile();
+        return findExistsAncestor(parent);
+    }
+
+    /**
+     * 任意の絶対パスのルートファイルシステムもしくはドライブレターを返す。
+     *
+     * @param file 任意の絶対パス
+     * @return ルートファイルシステムもしくはドライブレター
+     * @throws IllegalArgumentException 引数が絶対パスでない
+     */
+    public static File findRootFile(File file)
+            throws IllegalArgumentException{
+        if( ! file.isAbsolute() ) throw new IllegalArgumentException();
+        File parent = file.getParentFile();
+        if(parent == null) return file;
+        return findRootFile(parent);
+    }
+
+    /**
+     * 相対パスの絶対パス化を試みる。
+     *
+     * @param file 対象パス
+     * @return 絶対パス。絶対化に失敗した場合は元の引数。
+     */
+    public static File supplyFullPath(File file){
+        if(file.isAbsolute()) return file;
+
+        File absFile;
+
+        try{
+            absFile = file.getAbsoluteFile();
+        }catch(SecurityException e){
+            return file;
+        }
+
+        return absFile;
+    }
+
+    /**
+     * 任意のディレクトリがアクセス可能な状態にあるか判定する。
+     *
+     * <p>アクセス可能の条件を満たすためには、与えられたパスが
+     * <ul>
+     * <li>存在し、
+     * <li>かつディレクトリであり、
+     * <li>かつ読み込み可能であり、
+     * <li>かつ書き込み可能
+     * </ul>
+     * でなければならない。
+     *
+     * @param path 任意のディレクトリ
+     * @return アクセス可能ならtrue
+     */
+    public static boolean isAccessibleDirectory(File path){
+        if(path == null) return false;
+
+        boolean result = true;
+
+        if     ( ! path.exists() )      result = false;
+        else if( ! path.isDirectory() ) result = false;
+        else if( ! path.canRead() )     result = false;
+        else if( ! path.canWrite() )    result = false;
+
+        return result;
+    }
+
+    /**
+     * クラスがローカルファイルからロードされたのであれば
+     * そのファイルを返す。
+     *
+     * @param klass 任意のクラス
+     * @return ロード元ファイル。見つからなければnull。
+     */
+    public static File getClassSourceFile(Class<?> klass){
+        ProtectionDomain domain;
+        try{
+            domain = klass.getProtectionDomain();
+        }catch(SecurityException e){
+            return null;
+        }
+
+        CodeSource src = domain.getCodeSource();
+
+        URL location = src.getLocation();
+        String scheme = location.getProtocol();
+        if( ! scheme.equals(SCHEME_FILE) ) return null;
+
+        URI uri;
+        try{
+            uri = location.toURI();
+        }catch(URISyntaxException e){
+            assert false;
+            return null;
+        }
+
+        File file = new File(uri);
+
+        return file;
+    }
+
+    /**
+     * すでに存在するJARファイルか判定する。
+     *
+     * @param file 任意のファイル
+     * @return すでに存在するJARファイルであればtrue
+     */
+    public static boolean isExistsJarFile(File file){
+        if(file == null) return false;
+        if( ! file.exists() ) return false;
+        if( ! file.isFile() ) return false;
+
+        String name = file.getName();
+        if( ! name.matches("^.+\\.[jJ][aA][rR]$") ) return false;
+
+        // TODO ファイル先頭マジックナンバーのテストも必要?
+
+        return true;
+    }
+
+    /**
+     * クラスがローカルJARファイルからロードされたのであれば
+     * その格納ディレクトリを返す。
+     *
+     * @param klass 任意のクラス
+     * @return ロード元JARファイルの格納ディレクトリ。
+     *     JARが見つからない、もしくはロード元がJARファイルでなければnull。
+     */
+    public static File getJarDirectory(Class<?> klass){
+        File jarFile = getClassSourceFile(klass);
+        if(jarFile == null) return null;
+
+        if( ! isExistsJarFile(jarFile) ){
+            return null;
+        }
+
+        return jarFile.getParentFile();
+    }
+
+    /**
+     * このクラスがローカルJARファイルからロードされたのであれば
+     * その格納ディレクトリを返す。
+     *
+     * @return ロード元JARファイルの格納ディレクトリ。
+     *     JARが見つからない、もしくはロード元がJARファイルでなければnull。
+     */
+    public static File getJarDirectory(){
+        return getJarDirectory(THISKLASS);
+    }
+
+    /**
+     * ホームディレクトリを得る。
+     *
+     * <p>システムプロパティuser.homeで示されたホームディレクトリを返す。
+     *
+     * @return ホームディレクトリ。何らかの事情でnullを返す場合もあり。
+     */
+    public static File getHomeDirectory(){
+        String homeProp;
+        try{
+            homeProp = System.getProperty("user.home");
+        }catch(SecurityException e){
+            return null;
+        }
+
+        File homeFile = new File(homeProp);
+
+        return homeFile;
+    }
+
+    /**
+     * MacOSX環境か否か判定する。
+     *
+     * @return MacOSX環境ならtrue
+     */
+    public static boolean isMacOSXFs(){
+        if(File.separatorChar != '/') return false;
+
+        String osName;
+        try{
+            osName = System.getProperty(SYSPROP_OSNAME);
+        }catch(SecurityException e){
+            return false;
+        }
+
+        if(osName == null) return false;
+
+        osName = osName.toLowerCase(Locale.ROOT);
+
+        if(osName.startsWith("mac os x")){
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Windows環境か否か判定する。
+     *
+     * @return Windows環境ならtrue
+     */
+    public static boolean isWindowsOSFs(){
+        if(File.separatorChar != '\\') return false;
+
+        String osName;
+        try{
+            osName = System.getProperty(SYSPROP_OSNAME);
+        }catch(SecurityException e){
+            return false;
+        }
+
+        if(osName == null) return false;
+
+        osName = osName.toLowerCase(Locale.ROOT);
+
+        if(osName.startsWith("windows")){
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * アプリケーション設定ディレクトリを返す。
+     *
+     * <p>存在の有無、アクセスの可否は関知しない。
+     *
+     * <p>WindowsやLinuxではホームディレクトリ。
+     * Mac OS X ではさらにホームディレクトリの下の
+     * "Library/Application Support/"
+     *
+     * @return アプリケーション設定ディレクトリ
+     */
+    public static File getAppSetDir(){
+        File home = getHomeDirectory();
+        if(home == null) return null;
+
+        File result = home;
+
+        if(isMacOSXFs()){
+            result = new File(result, "Library");
+            result = new File(result, "Application Support");
+        }
+
+        // TODO Win環境での%APPDATA%サポート
+
+        return result;
+    }
+
+    /**
+     * ファイル名を表示するためのJLabel用HTML文字列を生成する。
+     *
+     * <p>Windows日本語環境では、バックスラッシュ記号が円通貨記号に置換される。
+     *
+     * @param file 対象ファイル
+     * @return HTML文字列断片
+     */
+    public static String getHtmledFileName(File file){
+        String pathName = file.getPath();
+
+        Locale locale = Locale.getDefault();
+        String lang = locale.getLanguage();
+
+        if( FileUtils.isWindowsOSFs() && lang.equals(LANG_JA) ){
+            pathName = pathName.replace(File.separator, ENTITY_YEN);
+        }
+
+        return "<code>" + pathName + "</code>";
+    }
+
+}