/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.flex.compiler.internal.graph;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.commons.io.FileUtils;
import org.apache.flex.compiler.clients.problems.ProblemQuery;
import org.apache.flex.compiler.internal.driver.js.goog.JSGoogConfiguration;
import org.apache.flex.compiler.problems.FileNotFoundProblem;
import com.google.common.io.Files;
public class GoogDepsWriter {
public GoogDepsWriter(File outputFolder, String mainClassName, JSGoogConfiguration config)
{
this.outputFolderPath = outputFolder.getAbsolutePath();
this.mainName = mainClassName;
otherPaths = config.getSDKJSLib();
}
private ProblemQuery problems;
private String outputFolderPath;
private String mainName;
private List<String> otherPaths;
private boolean problemsFound = false;
private HashMap<String,GoogDep> depMap = new HashMap<String,GoogDep>();
public ArrayList<String> getListOfFiles() throws InterruptedException
{
buildDB();
ArrayList<GoogDep> dps = sort(mainName);
ArrayList<String> files = new ArrayList<String>();
for (GoogDep gd : dps)
{
files.add(gd.filePath);
}
return files;
}
public boolean generateDeps(ProblemQuery problems, StringBuilder depsFileData) throws InterruptedException, FileNotFoundException
{
problemsFound = false;
this.problems = problems;
buildDB();
ArrayList<GoogDep> dps = sort(mainName);
String outString = "// generated by FalconJS" + "\n";
int n = dps.size();
for (int i = n - 1; i >= 0; i--)
{
GoogDep gd = dps.get(i);
if (!isGoogClass(gd.className))
{
String s = "goog.addDependency('";
s += relativePath(gd.filePath);
s += "', ['";
s += gd.className;
s += "'], [";
s += getDependencies(gd.deps);
s += "]);\n";
outString += s;
}
}
depsFileData.append(outString);
return !problemsFound;
}
private boolean isGoogClass(String className)
{
return className.startsWith("goog.");
}
private void buildDB()
{
addDeps(mainName);
}
public ArrayList<String> filePathsInOrder = new ArrayList<String>();
public ArrayList<String> additionalHTML = new ArrayList<String>();
private HashMap<String, GoogDep> visited = new HashMap<String, GoogDep>();
private ArrayList<GoogDep> sort(String rootClassName)
{
ArrayList<GoogDep> arr = new ArrayList<GoogDep>();
GoogDep current = depMap.get(rootClassName);
sortFunction(current, arr);
return arr;
}
private void sortFunction(GoogDep current, ArrayList<GoogDep> arr)
{
visited.put(current.className, current);
filePathsInOrder.add(current.filePath);
System.out.println("Dependencies calculated for '" + current.filePath + "'");
ArrayList<String> deps = current.deps;
for (String className : deps)
{
if (!visited.containsKey(className) && !isGoogClass(className))
{
GoogDep gd = depMap.get(className);
sortFunction(gd, arr);
}
}
arr.add(current);
}
private void addDeps(String className)
{
if (depMap.containsKey(className) || isGoogClass(className))
return;
// build goog dependency list
GoogDep gd = new GoogDep();
gd.className = className;
gd.filePath = getFilePath(className);
depMap.put(gd.className, gd);
ArrayList<String> deps = getDirectDependencies(gd.filePath);
gd.deps = new ArrayList<String>();
ArrayList<String> circulars = new ArrayList<String>();
for (String dep : deps)
{
if (depMap.containsKey(dep) && !isGoogClass(dep))
{
circulars.add(dep);
continue;
}
gd.deps.add(dep);
}
for (String dep : deps)
{
addDeps(dep);
}
if (circulars.size() > 0)
{
// remove requires that would cause circularity
try
{
List<String> fileLines = Files.readLines(new File(gd.filePath), Charset.defaultCharset());
ArrayList<String> finalLines = new ArrayList<String>();
String inherits = getBaseClass(fileLines, className);
for (String line : fileLines)
{
int c = line.indexOf("goog.require");
if (c > -1)
{
int c2 = line.indexOf(")");
String s = line.substring(c + 14, c2 - 1);
if (circulars.contains(s) && !s.equals(inherits))
continue;
}
finalLines.add(line);
}
File file = new File(gd.filePath);
PrintWriter out = new PrintWriter(new FileWriter(file));
for (String s : finalLines)
{
out.println(s);
}
out.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
String getBaseClass(List<String> lines, String className)
{
int n = lines.size();
for (int i = 0; i < n; i++)
{
String line = lines.get(i);
int c2;
int c = line.indexOf("goog.inherits");
if (c > -1)
{
String inheritLine = "";
while (true)
{
inheritLine += line;
c2 = line.indexOf(")");
if (c2 > -1)
break;
else
{
i++;
line = lines.get(i);
}
}
c = inheritLine.indexOf(",");
c2 = inheritLine.indexOf(")");
return inheritLine.substring(c + 1, c2).trim();
}
}
return null;
}
String getFilePath(String className)
{
String fn;
File destFile;
File f;
String classPath = className.replace(".", File.separator);
fn = outputFolderPath + File.separator + classPath + ".js";
f = new File(fn);
if (f.exists())
{
return fn;
}
for (String otherPath : otherPaths)
{
fn = otherPath + File.separator + classPath + ".js";
f = new File(fn);
if (f.exists())
{
fn = outputFolderPath + File.separator + classPath + ".js";
destFile = new File(fn);
// copy source to output
try {
FileUtils.copyFile(f, destFile);
// (erikdebruin) copy class assets files
if (className.indexOf("org.apache.flex") > -1)
{
File assetsDir = new File(f.getParentFile(), "assets");
if (assetsDir.exists())
{
String nameOfClass = className.substring(className.lastIndexOf('.') + 1);
File[] assetsList = assetsDir.listFiles();
for (int i = 0; i < assetsList.length; i++)
{
File assetFile = assetsList[i];
String assetFileName = assetFile.getName();
if (assetFile.isFile() && assetFileName.indexOf(nameOfClass) == 0)
{
String pathOfClass = "";
pathOfClass = className.substring(0, className.lastIndexOf('.'));
pathOfClass = pathOfClass.replace(".", File.separator);
destFile = new File(outputFolderPath +
File.separator + pathOfClass +
File.separator + "assets" +
File.separator + assetFileName);
FileUtils.copyFile(assetFile, destFile);
destFile = new File(outputFolderPath.replace("js-debug", "js-release") +
File.separator + pathOfClass +
File.separator + "assets" +
File.separator + assetFileName);
FileUtils.copyFile(assetFile, destFile);
System.out.println("Copied assets of the '" + nameOfClass + "' class");
}
}
}
}
} catch (IOException e) {
System.out.println("Error copying file for class: " + className);
}
return fn;
}
}
System.out.println("Could not find file for class: " + className);
problems.add(new FileNotFoundProblem(className));
problemsFound = true;
return "";
}
private ArrayList<String> getDirectDependencies(String fn)
{
ArrayList<String> deps = new ArrayList<String>();
FileInputStream fis;
try {
fis = new FileInputStream(fn);
Scanner scanner = new Scanner(fis, "UTF-8");
boolean inInjectHTML = false;
while (scanner.hasNextLine())
{
String s = scanner.nextLine();
if (s.indexOf("goog.inherits") > -1)
break;
if (inInjectHTML)
{
int c = s.indexOf("</inject_html>");
if (c > -1)
{
inInjectHTML = false;
continue;
}
}
if (inInjectHTML)
{
additionalHTML.add(s);
continue;
}
int c = s.indexOf("goog.require");
if (c > -1)
{
int c2 = s.indexOf(")");
s = s.substring(c + 14, c2 - 1);
deps.add(s);
}
c = s.indexOf("<inject_html>");
if (c > -1)
{
inInjectHTML = true;
}
}
scanner.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return deps;
}
private String getDependencies(ArrayList<String> deps)
{
String s = "";
for (String dep : deps)
{
if (s.length() > 0)
{
s += ", ";
}
s += "'" + dep + "'";
}
return s;
}
String relativePath(String path)
{
if (path.indexOf(outputFolderPath) == 0)
{
path = path.replace(outputFolderPath, "../../..");
}
else
{
for (String otherPath : otherPaths)
{
if (path.indexOf(otherPath) == 0)
{
path = path.replace(otherPath, "../../..");
}
}
}
// paths are actually URIs and always have forward slashes
path = path.replace('\\', '/');
return path;
}
private class GoogDep
{
public String filePath;
public String className;
public ArrayList<String> deps;
}
}