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             * ※ Tomcat8.0.3 ã§ã¯ã€ClassLoader ã® getResources(String)ã§å–å¾—ã™ã‚‹URLåãŒã€?
061             *    /C:/opengionV6/uap/webapps/gf/WEB-INF/classes/org/opengion/plugin/
062             *    ã®å½¢å¼ã§ã€æœ€å¾Œã? "/" ã‚’å–る為ã€filepath.length() - 1 処ç?—ã¦ã?¾ã—ãŸãŒã?
063             *    Tomcat8.0.5 ã§ã¯ã€?C:/opengionV6/uap/webapps/gf/WEB-INF/classes/org/opengion/plugin
064             *    ã®å½¢å¼ã§ã€æœ€å¾Œã? "/" ãŒãªããªã£ã¦ã?¾ã™ã?
065             *    æœ?¾Œã? "/" ãŒã‚ã£ã¦ã‚‚ãªãã¦ã‚‚ã?new File(String) ã§ãƒ?‚£ãƒ¬ã‚¯ãƒˆãƒªã®ã‚ªãƒ–ジェクトを
066             *    作æ?ã§ãã‚‹ãŸã‚ã€filepath.length() ã«å¤‰æ›´ã—ã¾ã™ã?
067             *
068             * @og.rev 4.0.3.0 (2007/01/07) UNIXパス検索時ã?ã€ãƒ•ァイルパスã®å–得方法ã?ä¸å?åˆå¯¾å¿?
069             * @og.rev 5.0.0.0 (2009/08/03) UNIXパス検索時ã?ã€ãƒ•ァイルパスã®å–得方法ã?ä¸å?åˆå¯¾å¿?
070             * @og.rev 5.0.0.0 (2009/08/03) UNIXパス検索時ã?ã€ãƒ•ァイルパスã®å–得方法ã?ä¸å?åˆå¯¾å¿?
071             * @og.rev 5.7.5.0 (2014/04/04) ファイルåã?å–得方法ã?修正
072             *
073             * @param       filepath        対象ã¨ãªã‚‹ãƒ•ァイル群を検索ã™ã‚‹ã€ãƒ•ァイルパス
074             * @param       keyword         検索対象ファイルã®ã‚­ãƒ¼ãƒ¯ãƒ¼ãƒ?
075             */
076    //      public FindClassFiles( final String filepath,final String prefix ) {
077            public FindClassFiles( final String filepath,final String keyword ) {
078                    // jar:file:/実ディレクトリ!å…ˆé?クラス ã¾ãŸã?ã€file:/実ディレクトリ ã¾ãŸã?ã€?実ディレクトリ
079    
080    //              String dir = null;
081                    String dir = filepath;                                                  // 5.5.2.6 (2012/05/25) findbugs対�
082                    if( filepath.startsWith( "jar:" ) || filepath.startsWith( "file:" )
083    //                       || ( filepath.charAt(0) == '/' && filepath.charAt(2) == ':' ) ) {
084                             || ( filepath.charAt(0) == '/' ) ) {           // 4.4.0.0 (2009/08/02)
085                            int stAdrs = filepath.indexOf( '/' );
086                            if( filepath.charAt(stAdrs+2) == ':' ) {        // 4.0.3.0 (2007/01/07)
087                                    stAdrs++;
088                            }
089                            int edAdrs = filepath.lastIndexOf( '!' );
090                            if( edAdrs < 0) {
091    //                              edAdrs = filepath.length() - 1;
092                                    edAdrs = filepath.length();                     // 5.7.5.0 (2014/04/04) æœ?¾Œã? "/" ã¯ã‚ã£ã¦ã‚‚ãªãã¦ã‚‚よã??
093                            }
094                            dir = filepath.substring( stAdrs,edAdrs );
095                    }
096    
097                    File basefile = new File( dir );
098                    String baseFilename = basefile.getAbsolutePath() ;
099    //              baseLen = baseFilename.length() - prefix.length();
100                    baseLen = baseFilename.length() - keyword.length();
101                    findFilename( basefile );
102            }
103    
104            /**
105             * ファイルパスã‚?ドッãƒ?.)ã«ç½®ãæ›ãˆã?.class ã‚’å–り除ã?Ÿå½¢å¼?クラスã®å®Œå?ç³»)ã®æ–?­—å?é…å?
106             *
107             * @return      ãƒ•ã‚¡ã‚¤ãƒ«ãƒ‘ã‚¹ã®æ–?­—å?é…å?
108             */
109            public String[] getFilenames() {
110                    return list.toArray( new String[list.size()] );
111            }
112    
113            /**
114             * ファイルをå?帰çš?«æ¤œç´¢ã—ã¾ã™ã?
115             * æŒ?®šã?ファイルオブジェクト㌠ファイルã®å ´åˆã?ã€?class ã§ã‚れã°Listã«è¿½åŠ?—ã€?
116             * .zip ã?.jar ã§ã¯ã€findJarFiles を呼ã³å‡ºã—ã¾ã™ã?
117             * ファイルã§ãªã??åˆã?ã€??列をå–り出ã—ã?自åˆ??身をå?帰çš?«å‘¼ã³å‡ºã—ã¾ã™ã?
118             *
119             * @param       file    ファイル
120             */
121            private void findFilename( final File file ) {
122                    if( file.isFile() ) {
123                            String name = file.getAbsolutePath();
124                            if( name.endsWith( SUFIX ) ) {
125                                    list.add( name.substring( baseLen,name.length()-SUFIX_LEN ).replace( File.separatorChar,'.' ) );
126                            }
127                            else if( name.endsWith( ".jar" ) || name.endsWith( ".zip" ) ) {
128                                    findJarFiles( name );
129                            }
130                    }
131                    else {
132                            File[] filelist = file.listFiles();
133                            for( int i=0; i<filelist.length; i++ ) {
134                                    findFilename( filelist[i] );
135                            }
136                    }
137            }
138    
139            /**
140             * jar/zipファイルを検索ã—ã¾ã™ã?
141             * 圧縮ファイルã§ã¯ã€?šŽå±¤ã§ã¯ãªãã?Enumeration ã¨ã—ã¦ãƒ•ァイルをå–りå?ã—ã¾ã™ã?
142             * æ‹¡å¼µå­ã§åˆ¤æ–­ã—ã¦ã€Listã«è¿½åŠ?—ã¦ã?ã¾ã™ã?
143             *
144             * @og.rev 5.5.2.6 (2012/05/25) JarFile ã‚’ã?Closer#zipClose( ZipFile ) メソãƒ?ƒ‰ã‚’利用ã—ã¦ã€close ã—ã¾ã™ã?
145             *
146             * @param       filename        ファイルå?
147             */
148            private void findJarFiles( final String filename ) {
149                    // 5.5.2.6 (2012/05/25) findbugs対�
150                    JarFile jarFile = null;
151                    try {
152    //                      JarFile jarFile = new JarFile( filename );
153                            jarFile = new JarFile( filename );
154                            Enumeration<JarEntry> en = jarFile.entries() ;
155                            while( en.hasMoreElements() ) {
156                                    JarEntry ent = en.nextElement();
157                                    if( ! ent.isDirectory() ) {
158                                            String name = ent.getName();
159                                            if( name.endsWith( SUFIX ) ) {
160                                                    list.add( name.substring( 0,name.length()-SUFIX_LEN ).replace( '/','.' ) );
161                                            }
162                                    }
163                            }
164                    }
165                    catch( IOException ex ) {
166                            String errMsg = "ファイル読ã¿å–りストリーãƒ?«å¤±æ•—ã—ã¾ã—ãŸã€?
167                                            + " File=" + filename
168                                            + ex.getMessage();                              // 5.1.8.0 (2010/07/01) errMsg 修正
169                            throw new RuntimeException( errMsg,ex );
170                    }
171                    // 5.5.2.6 (2012/05/25) findbugs対�
172                    finally {
173                            Closer.zipClose( jarFile );
174                    }
175            }
176    
177            /**
178             * サンプルメイン
179             * ã“ã“ã§ã¯ã€å¼•æ•°ã«é€šå¸¸ã®ãƒ•ァイルã§ã¯ãªãã?クラスパスよりå–å¾—ã—ã¾ã™ã?
180             * 通常ã€å–å¾—ã•れãŸãƒ•ァイルåã?ã€ã‚¯ãƒ©ã‚¹ã®å®Œå?ç³»ã®æ–?­—å?ãªã®ã§ã€ã‚¯ãƒ©ã‚¹ãƒ‘スよりå–å¾?
181             * ã—ã¦ã?‚‹é™ã‚Šã€ãã®ã¾ã¾ オブジェクトを構築ã§ãã‚‹ã“ã¨ã‚’æ„味ã—ã¾ã™ã?
182             *
183             * @param       args    引数
184             */
185            public static void main( final String[] args ) {
186                    try {
187                            ClassLoader loader = Thread.currentThread().getContextClassLoader();
188                            Enumeration<URL> enume = loader.getResources( args[0] );  // 4.3.3.6 (2008/11/15) Generics警告対�
189                            while( enume.hasMoreElements() ) {
190                                    URL url = enume.nextElement();          // 4.3.3.6 (2008/11/15) Generics警告対�
191                                    // jar:file:/実ディレクトリ!å…ˆé?クラス ã¾ãŸã?ã€file:/実ディレクトリ
192                                    System.out.println( "url=" + url.getFile() );
193    
194                                    FindClassFiles filenames = new FindClassFiles( url.getFile(),args[0] );
195                                    String[] names = filenames.getFilenames();
196                                    for( int i=0; i<names.length; i++ ) {
197                                            System.out.println( names[i] );
198                                    }
199                            }
200                    }
201                    catch( IOException ex ) {
202                            String errMsg = "ファイル読ã¿å–りストリーãƒ?«å¤±æ•—ã—ã¾ã—ãŸã€?
203                                            + ex.getMessage();
204                            throw new RuntimeException( errMsg,ex );
205                    }
206            }
207    }