001    /*
002     * Copyright (c) 2009 The openGion Project.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013     * either express or implied. See the License for the specific language
014     * governing permissions and limitations under the License.
015     */
016    package org.opengion.fukurou.util;
017    
018    import java.io.IOException;
019    import java.io.File;
020    
021    import java.util.List;
022    import java.util.ArrayList;
023    import java.util.Enumeration;
024    import java.util.jar.JarFile;
025    import java.util.jar.JarEntry;
026    import java.net.URL;
027    
028    /**
029     * こã?クラスは、指定ã?ãƒ?‚£レクトリパスから .class ファイルを検索するクラスですã?
030     * 検索パスは、実ファイルと、zipファイルのå†?ƒ¨、jar ファイルのå†?ƒ¨も含みますã?
031     * 検索結果はã€?class を取り除きã?ファイルパスをã?すべてドッãƒ?.)に変換した形式にしますã?
032     * これは、ほとんどクラスのフルパスæ–?­—å?に相当しますã?
033     * ここで取得されたファイル名よりã?実クラスオブジェクトã?作æ?が可能になりますã?
034     *
035     * こã?クラスの main メソãƒ?ƒ‰は、クラスパスからæŒ?®šã?名前を持つクラス以下ã?ãƒ?‚£レクトリより
036     * ファイルを検索しますã?通常、このクラスの使ã�?–¹として、取得したクラスファイルå�?æ–?­—å?)
037     * から、引数なしコンストラクタを呼び出して、実オブジェクトを生æ?させるã?でã€??常のフォルãƒ?
038     * から検索するより、クラスパスå†?�‹ら検索するペã?スが多いため、サンプルをそのように設å®?
039     * してã�?�¾すã?
040     *
041     * @og.rev 4.0.0.0 (2004/12/31) 新規作æ?
042     * @og.group 初期åŒ?
043     *
044     * @version  4.0
045     * @author   Kazuhiko Hasegawa
046     * @since    JDK5.0,
047     */
048    public final class FindClassFiles {
049            private final List<String> list = new ArrayList<String>();
050            private final int    baseLen;
051    
052            private static final String SUFIX     = ".class" ;
053            private static final int    SUFIX_LEN = SUFIX.length();
054    
055            /**
056             * 検索パスを指定して構築するã?コンストラクタですã?
057             * ここで見つかったパス以下ã? classファイル(拡張子ã?小文字でã€?class )を検索しますã?
058             * こã?ファイル名ã? ファイルパスã‚?ドッãƒ?.)に置き換えã?.class を取り除ã�?�Ÿ格納しておきますã?
059             *
060             * @og.rev 4.0.3.0 (2007/01/07) UNIXパス検索時ã?、ファイルパスの取得方法ã?不å?合対å¿?
061             * @og.rev 5.0.0.0 (2009/08/03) UNIXパス検索時ã?、ファイルパスの取得方法ã?不å?合対å¿?
062             *
063             * @param       filepath        対象となるファイル群を検索する、ファイルパス
064             * @param       prefix  検索対象ファイルのプレフィãƒ?‚¯ス
065             */
066            public FindClassFiles( final String filepath,final String prefix ) {
067                    // jar:file:/実ディレクトリ!先é?クラス またã?、file:/実ディレクトリ
068    
069    //              String dir = null;
070                    String dir = filepath;          // 5.5.2.6 (2012/05/25) findbugs対å¿?
071                    if( filepath.startsWith( "jar:" ) || filepath.startsWith( "file:" )
072    //                       || ( filepath.charAt(0) == '/' && filepath.charAt(2) == ':' ) ) {
073                             || ( filepath.charAt(0) == '/' ) ) { // 4.4.0.0 (2009/08/02)
074                            int stAdrs = filepath.indexOf( '/' );
075                            if( filepath.charAt(stAdrs+2) == ':' ) { // 4.0.3.0 (2007/01/07)
076                                    stAdrs++;
077                            }
078                            int edAdrs = filepath.lastIndexOf( '!' );
079                            if( edAdrs < 0) {
080                                    edAdrs = filepath.length() - 1;
081                            }
082    
083                            dir = filepath.substring( stAdrs,edAdrs );
084                    }
085    
086                    File basefile = new File( dir );
087                    String baseFilename = basefile.getAbsolutePath() ;
088                    baseLen = baseFilename.length() - prefix.length();
089                    findFilename( basefile );
090            }
091    
092            /**
093             * ファイルパスã‚?ドッãƒ?.)に置き換えã?.class を取り除ã�?�Ÿ形å¼?クラスの完å?系)のæ–?­—å?配å?
094             *
095             * @return      ファイルパスのæ–?­—å?配å?
096             */
097            public String[] getFilenames() {
098                    return list.toArray( new String[list.size()] );
099            }
100    
101            /**
102             * ファイルをå?帰çš?�«検索しますã?
103             * æŒ?®šã?ファイルオブジェクトが ファイルの場合ã?ã€?class であればListに追åŠ?�—ã€?
104             * .zip ã�?.jar では、findJarFiles を呼び出しますã?
105             * ファイルでなã�??合ã?ã€??列を取り出しã?自åˆ??身をå?帰çš?�«呼び出しますã?
106             *
107             * @param       file    ファイル
108             */
109            private void findFilename( final File file ) {
110                    if( file.isFile() ) {
111                            String name = file.getAbsolutePath();
112                            if( name.endsWith( SUFIX ) ) {
113                                    list.add( name.substring( baseLen,name.length()-SUFIX_LEN ).replace( File.separatorChar,'.' ) );
114                            }
115                            else if( name.endsWith( ".jar" ) || name.endsWith( ".zip" ) ) {
116                                    findJarFiles( name );
117                            }
118                    }
119                    else {
120                            File[] filelist = file.listFiles();
121                            for( int i=0; i<filelist.length; i++ ) {
122                                    findFilename( filelist[i] );
123                            }
124                    }
125            }
126    
127            /**
128             * jar/zipファイルを検索しますã?
129             * 圧縮ファイルではã€?šŽ層ではなくã?Enumeration としてファイルを取りå?しますã?
130             * 拡張子で判断して、Listに追åŠ?�—てã�?��ますã?
131             *
132             * @og.rev 5.5.2.6 (2012/05/25) JarFile をã?Closer#zipClose( ZipFile ) メソãƒ?ƒ‰を利用して、close しますã?
133             *
134             * @param       filename        ファイルå�?
135             */
136            private void findJarFiles( final String filename ) {
137                    // 5.5.2.6 (2012/05/25) findbugs対å¿?
138                    JarFile jarFile = null;
139                    try {
140    //                      JarFile jarFile = new JarFile( filename );
141                            jarFile = new JarFile( filename );
142                            Enumeration<JarEntry> en = jarFile.entries() ;
143                            while( en.hasMoreElements() ) {
144                                    JarEntry ent = en.nextElement();
145                                    if( ! ent.isDirectory() ) {
146                                            String name = ent.getName();
147                                            if( name.endsWith( SUFIX ) ) {
148                                                    list.add( name.substring( 0,name.length()-SUFIX_LEN ).replace( '/','.' ) );
149                                            }
150                                    }
151                            }
152                    }
153                    catch( IOException ex ) {
154                            String errMsg = "ファイル読み取りストリーãƒ?�«失敗しましたã€?
155                                            + " File=" + filename
156                                            + ex.getMessage();                              // 5.1.8.0 (2010/07/01) errMsg 修正
157                            throw new RuntimeException( errMsg,ex );
158                    }
159                    // 5.5.2.6 (2012/05/25) findbugs対å¿?
160                    finally {
161                            Closer.zipClose( jarFile );
162                    }
163            }
164    
165            /**
166             * サンプルメイン
167             * ここでは、引数に通常のファイルではなくã?クラスパスより取得しますã?
168             * 通常、取得されたファイル名ã?、クラスの完å?系のæ–?­—å?なので、クラスパスより取å¾?
169             * してã�?‚‹限り、そのまま オブジェクトを構築できることを意味しますã?
170             *
171             * @param       args    引数
172             */
173            public static void main( final String[] args ) {
174                    try {
175                            ClassLoader loader = Thread.currentThread().getContextClassLoader();
176                            Enumeration<URL> enume = loader.getResources( args[0] );  // 4.3.3.6 (2008/11/15) Generics警告対å¿?
177                            while( enume.hasMoreElements() ) {
178                                    URL url = enume.nextElement();          // 4.3.3.6 (2008/11/15) Generics警告対å¿?
179                                    // jar:file:/実ディレクトリ!先é?クラス またã?、file:/実ディレクトリ
180                                    System.out.println( "url=" + url.getFile() );
181    
182                                    FindClassFiles filenames = new FindClassFiles( url.getFile(),args[0] );
183                                    String[] names = filenames.getFilenames();
184                                    for( int i=0; i<names.length; i++ ) {
185                                            System.out.println( names[i] );
186                                    }
187                            }
188                    }
189                    catch( IOException ex ) {
190                            String errMsg = "ファイル読み取りストリーãƒ?�«失敗しましたã€?
191                                            + ex.getMessage();
192                            throw new RuntimeException( errMsg,ex );
193                    }
194            }
195    }