001/****************************************************************************
002 * Copyright/Copyleft:
003 *
004 * For this source the LGPL Lesser General Public License,
005 * published by the Free Software Foundation is valid.
006 * It means:
007 * 1) You can use this source without any restriction for any desired purpose.
008 * 2) You can redistribute copies of this source to everybody.
009 * 3) Every user of this source, also the user of redistribute copies
010 *    with or without payment, must accept this license for further using.
011 * 4) But the LPGL is not appropriate for a whole software product,
012 *    if this source is only a part of them. It means, the user
013 *    must publish this part of source,
014 *    but don't need to publish the whole source of the own product.
015 * 5) You can study and modify (improve) this source
016 *    for own using or for redistribution, but you have to license the
017 *    modified sources likewise under this LGPL Lesser General Public License.
018 *    You mustn't delete this Copyright/Copyleft inscription in this source file.
019 *
020 * @author Hartmut Schorrig: hartmut.schorrig@vishia.de, www.vishia.org
021 * @version 0.93 2011-01-05  (year-month-day)
022 *******************************************************************************/ 
023package org.vishia.java2C;
024
025import java.io.File;
026import java.io.FileFilter;
027import java.text.ParseException;
028import java.util.Iterator;
029import java.util.List;
030
031import org.vishia.mainCmd.Report;
032
033/**This class is a helper to get the java source tree from given class path.
034 * The class may be used only temporary, 
035 * it is wrapped around its method {@link JavaSrcTreeGetter#gatherAllJavaSrcFiles(JavaFolder, List)}.
036 * The usage is (new JavaSrcTreeGetter(report)).captureAllJavaSrcFiles(dst, src).
037 *
038 */
039public class JavaSrcTreeGetter
040{
041
042  /**Version, history and license.
043   * <ul>
044   * <li>2008 Hartmut created:    
045   * </ul>
046   * <br><br>
047   * <b>Copyright/Copyleft</b>:
048   * For this source the LGPL Lesser General Public License,
049   * published by the Free Software Foundation is valid.
050   * It means:
051   * <ol>
052   * <li> You can use this source without any restriction for any desired purpose.
053   * <li> You can redistribute copies of this source to everybody.
054   * <li> Every user of this source, also the user of redistribute copies
055   *    with or without payment, must accept this license for further using.
056   * <li> But the LPGL is not appropriate for a whole software product,
057   *    if this source is only a part of them. It means, the user
058   *    must publish this part of source,
059   *    but don't need to publish the whole source of the own product.
060   * <li> You can study and modify (improve) this source
061   *    for own using or for redistribution, but you have to license the
062   *    modified sources likewise under this LGPL Lesser General Public License.
063   *    You mustn't delete this Copyright/Copyleft inscription in this source file.
064   * </ol>
065   * If you are intent to use this sources without publishing its usage, you can get
066   * a second license subscribing a special contract with the author. 
067   * 
068   * @author Hartmut Schorrig = hartmut.schorrig@vishia.de
069   */
070  public final static String sVersion = "2014-09-05"; 
071
072  private final Report console;
073  
074  private final ConfigSrcPathPkg_ifc inputCfg;
075  
076  /**Aggregation to the Instance, which stores the produced data 
077   * while call of {@link #captureAllJavaSrcFiles(List, JavaSrcTreePkg, List)}.
078   */
079  private final JavaSources dstJavaSrcData;
080  
081  private final List<String> listInputToTranslate;
082  
083  private FileFilter javaFileFilter = new FileFilter(){
084    public boolean accept(File file)
085    { return file.isFile() && file.getName().endsWith(".java");
086      }
087    };
088    
089  private FileFilter dirFilter = new FileFilter(){
090      public boolean accept(File file)
091      { return file.isDirectory();
092      }
093    };
094    
095 
096  /**Constructs an instance, which should be used only temporary to capture the tree.
097   * @param inputCfg Association to the instance, which knows the assignment between Java-Packages and C-Pre- and Suffixes.
098   * @param console
099   */
100  public JavaSrcTreeGetter(JavaSources dstJavaSrcData, ConfigSrcPathPkg_ifc inputCfg, List<String> listInputToTranslate, Report console)
101  {
102    this.console = console;
103    this.inputCfg = inputCfg;
104    this.dstJavaSrcData = dstJavaSrcData;
105    this.listInputToTranslate = listInputToTranslate;
106  }
107
108  /**Captures all Java Files, which are found at file system in all given Java Source pathes
109   * evaluates the content of {@link ConfigSrcPathPkg_ifc} (association given on constructor)
110   * and sets respectively completes the input files.
111   * Uses the {@link #inputCfg} aggregation to get the source path and the package replacement
112   * 
113   * @param javaSrcTree The destination, it should be an empty List before.
114   * @param listJavaSrcpath List of all source pathes. The list won't be changed here.
115   * @param listInputToTranslate List of all sources to translate. The list won't be changed here.
116   * @throws ParseException 
117   */
118  public void gatherAllJavaSrcFiles(LocalIdents identsToAssignFirstPkgIdents, List<String> listJavaSrcpath) throws ParseException
119  { console.reportln(4, "gatherAllJavaSrcFiles");
120          for(String srcPath: listJavaSrcpath){
121        console.reportln(4, "* Folder: " + srcPath);
122        File javaFolder = new File(srcPath);
123      if(!javaFolder.isDirectory()) throw new IllegalArgumentException("Java-Srcpath should be a directory: " + srcPath);
124      File[] firstPkgs = javaFolder.listFiles(dirFilter);
125      for(File firstPkg: firstPkgs){
126        captureAllJavaSrcFilesRecursive(identsToAssignFirstPkgIdents, firstPkg, dstJavaSrcData.javaSrcTree, "", srcPath, false);
127      }
128    }
129    if(console.getReportLevel()>=Report.fineInfo){
130      console.reportln(Report.fineInfo, "===All found Java source files==="); 
131      reportAllJavaSrcFiles(dstJavaSrcData.javaSrcTree);
132    }
133  }
134  
135  
136  /**Captures the package folders and java files of the given file directory level.
137   * Creates a {@link JavaSrcTreeFile} for all found files, but not if the FileInfo
138   * exists already. It exists, if the file is found in another source-path already
139   * or if it is defined in the {@link CRuntimeJavalikeClassData}
140   * or it is defined by a package.file-replacement in the config-file, 
141   * see {@link Java2C_Main#inputCfg}. 
142   * 
143   * @param identsToAssignPkgIdents
144   * @param dirPkg The directory in file tree for package.
145   * @param dstParent write packages and files into it.
146   * @param sPkgPathParent package path with / as separator and at end for the given level
147   * @param javaSrcPath The source path which is captured yet. Path before package tree.
148   * @param bTranslatePkg
149   * @throws ParseException 
150   */
151  private void captureAllJavaSrcFilesRecursive(LocalIdents identsToAssignPkgIdents
152                , File dirPkg, JavaSrcTreePkg dstParent, String sPkgPathParent
153                , String javaSrcPath, boolean bTranslatePkg) throws ParseException
154  { String sNamePkg = dirPkg.getName();
155    String sPkgPath = sPkgPathParent + sNamePkg + "/";    
156    /**Register the package. */
157    JavaSrcTreePkg dstJavaPkg = dstParent.getOrAddPkg(sPkgPath, sNamePkg, null); //, identsToAssignPkgIdents);
158    dstJavaSrcData.indexJavaSrcPkgs.put(sPkgPath, dstJavaPkg);
159    identsToAssignPkgIdents.putClassType(sNamePkg, dstJavaPkg);  //add in LocalIdents
160    /**Check whether the whole package is to translate to C: */
161    { Iterator<String> iter = listInputToTranslate.iterator();
162      while(!bTranslatePkg && iter.hasNext()){
163        String sPkgCheckTranslate = iter.next();
164        if(sPkgCheckTranslate.equals(sPkgPath)){
165          bTranslatePkg = true;
166        }
167      }
168    }  
169    console.reportln(Report.info, "  + Package" + (bTranslatePkg? "-transl:" : ":")+ sPkgPath + " dst:" + dstJavaPkg);
170    /**check packages (directories) */
171    File[] javaPkgs = dirPkg.listFiles(dirFilter);
172    for(File subFolder: javaPkgs){
173      captureAllJavaSrcFilesRecursive(dstJavaPkg.getLocalIdents(""), subFolder, dstJavaPkg, sPkgPath, javaSrcPath, bTranslatePkg);
174    }
175    /**check files */
176    File[] javaFiles = dirPkg.listFiles(javaFileFilter);
177    if(javaFiles.length>0){
178      /**Get prefix and suffix for C-name: */
179      //dstJavaPkg.addStdTypes(Java2C_Main.singleton.standardClassData.stdTypes);
180      if(sPkgPath.equals("org/vishia/java2C/test/"))
181        stop();
182      /**Prefix and suffix from packageReplacement from config file. */
183      final String sFilePrefixPkg, sFileSuffixPkg, sNamePrefixPkg, sNameSuffixPkg;
184      ConfigSrcPathPkg_ifc.Set preSuffixPkg = inputCfg.getCPathPrePostfixForPackage(sPkgPath);
185      if(preSuffixPkg == null){ /**The package is not found in package replacement: */
186        sFilePrefixPkg = "";
187        sFileSuffixPkg = "";
188        sNamePrefixPkg = "";
189        sNameSuffixPkg = "";
190      }
191      else{ /**Use the package replacement: */
192        sFilePrefixPkg = preSuffixPkg.getFilePrefix();
193        sFileSuffixPkg = preSuffixPkg.getFileSuffix();
194        sNamePrefixPkg = preSuffixPkg.getNamePrefix();
195        sNameSuffixPkg = preSuffixPkg.getNameSuffix();
196      }
197      /**Iterate all files: */
198      for(File fileJava: javaFiles){
199        String nameFileJava = fileJava.getName();
200        String nameJava = nameFileJava.substring(0, nameFileJava.length()-5);  //always extension ".java", without it!
201        /**Prefix and suffix from packageReplacement from config file. */
202        final String sFilePrefix, sFileSuffix, sNamePrefix, sNameSuffix;
203        ConfigSrcPathPkg_ifc.Set preSuffix = inputCfg.getCPathPrePostfixForPackage(sPkgPath+nameJava);
204        if(preSuffix == null){ /**The file is not found in file replacement, use package replacement: */
205          preSuffix = preSuffixPkg;
206                sFilePrefix = sFilePrefixPkg;
207          sFileSuffix = sFileSuffixPkg;
208          sNamePrefix = sNamePrefixPkg;
209          sNameSuffix = sNameSuffixPkg;
210        }
211        else{ /**Use the file replacement: */
212          sFilePrefix = preSuffix.getFilePrefix();
213          sFileSuffix = preSuffix.getFileSuffix();
214          sNamePrefix = preSuffix.getNamePrefix();
215          sNameSuffix = preSuffix.getNameSuffix();
216        }
217        //String pathC = sFilePrefix + nameJava + sFileSuffix;
218        /**Check whether it is to translate to C:*/
219        assert(nameFileJava.endsWith(".java"));
220        String sPublicClassName = nameFileJava.substring(0, nameFileJava.length()-5); // without ".java"
221        if(sPublicClassName.equals("AllocInBlock"))
222                stop();
223        String sFullPathName = sPkgPath + sPublicClassName;
224        console.reportln(Report.info, "source: " + sFullPathName);
225        //Check whether the file-info for the found file exists already.
226        //create a JavaSrcTreeFile while checking the sources only if the file isn't known already.
227        JavaSources.ClassDataOrJavaSrcFile javaFile = Java2C_Main.getRootLevelIdents().getTypeInfo(sFullPathName, null);
228        if(javaFile == null){
229          javaFile = Java2C_Main.singleton.standardClassData.stdTypes.getTypeInfo(sPublicClassName, null);
230          if(javaFile != null)
231                stop();
232        }
233        if(javaFile == null){
234          /**If the type is registered already as standard type (at ex from org/vishia/bridgeC), than do not handle.*/
235                console.report(Report.info, ": found in srcTree");
236          javaFile = dstJavaPkg.setFileJava(
237              javaSrcPath, fileJava, nameFileJava, preSuffix, null, false);
238        } else {
239                console.report(Report.info, ": stdType");
240        }
241        boolean bTranslate= bTranslatePkg;
242        if(!bTranslate)
243        { /**Search whether the java-file is to translate: look in the listInputToTranslate. */
244          Iterator<String> iter = listInputToTranslate.iterator();
245          String sFilePathName = sPkgPath + nameFileJava;
246          if(sFilePathName.startsWith("org/vishia/java2C/test"))
247                stop();
248          while(!bTranslate && iter.hasNext()){
249            String sCheckTranslate = iter.next();
250            if(sFilePathName.startsWith(sCheckTranslate)) {
251            //if(sCheckTranslate.startsWith(sFilePathName)){
252              bTranslate = true;
253            }
254          }
255        }  
256        console.report(Report.info, bTranslate ? ": translate" : ": not translate");
257        if(bTranslate){
258                assert(javaFile instanceof JavaSrcTreeFile);
259                JavaSrcTreeFile javaSrc = (JavaSrcTreeFile)javaFile;
260                javaSrc.setToTranslate(fileJava);
261          dstJavaSrcData.listJavaSrcFilesToTranslate.add(javaSrc);
262        }
263        console.reportln(4, "    --File" + (bTranslate? "-transl:" : ":") + javaFile.toString());
264      } 
265    }
266    
267    
268  }
269
270
271  private void reportAllJavaSrcFiles(JavaSrcTreePkg javaPkgParent)
272  {
273    for(JavaSrcTreePkg javaPkg: javaPkgParent.listChildren()){
274      console.reportln(Report.fineInfo, javaPkg.getPkgPath());
275      javaPkg.reportClasses(console);
276      reportAllJavaSrcFiles(javaPkg);
277    }
278  }
279  
280  void stop(){}
281
282}  
283