提交 8265cced 编写于 作者: O ohrstrom

8004658: Add internal smart javac wrapper to solve JEP 139

Reviewed-by: jjg
上级 8ac35cfc
...@@ -29,18 +29,18 @@ ...@@ -29,18 +29,18 @@
# Override this path as needed, either on the command line or in # Override this path as needed, either on the command line or in
# one of the standard user build.properties files (see build.xml) # one of the standard user build.properties files (see build.xml)
# boot.java.home = /opt/jdk/1.6.0 # boot.java.home = /opt/jdk/1.7.0
boot.java = ${boot.java.home}/bin/java boot.java = ${boot.java.home}/bin/java
boot.javac = ${boot.java.home}/bin/javac boot.javac = ${boot.java.home}/bin/javac
boot.javac.source = 6 boot.javac.source = 7
boot.javac.target = 6 boot.javac.target = 7
# This is the JDK used to run the product version of the tools, # This is the JDK used to run the product version of the tools,
# for example, for testing. If you're building a complete JDK, specify that. # for example, for testing. If you're building a complete JDK, specify that.
# Override this path as needed, either on the command line or in # Override this path as needed, either on the command line or in
# one of the standard user build.properties files (see build.xml) # one of the standard user build.properties files (see build.xml)
# target.java.home = /opt/jdk/1.7.0 # target.java.home = /opt/jdk/1.8.0
target.java = ${target.java.home}/bin/java target.java = ${target.java.home}/bin/java
# Version info -- override as needed # Version info -- override as needed
...@@ -161,6 +161,14 @@ javap.tests = \ ...@@ -161,6 +161,14 @@ javap.tests = \
# #
sjavac.includes = \
com/sun/tools/sjavac/
sjavac.tests = \
tools/sjavac
#
# The following files require the latest JDK to be available. # The following files require the latest JDK to be available.
# The API can be provided by using a suitable boot.java.home # The API can be provided by using a suitable boot.java.home
# or by setting import.jdk # or by setting import.jdk
......
...@@ -241,15 +241,15 @@ ...@@ -241,15 +241,15 @@
</target> </target>
<target name="build-bootstrap-tools" <target name="build-bootstrap-tools"
depends="build-bootstrap-javac,build-bootstrap-javadoc,build-bootstrap-doclets,build-bootstrap-javah" depends="build-bootstrap-javac,build-bootstrap-javadoc,build-bootstrap-doclets,build-bootstrap-javah,build-bootstrap-sjavac"
/> />
<target name="build-all-tools" <target name="build-all-tools"
depends="build-javac,build-javadoc,build-doclets,build-javah,build-javap" depends="build-javac,build-javadoc,build-doclets,build-javah,build-javap,build-sjavac"
/> />
<target name="build-all-classes" depends="build-bootstrap-javac,-create-import-jdk-stubs"> <target name="build-all-classes" depends="build-bootstrap-javac,-create-import-jdk-stubs">
<build-classes includes="${javac.includes} ${javadoc.includes} ${doclets.includes} ${javah.includes} ${javap.includes}"/> <build-classes includes="${javac.includes} ${javadoc.includes} ${doclets.includes} ${javah.includes} ${javap.includes} ${sjavac.includes}"/>
</target> </target>
<!-- clean --> <!-- clean -->
...@@ -656,6 +656,40 @@ ...@@ -656,6 +656,40 @@
<target name="javap" depends="build-javap,jtreg-javap,findbugs-javap"/> <target name="javap" depends="build-javap,jtreg-javap,findbugs-javap"/>
<!--
**** sjavac targets.
-->
<target name="build-bootstrap-sjavac"
depends="-def-build-bootstrap-classes,-def-build-bootstrap-jar,-def-build-bootstrap-tool">
<build-bootstrap-classes includes="${sjavac.includes}"/>
<build-bootstrap-jar name="sjavac" includes="${sjavac.includes}"
jarmainclass="com.sun.tools.sjavac.Main"/>
<build-bootstrap-tool name="sjavac"/>
</target>
<target name="build-classes-sjavac" depends="build-classes-javac">
<build-classes includes="${sjavac.includes}"/>
</target>
<target name="build-sjavac" depends="build-classes-sjavac">
<build-jar name="sjavac" includes="${sjavac.includes}"
jarmainclass="com.sun.tools.sjavac.Main"
jarclasspath="sjavac.jar"/>
<build-tool name="sjavac"/>
</target>
<!-- (no javadoc for javap) -->
<target name="jtreg-sjavac" depends="build-sjavac,-def-jtreg">
<jtreg-tool name="sjavac" tests="${sjavac.tests}"/>
</target>
<target name="findbugs-sjavac" depends="build-sjavac,-def-findbugs">
<findbugs-tool name="sjavac"/>
</target>
<target name="sjavac" depends="build-sjavac,jtreg-sjavac,findbugs-sjavac"/>
<!-- <!--
**** Create import JDK stubs. **** Create import JDK stubs.
......
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* The build state class captures the source code and generated artifacts
* from a build. There are usually two build states, the previous one (prev),
* loaded from the javac_state file, and the current one (now).
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class BuildState {
private Map<String,Module> modules = new HashMap<String,Module>();
private Map<String,Package> packages = new HashMap<String,Package>();
private Map<String,Source> sources = new HashMap<String,Source>();
private Map<String,File> artifacts = new HashMap<String,File>();
// Map from package to a set of packages that depend on said package.
private Map<String,Set<String>> dependents = new HashMap<String,Set<String>>();
public Map<String,Module> modules() { return modules; }
public Map<String,Package> packages() { return packages; }
public Map<String,Source> sources() { return sources; }
public Map<String,File> artifacts() { return artifacts; }
public Map<String,Set<String>> dependents() { return dependents; }
/**
* Lookup a module from a name. Create the module if it does
* not exist yet.
*/
public Module lookupModule(String mod) {
Module m = modules.get(mod);
if (m == null) {
m = new Module(mod, "???");
modules.put(mod, m);
}
return m;
}
/**
* Find a module from a given package name. For example:
* The package name "base:java.lang" will fetch the module named "base".
* The package name ":java.net" will fetch the default module.
*/
Module findModuleFromPackageName(String pkg) {
int cp = pkg.indexOf(':');
assert(cp != -1);
String mod = pkg.substring(0, cp);
return lookupModule(mod);
}
/**
* Collect all packages, sources and artifacts for all modules
* into the build state.
*
* @param m The set of modules.
*/
public void collectPackagesSourcesAndArtifacts(Map<String,Module> m) {
modules = m;
// Extract all the found packages.
for (Module i : modules.values()) {
for (Map.Entry<String,Package> j : i.packages().entrySet()) {
Package p = packages.get(j.getKey());
// Check that no two different packages are stored under same name.
assert(p == null || p == j.getValue());
if (p == null) {
p = j.getValue();
packages.put(j.getKey(),j.getValue());
}
for (Map.Entry<String,Source> k : p.sources().entrySet()) {
Source s = sources.get(k.getKey());
// Check that no two different sources are stored under same name.
assert(s == null || s == k.getValue());
if (s == null) {
s = k.getValue();
sources.put(k.getKey(), k.getValue());
}
}
for (Map.Entry<String,File> g : p.artifacts().entrySet()) {
File f = artifacts.get(g.getKey());
// Check that no two artifacts are stored under the same file.
assert(f == null || f == g.getValue());
if (f == null) {
f = g.getValue();
artifacts.put(g.getKey(), g.getValue());
}
}
}
}
}
/**
* Collect all the artifacts of all modules and packages.
*
* @param m The set of modules.
*/
public void collectArtifacts(Map<String,Module> m) {
modules = m;
// Extract all the found packages.
for (Module i : modules.values()) {
for (Map.Entry<String,Package> j : i.packages().entrySet()) {
Package p = packages.get(j.getKey());
// Check that no two different packages are stored under same name.
assert(p == null || p == j.getValue());
p = j.getValue();
packages.put(j.getKey(),j.getValue());
for (Map.Entry<String,File> g : p.artifacts().entrySet()) {
File f = artifacts.get(g.getKey());
// Check that no two artifacts are stored under the same file.
assert(f == null || f == g.getValue());
artifacts.put(g.getKey(), g.getValue());
}
}
}
}
/**
* Calculate the package dependents (ie the reverse of the dependencies).
*/
public void calculateDependents() {
dependents = new HashMap<String,Set<String>>();
for (String s : packages.keySet()) {
Package p = packages.get(s);
for (String d : p.dependencies()) {
Set<String> ss = dependents.get(d);
if (ss == null) {
ss = new HashSet<String>();
dependents.put(d, ss);
}
// Add the dependent information to the global dependent map.
ss.add(s);
Package dp = packages.get(d);
// Also add the dependent information to the package specific map.
// Normally, you do not compile java.lang et al. Therefore
// there are several packages that p depends upon that you
// do not have in your state database. This is perfectly fine.
if (dp != null) {
// But this package did exist in the state database.
dp.addDependent(p.name());
}
}
}
}
/**
* Verify that the setModules method above did the right thing when
* running through the module->package->source structure.
*/
public void checkInternalState(String msg, boolean linkedOnly, Map<String,Source> srcs) {
boolean baad = false;
Map<String,Source> original = new HashMap<String,Source>();
Map<String,Source> calculated = new HashMap<String,Source>();
for (String s : sources.keySet()) {
Source ss = sources.get(s);
if (ss.isLinkedOnly() == linkedOnly) {
calculated.put(s,ss);
}
}
for (String s : srcs.keySet()) {
Source ss = srcs.get(s);
if (ss.isLinkedOnly() == linkedOnly) {
original.put(s,ss);
}
}
if (original.size() != calculated.size()) {
Log.error("INTERNAL ERROR "+msg+" original and calculated are not the same size!");
baad = true;
}
if (!original.keySet().equals(calculated.keySet())) {
Log.error("INTERNAL ERROR "+msg+" original and calculated do not have the same domain!");
baad = true;
}
if (!baad) {
for (String s : original.keySet()) {
Source s1 = original.get(s);
Source s2 = calculated.get(s);
if (s1 == null || s2 == null || !s1.equals(s2)) {
Log.error("INTERNAL ERROR "+msg+" original and calculated have differing elements for "+s);
}
baad = true;
}
}
if (baad) {
for (String s : original.keySet()) {
Source ss = original.get(s);
Source sss = calculated.get(s);
if (sss == null) {
Log.error("The file "+s+" does not exist in calculated tree of sources.");
}
}
for (String s : calculated.keySet()) {
Source ss = calculated.get(s);
Source sss = original.get(s);
if (sss == null) {
Log.error("The file "+s+" does not exist in original set of found sources.");
}
}
}
}
/**
* Load a module from the javac state file.
*/
public Module loadModule(String l) {
Module m = Module.load(l);
modules.put(m.name(), m);
return m;
}
/**
* Load a package from the javac state file.
*/
public Package loadPackage(Module lastModule, String l) {
Package p = Package.load(lastModule, l);
lastModule.addPackage(p);
packages.put(p.name(), p);
return p;
}
/**
* Load a source from the javac state file.
*/
public Source loadSource(Package lastPackage, String l, boolean is_generated) {
Source s = Source.load(lastPackage, l, is_generated);
lastPackage.addSource(s);
sources.put(s.name(), s);
return s;
}
/**
* During an incremental compile we need to copy the old javac state
* information about packages that were not recompiled.
*/
public void copyPackagesExcept(BuildState prev, Set<String> recompiled, Set<String> removed) {
for (String pkg : prev.packages().keySet()) {
// Do not copy recompiled or removed packages.
if (recompiled.contains(pkg) || removed.contains(pkg)) continue;
Module mnew = findModuleFromPackageName(pkg);
Package pprev = prev.packages().get(pkg);
mnew.addPackage(pprev);
}
}
}
/*
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac;
import java.io.*;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
/**
* The clean properties transform should not be necessary.
* Eventually we will cleanup the property file sources in the OpenJDK instead.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class CleanProperties implements Transformer
{
public void setExtra(String e) {
// Any extra information is ignored for clean properties.
}
public void setExtra(String[] a) {
// Any extra information is ignored for clean properties.
}
public boolean transform(Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSrcs,
Map<URI,Set<String>> visibleClasses,
Map<String,Set<String>> oldPackageDependencies,
URI destRoot,
Map<String,Set<URI>> packageArtifacts,
Map<String,Set<String>> packageDependencies,
Map<String,String> packagePublicApis,
int debugLevel,
boolean incremental,
int numCores,
PrintStream out,
PrintStream err)
{
boolean rc = true;
for (String pkgName : pkgSrcs.keySet()) {
String pkgNameF = pkgName.replace('.',File.separatorChar);
for (URI u : pkgSrcs.get(pkgName)) {
File src = new File(u);
boolean r = clean(pkgName, pkgNameF, src, new File(destRoot), debugLevel,
packageArtifacts);
if (r == false) {
rc = false;
}
}
}
return rc;
}
boolean clean(String pkgName, String pkgNameF, File src, File destRoot, int debugLevel,
Map<String,Set<URI>> packageArtifacts)
{
// Load the properties file.
Properties p = new Properties();
try {
p.load(new FileInputStream(src));
} catch (IOException e) {
Log.error("Error reading file "+src.getPath());
return false;
}
// Sort the properties in increasing key order.
List<String> sortedKeys = new ArrayList<String>();
for (Object key : p.keySet()) {
sortedKeys.add((String)key);
}
Collections.sort(sortedKeys);
Iterator<String> keys = sortedKeys.iterator();
// Collect the properties into a string buffer.
StringBuilder data = new StringBuilder();
while (keys.hasNext()) {
String key = keys.next();
data.append(CompileProperties.escape(key)+":"+CompileProperties.escape((String)p.get(key))+"\n");
}
String destFilename = destRoot.getPath()+File.separator+pkgNameF+File.separator+src.getName();
File dest = new File(destFilename);
// Make sure the dest directories exist.
if (!dest.getParentFile().isDirectory()) {
if (!dest.getParentFile().mkdirs()) {
Log.error("Could not create the directory "+dest.getParentFile().getPath());
return false;
}
}
Set<URI> as = packageArtifacts.get(pkgName);
if (as == null) {
as = new HashSet<URI>();
packageArtifacts.put(pkgName, as);
}
as.add(dest.toURI());
if (dest.exists() && dest.lastModified() > src.lastModified()) {
// A cleaned property file exists, and its timestamp is newer than the source.
// Assume that we do not need to clean!
// Thus we are done.
return true;
}
Log.info("Cleaning property file "+pkgNameF+File.separator+src.getName());
try (Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dest)))) {
writer.write(data.toString());
} catch ( IOException e ) {
Log.error("Could not write file "+dest.getPath());
return false;
}
return true;
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac;
import java.net.URI;
import java.util.HashSet;
import java.util.Set;
/**
* A compile chunk is a list of sources/packages to be compiled. Possibly a subset of
* the total number of sources/packages to be compiled for this sjavac invocation.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class CompileChunk implements Comparable<CompileChunk> {
public int numPackages;
public int numDependents;
public Set<URI> srcs = new HashSet<URI>();
public StringBuilder pkgNames = new StringBuilder();
public String pkgFromTos = "";
public int compareTo(CompileChunk c) {
if (numDependents == c.numDependents) return 0;
if (numDependents > c.numDependents) return -1;
return -1;
}
boolean equal(CompileChunk c) {
return numDependents == c.numDependents;
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac;
import java.net.URI;
import java.util.Arrays;
import java.util.Random;
import java.util.Set;
import java.util.Map;
import com.sun.tools.sjavac.server.JavacServer;
import com.sun.tools.sjavac.server.SysInfo;
import java.io.PrintStream;
/**
* This transform compiles a set of packages containing Java sources.
* The compile request is divided into separate sets of source files.
* For each set a separate request thread is dispatched to a javac server
* and the meta data is accumulated. The number of sets correspond more or
* less to the number of cores. Less so now, than it will in the future.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class CompileJavaPackages implements Transformer {
// The current limited sharing of data between concurrent JavaCompilers
// in the server will not give speedups above 3 cores. Thus this limit.
// We hope to improve this in the future.
final static int limitOnConcurrency = 3;
String serverSettings;
public void setExtra(String e) {
serverSettings = e;
}
String[] args;
public void setExtra(String[] a) {
args = a;
}
public boolean transform(Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSources,
Map<URI,Set<String>> visibleClasses,
Map<String,Set<String>> oldPackageDependents,
URI destRoot,
final Map<String,Set<URI>> packageArtifacts,
final Map<String,Set<String>> packageDependencies,
final Map<String,String> packagePubapis,
int debugLevel,
boolean incremental,
int numCores,
PrintStream out,
PrintStream err)
{
boolean rc = true;
boolean concurrentCompiles = true;
// Fetch the id.
String id = Util.extractStringOption("id", serverSettings);
if (id == null || id.equals("")) {
// No explicit id set. Create a random id so that the requests can be
// grouped properly in the server.
id = "id"+(((new Random()).nextLong())&Long.MAX_VALUE);
}
// Only keep portfile and sjavac settings..
String psServerSettings = Util.cleanSubOptions("--server:", Util.set("portfile","sjavac","background","keepalive"), serverSettings);
// Get maximum heap size from the server!
SysInfo sysinfo = JavacServer.connectGetSysInfo(psServerSettings, out, err);
if (sysinfo.numCores == -1) {
Log.error("Could not query server for sysinfo!");
return false;
}
int numMBytes = (int)(sysinfo.maxMemory / ((long)(1024*1024)));
Log.debug("Server reports "+numMBytes+"MiB of memory and "+sysinfo.numCores+" cores");
if (numCores <= 0) {
// Set the requested number of cores to the number of cores on the server.
numCores = sysinfo.numCores;
Log.debug("Number of jobs not explicitly set, defaulting to "+sysinfo.numCores);
} else if (sysinfo.numCores < numCores) {
// Set the requested number of cores to the number of cores on the server.
Log.debug("Limiting jobs from explicitly set "+numCores+" to cores available on server: "+sysinfo.numCores);
numCores = sysinfo.numCores;
} else {
Log.debug("Number of jobs explicitly set to "+numCores);
}
// More than three concurrent cores does not currently give a speedup, at least for compiling the jdk
// in the OpenJDK. This will change in the future.
int numCompiles = numCores;
if (numCores > limitOnConcurrency) numCompiles = limitOnConcurrency;
// Split the work up in chunks to compiled.
int numSources = 0;
for (String s : pkgSrcs.keySet()) {
Set<URI> ss = pkgSrcs.get(s);
numSources += ss.size();
}
int sourcesPerCompile = numSources / numCompiles;
// For 64 bit Java, it seems we can compile the OpenJDK 8800 files with a 1500M of heap
// in a single chunk, with reasonable performance.
// For 32 bit java, it seems we need 1G of heap.
// Number experimentally determined when compiling the OpenJDK.
// Includes space for reasonably efficient garbage collection etc,
// Calculating backwards gives us a requirement of
// 1500M/8800 = 175 KiB for 64 bit platforms
// and 1G/8800 = 119 KiB for 32 bit platform
// for each compile.....
int kbPerFile = 175;
String osarch = System.getProperty("os.arch");
if (osarch.equals("i386")) {
// For 32 bit platforms, assume it is slightly smaller
// because of smaller object headers and pointers.
kbPerFile = 119;
}
int numRequiredMBytes = (kbPerFile*numSources)/1024;
Log.debug("For os.arch "+osarch+" the empirically determined heap required per file is "+kbPerFile+"KiB");
Log.debug("Server has "+numMBytes+"MiB of heap.");
Log.debug("Heuristics say that we need "+numRequiredMBytes+"MiB of heap for all source files.");
// Perform heuristics to see how many cores we can use,
// or if we have to the work serially in smaller chunks.
if (numMBytes < numRequiredMBytes) {
// Ouch, cannot fit even a single compile into the heap.
// Split it up into several serial chunks.
concurrentCompiles = false;
// Limit the number of sources for each compile to 500.
if (numSources < 500) {
numCompiles = 1;
sourcesPerCompile = numSources;
Log.debug("Compiling as a single source code chunk to stay within heap size limitations!");
} else if (sourcesPerCompile > 500) {
// This number is very low, and tuned to dealing with the OpenJDK
// where the source is >very< circular! In normal application,
// with less circularity the number could perhaps be increased.
numCompiles = numSources / 500;
sourcesPerCompile = numSources/numCompiles;
Log.debug("Compiling source as "+numCompiles+" code chunks serially to stay within heap size limitations!");
}
} else {
if (numCompiles > 1) {
// Ok, we can fit at least one full compilation on the heap.
float usagePerCompile = (float)numRequiredMBytes / ((float)numCompiles * (float)0.7);
int usage = (int)(usagePerCompile * (float)numCompiles);
Log.debug("Heuristics say that for "+numCompiles+" concurrent compiles we need "+usage+"MiB");
if (usage > numMBytes) {
// Ouch it does not fit. Reduce to a single chunk.
numCompiles = 1;
sourcesPerCompile = numSources;
// What if the relationship betweem number of compile_chunks and num_required_mbytes
// is not linear? Then perhaps 2 chunks would fit where 3 does not. Well, this is
// something to experiment upon in the future.
Log.debug("Limiting compile to a single thread to stay within heap size limitations!");
}
}
}
Log.debug("Compiling sources in "+numCompiles+" chunk(s)");
// Create the chunks to be compiled.
final CompileChunk[] compileChunks = createCompileChunks(pkgSrcs, oldPackageDependents,
numCompiles, sourcesPerCompile);
if (Log.isDebugging()) {
int cn = 1;
for (CompileChunk cc : compileChunks) {
Log.debug("Chunk "+cn+" for "+id+" ---------------");
cn++;
for (URI u : cc.srcs) {
Log.debug(""+u);
}
}
}
// The return values for each chunked compile.
final int[] rn = new int[numCompiles];
// The requets, might or might not run as a background thread.
final Thread[] requests = new Thread[numCompiles];
final Set<URI> fvisible_sources = visibleSources;
final Map<URI,Set<String>> fvisible_classes = visibleClasses;
long start = System.currentTimeMillis();
for (int i=0; i<numCompiles; ++i) {
final int ii = i;
final CompileChunk cc = compileChunks[i];
// Pass the num_cores and the id (appended with the chunk number) to the server.
final String cleanedServerSettings = psServerSettings+",poolsize="+numCores+",id="+id+"-"+ii;
final PrintStream fout = out;
final PrintStream ferr = err;
requests[ii] = new Thread() {
@Override
public void run() {
rn[ii] = JavacServer.useServer(cleanedServerSettings,
Main.removeWrapperArgs(args),
cc.srcs,
fvisible_sources,
fvisible_classes,
packageArtifacts,
packageDependencies,
packagePubapis,
null,
fout, ferr);
}
};
if (cc.srcs.size() > 0) {
String numdeps = "";
if (cc.numDependents > 0) numdeps = "(with "+cc.numDependents+" dependents) ";
if (!incremental || cc.numPackages > 16) {
String info = "("+cc.pkgFromTos+")";
if (info.equals("( to )")) {
info = "";
}
Log.info("Compiling "+cc.srcs.size()+" files "+numdeps+"in "+cc.numPackages+" packages "+info);
} else {
Log.info("Compiling "+cc.pkgNames+numdeps);
}
if (concurrentCompiles) {
requests[ii].start();
}
else {
requests[ii].run();
// If there was an error, then stop early when running single threaded.
if (rn[i] != 0) {
return false;
}
}
}
}
if (concurrentCompiles) {
// If there are background threads for the concurrent compiles, then join them.
for (int i=0; i<numCompiles; ++i) {
try { requests[i].join(); } catch (InterruptedException e) { }
}
}
// Check the return values.
for (int i=0; i<numCompiles; ++i) {
if (compileChunks[i].srcs.size() > 0) {
if (rn[i] != 0) {
rc = false;
}
}
}
long duration = System.currentTimeMillis() - start;
long minutes = duration/60000;
long seconds = (duration-minutes*60000)/1000;
Log.debug("Compilation of "+numSources+" source files took "+minutes+"m "+seconds+"s");
return rc;
}
/**
* Split up the sources into compile chunks. If old package dependents information
* is available, sort the order of the chunks into the most dependent first!
* (Typically that chunk contains the java.lang package.) In the future
* we could perhaps improve the heuristics to put the sources into even more sensible chunks.
* Now the package are simple sorted in alphabetical order and chunked, then the chunks
* are sorted on how dependent they are.
*
* @param pkgSrcs The sources to compile.
* @param oldPackageDependents Old package dependents, if non-empty, used to sort the chunks.
* @param numCompiles The number of chunks.
* @param sourcesPerCompile The number of sources per chunk.
* @return
*/
CompileChunk[] createCompileChunks(Map<String,Set<URI>> pkgSrcs,
Map<String,Set<String>> oldPackageDependents,
int numCompiles,
int sourcesPerCompile) {
CompileChunk[] compileChunks = new CompileChunk[numCompiles];
for (int i=0; i<compileChunks.length; ++i) {
compileChunks[i] = new CompileChunk();
}
// Now go through the packages and spread out the source on the different chunks.
int ci = 0;
// Sort the packages
String[] packageNames = pkgSrcs.keySet().toArray(new String[0]);
Arrays.sort(packageNames);
String from = null;
for (String pkgName : packageNames) {
CompileChunk cc = compileChunks[ci];
Set<URI> s = pkgSrcs.get(pkgName);
if (cc.srcs.size()+s.size() > sourcesPerCompile && ci < numCompiles-1) {
from = null;
ci++;
cc = compileChunks[ci];
}
cc.numPackages++;
cc.srcs.addAll(s);
// Calculate nice package names to use as information when compiling.
String justPkgName = Util.justPackageName(pkgName);
// Fetch how many packages depend on this package from the old build state.
Set<String> ss = oldPackageDependents.get(pkgName);
if (ss != null) {
// Accumulate this information onto this chunk.
cc.numDependents += ss.size();
}
if (from == null || from.trim().equals("")) from = justPkgName;
cc.pkgNames.append(justPkgName+"("+s.size()+") ");
cc.pkgFromTos = from+" to "+justPkgName;
}
// If we are compiling serially, sort the chunks, so that the chunk (with the most dependents) (usually the chunk
// containing java.lang.Object, is to be compiled first!
// For concurrent compilation, this does not matter.
Arrays.sort(compileChunks);
return compileChunks;
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac;
import java.io.*;
import java.net.URI;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
/**
* Compile properties transform a properties file into a Java source file.
* Java has built in support for reading properties from either a text file
* in the source or a compiled java source file.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class CompileProperties implements Transformer
{
// Any extra information passed from the command line, for example if:
// -tr .proppp=com.sun.tools.javac.smart.CompileProperties,sun.util.resources.LocaleNamesBundle
// then extra will be "sun.util.resources.LocaleNamesBundle"
String extra;
public void setExtra(String e) {
extra = e;
}
public void setExtra(String[] a) {
}
public boolean transform(Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSrcs,
Map<URI,Set<String>> visibleClasses,
Map<String,Set<String>> oldPackageDependents,
URI destRoot,
Map<String,Set<URI>> packageArtifacts,
Map<String,Set<String>> packageDependencies,
Map<String,String> packagePublicApis,
int debugLevel,
boolean incremental,
int numCores,
PrintStream out,
PrintStream err) {
boolean rc = true;
for (String pkgName : pkgSrcs.keySet()) {
String pkgNameF = Util.toFileSystemPath(pkgName);
for (URI u : pkgSrcs.get(pkgName)) {
File src = new File(u);
boolean r = compile(pkgName, pkgNameF, src, new File(destRoot), debugLevel,
packageArtifacts);
if (r == false) {
rc = false;
}
}
}
return rc;
}
boolean compile(String pkgName, String pkgNameF, File src, File destRoot, int debugLevel,
Map<String,Set<URI>> packageArtifacts)
{
String superClass = "java.util.ListResourceBundle";
if (extra != null) {
superClass = extra;
}
// Load the properties file.
Properties p = new Properties();
try {
p.load(new FileInputStream(src));
} catch (IOException e) {
Log.error("Error reading file "+src.getPath());
return false;
}
// Calculate the name of the Java source file to be generated.
int dp = src.getName().lastIndexOf(".");
String classname = src.getName().substring(0,dp);
// Sort the properties in increasing key order.
List<String> sortedKeys = new ArrayList<String>();
for (Object key : p.keySet()) {
sortedKeys.add((String)key);
}
Collections.sort(sortedKeys);
Iterator<String> keys = sortedKeys.iterator();
// Collect the properties into a string buffer.
StringBuilder data = new StringBuilder();
while (keys.hasNext()) {
String key = keys.next();
data.append(" { \"" + escape(key) + "\", \"" +
escape((String)p.get(key)) + "\" },\n");
}
// Create dest file name. It is derived from the properties file name.
String destFilename = destRoot.getPath()+File.separator+pkgNameF+File.separator+classname+".java";
File dest = new File(destFilename);
// Make sure the dest directories exist.
if (!dest.getParentFile().isDirectory()) {
if (!dest.getParentFile().mkdirs()) {
Log.error("Could not create the directory "+dest.getParentFile().getPath());
return false;
}
}
Set<URI> as = packageArtifacts.get(pkgName);
if (as == null) {
as = new HashSet<URI>();
packageArtifacts.put(pkgName, as);
}
as.add(dest.toURI());
if (dest.exists() && dest.lastModified() > src.lastModified()) {
// A generated file exists, and its timestamp is newer than the source.
// Assume that we do not need to regenerate the dest file!
// Thus we are done.
return true;
}
String packageString = "package " + pkgNameF.replace(File.separatorChar,'.') + ";\n\n";
Log.info("Compiling property file "+pkgNameF+File.separator+src.getName());
try (Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dest)))) {
MessageFormat format = new MessageFormat(FORMAT);
writer.write(format.format(new Object[] { packageString, classname, superClass, data }));
} catch ( IOException e ) {
Log.error("Could not write file "+dest.getPath());
return false;
}
return true;
}
private static final String FORMAT =
"{0}" +
"public final class {1} extends {2} '{'\n" +
" protected final Object[][] getContents() '{'\n" +
" return new Object[][] '{'\n" +
"{3}" +
" };\n" +
" }\n" +
"}\n";
public static String escape(String theString) {
int len = theString.length();
StringBuilder outBuffer = new StringBuilder(len*2);
for(int x=0; x<len; x++) {
char aChar = theString.charAt(x);
switch(aChar) {
case '\\':outBuffer.append('\\'); outBuffer.append('\\');
break;
case '\t':outBuffer.append('\\'); outBuffer.append('t');
break;
case '\n':outBuffer.append('\\'); outBuffer.append('n');
break;
case '\r':outBuffer.append('\\'); outBuffer.append('r');
break;
case '\f':outBuffer.append('\\'); outBuffer.append('f');
break;
default:
if ((aChar < 0x0020) || (aChar > 0x007e)) {
outBuffer.append('\\');
outBuffer.append('u');
outBuffer.append(toHex((aChar >> 12) & 0xF));
outBuffer.append(toHex((aChar >> 8) & 0xF));
outBuffer.append(toHex((aChar >> 4) & 0xF));
outBuffer.append(toHex( aChar & 0xF));
} else {
if (aChar == '"') {
outBuffer.append('\\');
}
outBuffer.append(aChar);
}
}
}
return outBuffer.toString();
}
private static char toHex(int nibble) {
return hexDigit[(nibble & 0xF)];
}
private static final char[] hexDigit = {
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
};
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac;
import java.io.*;
import java.net.URI;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
/**
* The copy file transform simply copies a matching file from -src to -d .
* Such files are typically images, xml documents and other data files.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class CopyFile implements Transformer {
public void setExtra(String e) {
}
public void setExtra(String[] a) {
}
public boolean transform(Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSrcs,
Map<URI,Set<String>> visibleClasses,
Map<String,Set<String>> oldPackageDependents,
URI destRoot,
Map<String,Set<URI>> packageArtifacts,
Map<String,Set<String>> packageDependencies,
Map<String,String> packagePubapis,
int debugLevel,
boolean incremental,
int numCores,
PrintStream out,
PrintStream err)
{
boolean rc = true;
String dest_filename;
File dest;
for (String pkgName : pkgSrcs.keySet()) {
String pkgNameF = Util.toFileSystemPath(pkgName);
for (URI u : pkgSrcs.get(pkgName)) {
File src = new File(u);
File destDir;
destDir = new File(destRoot.getPath()+File.separator+pkgNameF);
dest_filename = destRoot.getPath()+File.separator+pkgNameF+File.separator+src.getName();
dest = new File(dest_filename);
if (!destDir.isDirectory()) {
if (!destDir.mkdirs()) {
Log.error("Error: The copier could not create the directory "+
destDir.getPath());
return false;
}
}
Set<URI> as = packageArtifacts.get(pkgName);
if (as == null) {
as = new HashSet<URI>();
packageArtifacts.put(pkgName, as);
}
as.add(dest.toURI());
if (dest.exists() && dest.lastModified() > src.lastModified()) {
// A copied file exists, and its timestamp is newer than the source.
continue;
}
Log.info("Copying "+pkgNameF+File.separator+src.getName());
try (InputStream fin = new FileInputStream(src);
OutputStream fout = new FileOutputStream(dest)) {
byte[] buf = new byte[1024];
int len;
while ((len = fin.read(buf)) > 0){
fout.write(buf, 0, len);
}
}
catch(IOException e){
Log.error("Could not copy the file "+src.getPath()+" to "+dest.getPath());
rc = false;
}
}
}
return rc;
}
}
此差异已折叠。
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac;
import java.io.PrintStream;
/**
* Utility class only for sjavac logging.
* The log level can be set using for example --log=DEBUG on the sjavac command line.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class Log {
private static PrintStream out, err;
public final static int WARN = 1;
public final static int INFO = 2;
public final static int DEBUG = 3;
public final static int TRACE = 4;
private static int level = WARN;
static public void trace(String msg) {
if (level >= TRACE) {
out.println(msg);
}
}
static public void debug(String msg) {
if (level >= DEBUG) {
out.println(msg);
}
}
static public void info(String msg) {
if (level >= INFO) {
out.println(msg);
}
}
static public void warn(String msg) {
err.println(msg);
}
static public void error(String msg) {
err.println(msg);
}
static public void setLogLevel(String l, PrintStream o, PrintStream e)
throws ProblemException {
out = o;
err = e;
if (l.equals("warn")) level = WARN;
else if (l.equals("info")) level = INFO;
else if (l.equals("debug")) level = DEBUG;
else if (l.equals("trace")) level = TRACE;
else throw new ProblemException("No such log level \""+l+"\"");
}
static public boolean isTracing() {
return level >= TRACE;
}
static public boolean isDebugging() {
return level >= DEBUG;
}
}
此差异已折叠。
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac;
import java.io.File;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* The module is the root of a set of packages/sources/artifacts.
* At the moment there is only one module in use, the empty/no-name/default module.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class Module implements Comparable<Module> {
private String name;
private String dirname;
private Map<String,Package> packages = new HashMap<String,Package>();
private Map<String,Source> sources = new HashMap<String,Source>();
private Map<String,File> artifacts = new HashMap<String,File>();
public Module(String n, String dn) {
name = n;
dirname = n;
}
public String name() { return name; }
public String dirname() { return dirname; }
public Map<String,Package> packages() { return packages; }
public Map<String,Source> sources() { return sources; }
public Map<String,File> artifacts() { return artifacts; }
@Override
public boolean equals(Object o) {
return (o instanceof Module) && name.equals(((Module)o).name);
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public int compareTo(Module o) {
return name.compareTo(o.name);
}
public void save(StringBuilder b) {
b.append("M ").append(name).append(":").append("\n");
Package.savePackages(packages, b);
}
public static Module load(String l) {
int cp = l.indexOf(':',2);
if (cp == -1) return null;
String name = l.substring(2,cp);
return new Module(name, "");
}
public static void saveModules(Map<String,Module> ms, StringBuilder b)
{
for (Module m : ms.values()) {
m.save(b);
}
}
public void addPackage(Package p) {
packages.put(p.name(), p);
}
public Package lookupPackage(String pkg) {
Package p = packages.get(pkg);
if (p == null) {
p = new Package(this, pkg);
packages.put(pkg, p);
}
return p;
}
public void addSource(String pkg, Source src) {
Package p = lookupPackage(pkg);
src.setPackage(p);
p.addSource(src);
sources.put(src.file().getPath(), src);
}
public Source lookupSource(String path) {
return sources.get(path);
}
public void addArtifacts(String pkg, Set<URI> as) {
Package p = lookupPackage(pkg);
for (URI u : as) {
p.addArtifact(new File(u));
}
}
public void setDependencies(String pkg, Set<String> deps) {
Package p = lookupPackage(pkg);
p.setDependencies(deps);
}
public void setPubapi(String pkg, List<String> ps) {
Package p = lookupPackage(pkg);
p.setPubapi(ps);
}
public boolean hasPubapiChanged(String pkg, List<String> ps) {
Package p = lookupPackage(pkg);
return p.hasPubapiChanged(ps);
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* The Package class maintains meta information about a package.
* For example its sources, dependents,its pubapi and its artifacts.
*
* It might look odd that we track dependents/pubapi/artifacts on
* a package level, but it makes sense since recompiling a full package
* takes as long as recompiling a single java file in that package,
* if you take into account the startup time of the jvm.
*
* Also the dependency information will be much smaller (good for the javac_state file size)
* and it simplifies tracking artifact generation, you do not always know from which
* source a class file was generated, but you always know which package it belongs to.
*
* It is also educational to see package dependencies triggering recompilation of
* other packages. Even though the recompilation was perhaps not necessary,
* the visible recompilation of the dependent packages indicates how much circular
* dependencies your code has.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class Package implements Comparable<Package> {
// The module this package belongs to. (There is a legacy module with an empty string name,
// used for all legacy sources.)
private Module mod;
// Name of this package, module:pkg
// ex1 jdk.base:java.lang
// ex2 :java.lang (when in legacy mode)
private String name;
// The directory path to the package. If the package belongs to a module,
// then that module's file system name is part of the path.
private String dirname;
// This package depends on these packages.
private Set<String> dependencies = new HashSet<String>();
// This package has the following dependents, that depend on this package.
private Set<String> dependents = new HashSet<String>();
// This is the public api of this package.
private List<String> pubapi = new ArrayList<String>();
// Map from source file name to Source info object.
private Map<String,Source> sources = new HashMap<String,Source>();
// This package generated these artifacts.
private Map<String,File> artifacts = new HashMap<String,File>();
public Package(Module m, String n) {
int c = n.indexOf(":");
assert(c != -1);
String mn = n.substring(0,c);
assert(m.name().equals(m.name()));
name = n;
dirname = n.replace('.', File.separatorChar);
if (m.name().length() > 0) {
// There is a module here, prefix the module dir name to the path.
dirname = m.dirname()+File.separatorChar+dirname;
}
}
public Module mod() { return mod; }
public String name() { return name; }
public String dirname() { return dirname; }
public Map<String,Source> sources() { return sources; }
public Map<String,File> artifacts() { return artifacts; }
public List<String> pubapi() { return pubapi; }
public Set<String> dependencies() { return dependencies; }
public Set<String> dependents() { return dependents; }
@Override
public boolean equals(Object o) {
return (o instanceof Package) && name.equals(((Package)o).name);
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public int compareTo(Package o) {
return name.compareTo(o.name);
}
public void addSource(Source s) {
sources.put(s.file().getPath(), s);
}
public void addDependency(String d) {
dependencies.add(d);
}
public void addDependent(String d) {
dependents.add(d);
}
public void addPubapi(String p) {
pubapi.add(p);
}
/**
* Check if we have knowledge in the javac state that
* describe the results of compiling this package before.
*/
public boolean existsInJavacState() {
return artifacts.size() > 0 || pubapi.size() > 0;
}
public static List<String> pubapiToList(String ps)
{
String[] lines = ps.split("\n");
List<String> r = new ArrayList<String>();
for (String l : lines) {
r.add(l);
}
return r;
}
public boolean hasPubapiChanged(List<String> ps) {
Iterator<String> i = ps.iterator();
Iterator<String> j = pubapi.iterator();
int line = 0;
while (i.hasNext() && j.hasNext()) {
String is = i.next();
String js = j.next();
if (!is.equals(js)) {
Log.debug("Change in pubapi for package "+name+" line "+line);
Log.debug("Old: "+js);
Log.debug("New: "+is);
return true;
}
line++;
}
if ((i.hasNext() && !j.hasNext() ) ||
(!i.hasNext() && j.hasNext())) {
Log.debug("Change in pubapi for package "+name);
if (i.hasNext()) {
Log.debug("New has more lines!");
} else {
Log.debug("Old has more lines!");
}
return true;
}
return false;
}
public void setPubapi(List<String> ps) {
pubapi = ps;
}
public void setDependencies(Set<String> ds) {
dependencies = ds;
}
public void save(StringBuilder b) {
b.append("P ").append(name).append("\n");
Source.saveSources(sources, b);
saveDependencies(b);
savePubapi(b);
saveArtifacts(b);
}
static public Package load(Module module, String l) {
String name = l.substring(2);
return new Package(module, name);
}
public void loadDependency(String l) {
String n = l.substring(2);
addDependency(n);
}
public void loadPubapi(String l) {
String pi = l.substring(2);
addPubapi(pi);
}
public void saveDependencies(StringBuilder b) {
List<String> sorted_dependencies = new ArrayList<String>();
for (String key : dependencies) {
sorted_dependencies.add(key);
}
Collections.sort(sorted_dependencies);
for (String a : sorted_dependencies) {
b.append("D "+a+"\n");
}
}
public void savePubapi(StringBuilder b) {
for (String l : pubapi) {
b.append("I "+l+"\n");
}
}
public static void savePackages(Map<String,Package> packages, StringBuilder b) {
List<String> sorted_packages = new ArrayList<String>();
for (String key : packages.keySet() ) {
sorted_packages.add(key);
}
Collections.sort(sorted_packages);
for (String s : sorted_packages) {
Package p = packages.get(s);
p.save(b);
}
}
public void addArtifact(String a) {
artifacts.put(a, new File(a));
}
public void addArtifact(File f) {
artifacts.put(f.getPath(), f);
}
public void addArtifacts(Set<URI> as) {
for (URI u : as) {
addArtifact(new File(u));
}
}
public void setArtifacts(Set<URI> as) {
assert(!artifacts.isEmpty());
artifacts = new HashMap<String,File>();
addArtifacts(as);
}
public void loadArtifact(String l) {
// Find next space after "A ".
int dp = l.indexOf(' ',2);
String fn = l.substring(2,dp);
long last_modified = Long.parseLong(l.substring(dp+1));
File f = new File(fn);
if (f.exists() && f.lastModified() != last_modified) {
// Hmm, the artifact on disk does not have the same last modified
// timestamp as the information from the build database.
// We no longer trust the artifact on disk. Delete it.
// The smart javac wrapper will then rebuild the artifact.
Log.debug("Removing "+f.getPath()+" since its timestamp does not match javac_state.");
f.delete();
}
artifacts.put(f.getPath(), f);
}
public void saveArtifacts(StringBuilder b) {
List<File> sorted_artifacts = new ArrayList<File>();
for (File f : artifacts.values()) {
sorted_artifacts.add(f);
}
Collections.sort(sorted_artifacts);
for (File f : sorted_artifacts) {
// The last modified information is only used
// to detect tampering with the output dir.
// If the outputdir has been modified, not by javac,
// then a mismatch will be detected in the last modified
// timestamps stored in the build database compared
// to the timestamps on disk and the artifact will be deleted.
b.append("A "+f.getPath()+" "+f.lastModified()+"\n");
}
}
/**
* Always clean out a tainted package before it is recompiled.
*/
public void deleteArtifacts() {
for (File a : artifacts.values()) {
a.delete();
}
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac;
/**
* Used to signal serious problems when running sjavac.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class ProblemException extends Exception {
static final long serialVersionUID = -3387516993124229949L;
public ProblemException(String s) {
super(s);
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac;
import java.io.File;
import java.util.Set;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
/** A Source object maintains information about a source file.
* For example which package it belongs to and kind of source it is.
* The class also knows how to find source files (scanRoot) given include/exclude
* patterns and a root.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class Source implements Comparable<Source> {
// The package the source belongs to.
private Package pkg;
// Name of this source file, relative its source root.
// For example: java/lang/Object.java
// Or if the source file is inside a module:
// jdk.base/java/lang/Object.java
private String name;
// What kind of file is this.
private String suffix;
// When this source file was last_modified
private long lastModified;
// The source File.
private File file;
// The source root under which file resides.
private File root;
// If the source is generated.
private boolean isGenerated;
// If the source is only linked to, not compiled.
private boolean linkedOnly;
@Override
public boolean equals(Object o) {
return (o instanceof Source) && name.equals(((Source)o).name);
}
@Override
public int compareTo(Source o) {
return name.compareTo(o.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
public Source(Module m, String n, File f, File r) {
name = n;
int dp = n.lastIndexOf(".");
if (dp != -1) {
suffix = n.substring(dp);
} else {
suffix = "";
}
file = f;
root = r;
lastModified = f.lastModified();
linkedOnly = false;
}
public Source(Package p, String n, long lm) {
pkg = p;
name = n;
int dp = n.lastIndexOf(".");
if (dp != -1) {
suffix = n.substring(dp);
} else {
suffix = "";
}
file = null;
root = null;
lastModified = lm;
linkedOnly = false;
int ls = n.lastIndexOf('/');
}
public String name() { return name; }
public String suffix() { return suffix; }
public Package pkg() { return pkg; }
public File file() { return file; }
public File root() { return root; }
public long lastModified() {
return lastModified;
}
public void setPackage(Package p) {
pkg = p;
}
public void markAsGenerated() {
isGenerated = true;
}
public boolean isGenerated() {
return isGenerated;
}
public void markAsLinkedOnly() {
linkedOnly = true;
}
public boolean isLinkedOnly() {
return linkedOnly;
}
private void save(StringBuilder b) {
String CL = linkedOnly?"L":"C";
String GS = isGenerated?"G":"S";
b.append(GS+" "+CL+" "+name+" "+file.lastModified()+"\n");
}
// Parse a line that looks like this:
// S C /code/alfa/A.java 1357631228000
static public Source load(Package lastPackage, String l, boolean isGenerated) {
int sp = l.indexOf(' ',4);
if (sp == -1) return null;
String name = l.substring(4,sp);
long last_modified = Long.parseLong(l.substring(sp+1));
boolean isLinkedOnly = false;
if (l.charAt(2) == 'L') {
isLinkedOnly = true;
} else if (l.charAt(2) == 'C') {
isLinkedOnly = false;
} else return null;
Source s = new Source(lastPackage, name, last_modified);
s.file = new File(name);
if (isGenerated) s.markAsGenerated();
if (isLinkedOnly) s.markAsLinkedOnly();
return s;
}
public static void saveSources(Map<String,Source> sources, StringBuilder b) {
List<String> sorted_sources = new ArrayList<String>();
for (String key : sources.keySet()) {
sorted_sources.add(key);
}
Collections.sort(sorted_sources);
for (String key : sorted_sources) {
Source s = sources.get(key);
s.save(b);
}
}
/**
* Recurse into the directory root and find all files matchine the excl/incl/exclfiles/inclfiles rules.
* Detects the existence of module-info.java files and presumes that the directory it resides in
* is the name of the current module.
*/
static public void scanRoot(File root,
Set<String> suffixes,
List<String> excludes, List<String> includes,
List<String> excludeFiles, List<String> includeFiles,
Map<String,Source> foundFiles,
Map<String,Module> foundModules,
Module currentModule,
boolean permitSourcesWithoutPackage,
boolean inGensrc,
boolean inLinksrc)
throws ProblemException {
if (root == null) return;
int root_prefix = root.getPath().length()+1;
// This is the root source directory, it must not contain any Java sources files
// because we do not allow Java source files without a package.
// (Unless of course --permit-sources-without-package has been specified.)
// It might contain other source files however, (for -tr and -copy) these will
// always be included, since no package pattern can match the root directory.
currentModule = addFilesInDir(root, root_prefix, root, suffixes, permitSourcesWithoutPackage,
excludeFiles, includeFiles, false,
foundFiles, foundModules, currentModule,
inGensrc, inLinksrc);
File[] dirfiles = root.listFiles();
for (File d : dirfiles) {
if (d.isDirectory()) {
// Descend into the directory structure.
scanDirectory(d, root_prefix, root, suffixes,
excludes, includes, excludeFiles, includeFiles,
false, foundFiles, foundModules, currentModule, inGensrc, inLinksrc);
}
}
}
/**
* Test if a path matches any of the patterns given.
* The pattern foo.bar matches only foo.bar
* The pattern foo.* matches foo.bar and foo.bar.zoo etc
*/
static private boolean hasMatch(String path, List<String> patterns) {
for (String p : patterns) {
// Exact match
if (p.equals(path)) {
return true;
}
// Single dot the end matches this package and all its subpackages.
if (p.endsWith(".*")) {
// Remove the wildcard
String patprefix = p.substring(0,p.length()-2);
// Does the path start with the pattern prefix?
if (path.startsWith(patprefix)) {
// If the path has the same length as the pattern prefix, then it is a match.
// If the path is longer, then make sure that
// the next part of the path starts with a dot (.) to prevent
// wildcard matching in the middle of a package name.
if (path.length()==patprefix.length() || path.charAt(patprefix.length())=='.') {
return true;
}
}
}
}
return false;
}
/**
* Matches patterns with the asterisk first. */
// The pattern foo/bar.java only matches foo/bar.java
// The pattern */bar.java matches foo/bar.java and zoo/bar.java etc
static private boolean hasFileMatch(String path, List<String> patterns) {
path = Util.normalizeDriveLetter(path);
for (String p : patterns) {
// Exact match
if (p.equals(path)) {
return true;
}
// Single dot the end matches this package and all its subpackages.
if (p.startsWith("*")) {
// Remove the wildcard
String patsuffix = p.substring(1);
// Does the path start with the pattern prefix?
if (path.endsWith(patsuffix)) {
return true;
}
}
}
return false;
}
/**
* Add the files in the directory, assuming that the file has not been excluded.
* Returns a fresh Module object, if this was a dir with a module-info.java file.
*/
static private Module addFilesInDir(File dir, int rootPrefix, File root,
Set<String> suffixes, boolean allow_javas,
List<String> excludeFiles, List<String> includeFiles, boolean all,
Map<String,Source> foundFiles,
Map<String,Module> foundModules,
Module currentModule,
boolean inGensrc,
boolean inLinksrc)
throws ProblemException
{
for (File f : dir.listFiles()) {
if (f.isFile()) {
boolean should_add =
(excludeFiles == null || excludeFiles.isEmpty() || !hasFileMatch(f.getPath(), excludeFiles))
&& (includeFiles == null || includeFiles.isEmpty() || hasFileMatch(f.getPath(), includeFiles));
if (should_add) {
if (!allow_javas && f.getName().endsWith(".java")) {
throw new ProblemException("No .java files are allowed in the source root "+dir.getPath()+
", please remove "+f.getName());
}
// Extract the file name relative the root.
String fn = f.getPath().substring(rootPrefix);
// Extract the package name.
int sp = fn.lastIndexOf(File.separatorChar);
String pkg = "";
if (sp != -1) {
pkg = fn.substring(0,sp).replace(File.separatorChar,'.');
}
// Is this a module-info.java file?
if (fn.endsWith("module-info.java")) {
// Aha! We have recursed into a module!
if (!currentModule.name().equals("")) {
throw new ProblemException("You have an extra module-info.java inside a module! Please remove "+fn);
}
String module_name = fn.substring(0,fn.length()-16);
currentModule = new Module(module_name, f.getPath());
foundModules.put(module_name, currentModule);
}
// Extract the suffix.
int dp = fn.lastIndexOf(".");
String suffix = "";
if (dp > 0) {
suffix = fn.substring(dp);
}
// Should the file be added?
if (all || suffixes.contains(suffix)) {
Source of = foundFiles.get(f.getPath());
if (of != null) {
throw new ProblemException("You have already added the file "+fn+" from "+of.file().getPath());
}
of = currentModule.lookupSource(f.getPath());
if (of != null) {
// Oups, the source is already added, could be ok, could be not, lets check.
if (inLinksrc) {
// So we are collecting sources for linking only.
if (of.isLinkedOnly()) {
// Ouch, this one is also for linking only. Bad.
throw new ProblemException("You have already added the link only file "+fn+" from "+of.file().getPath());
}
// Ok, the existing source is to be compiled. Thus this link only is redundant
// since all compiled are also linked to. Continue to the next source.
// But we need to add the source, so that it will be visible to linking,
// if not the multi core compile will fail because a JavaCompiler cannot
// find the necessary dependencies for its part of the source.
foundFiles.put(f.getPath(), of);
continue;
} else {
// We are looking for sources to compile, if we find an existing to be compiled
// source with the same name, it is an internal error, since we must
// find the sources to be compiled before we find the sources to be linked to.
throw new ProblemException("Internal error: Double add of file "+fn+" from "+of.file().getPath());
}
}
Source s = new Source(currentModule, f.getPath(), f, root);
if (inGensrc) s.markAsGenerated();
if (inLinksrc) {
s.markAsLinkedOnly();
}
pkg = currentModule.name()+":"+pkg;
foundFiles.put(f.getPath(), s);
currentModule.addSource(pkg, s);
}
}
}
}
return currentModule;
}
private static boolean gurka = false;
static private void scanDirectory(File dir, int rootPrefix, File root,
Set<String> suffixes,
List<String> excludes, List<String> includes,
List<String> excludeFiles, List<String> includeFiles, boolean all,
Map<String,Source> foundFiles,
Map<String,Module> foundModules,
Module currentModule, boolean inGensrc, boolean inLinksrc)
throws ProblemException {
String pkg_name = "";
// Remove the root prefix from the dir path, and replace file separator with dots
// to get the package name.
if (dir.getPath().length() > rootPrefix) {
pkg_name = dir.getPath().substring(rootPrefix).replace(File.separatorChar,'.');
}
// Should this package directory be included and not excluded?
if (all || ((includes==null || includes.isEmpty() || hasMatch(pkg_name, includes)) &&
(excludes==null || excludes.isEmpty() || !hasMatch(pkg_name, excludes)))) {
// Add the source files.
currentModule = addFilesInDir(dir, rootPrefix, root, suffixes, true, excludeFiles, includeFiles, all,
foundFiles, foundModules, currentModule, inGensrc, inLinksrc);
}
for (File d : dir.listFiles()) {
if (d.isDirectory()) {
// Descend into the directory structure.
scanDirectory(d, rootPrefix, root, suffixes,
excludes, includes, excludeFiles, includeFiles, all,
foundFiles, foundModules, currentModule, inGensrc, inLinksrc);
}
}
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac;
import java.io.PrintStream;
import java.net.URI;
import java.util.Set;
import java.util.Map;
/**
* The transform interface is used to transform content inside a package, from one form to another.
* Usually the output form is an unpredictable number of output files. (eg class files)
* but can also be an unpredictable number of generated source files (eg idl2java)
* or a single predictable output file (eg when copying,cleaning or compiling a properties file).
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public interface Transformer
{
/**
* The transform method takes a set of package names, mapped to their source files and to the
* pubapis of the packages.
*
* The transform implementation must:
* store the names of the generated artifacts for each package into package_artifacts
* store found dependencies to other packages into the supplied set package_dependencies
* store the public api for a package into the supplied set package_pubapis
*
* Any benign messages as a result of running the transform
* are written into stdout, and errors are written to stderr.
*
* The debug_level can be 0=silent (only warnings and errors) 1=normal 2=verbose 3 or greater=debug
* setExtra is used to set the extra information information that can be passed on
* the command line to the smart javac wrapper.
*
* If sjavac is building incrementally from an existing javac_state, the var incremental is true.
*
* The transformer will only be called if some source in the package (or dependency) has
* a modified timestamp. Thus the transformer might get called with many sources, of which
* only one has changed. The transformer is allowed to regenerate all artifacts but
* a better transformer will only write those artifacts that need updating.
*
* However the transformer must verify that the existing artifacts really are there!
* and it must always update package_artifacts, package_dependencies, and package_pubapis correctly.
* This means that at least for Java source, it will always have to recompile the sources.
*
* The transformer is allowed to put files anywhere in the dest_root.
* An example of this is, can be the META-INF transformer that copy files
* below META-INF directories to the single META-INF directory below dest_root.
*
* False is returned if there was an error that prevented the transform.
* I.e. something was printed on stderr.
*
* If num_cores is set to a non-zero value. The transform should attempt to use no more than these
* number of threads for heavy work.
*/
boolean transform(Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSources,
Map<URI,Set<String>> visibleClasses,
Map<String,Set<String>> oldPackageDependencies,
URI destRoot,
Map<String,Set<URI>> packageArtifacts,
Map<String,Set<String>> packageDependencies,
Map<String,String> packagePublicApis,
int debugLevel,
boolean incremental,
int numCores,
PrintStream out,
PrintStream err);
void setExtra(String e);
void setExtra(String[] args);
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
/**
* Utilities.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class Util {
public static String toFileSystemPath(String pkgId) {
if (pkgId == null || pkgId.length()==0) return null;
String pn;
if (pkgId.charAt(0) == ':') {
// When the module is the default empty module.
// Do not prepend the module directory, because there is none.
// Thus :java.foo.bar translates to java/foo/bar (or \)
pn = pkgId.substring(1).replace('.',File.separatorChar);
} else {
// There is a module. Thus jdk.base:java.foo.bar translates
// into jdk.base/java/foo/bar
int cp = pkgId.indexOf(':');
String mn = pkgId.substring(0,cp);
pn = mn+File.separatorChar+pkgId.substring(cp+1).replace('.',File.separatorChar);
}
return pn;
}
public static String justPackageName(String pkgName) {
int c = pkgName.indexOf(":");
assert(c != -1);
return pkgName.substring(c+1);
}
public static String extractStringOption(String opName, String s) {
int p = s.indexOf(opName+"=");
if (p == -1) return null;
p+=opName.length()+1;
int pe = s.indexOf(',', p);
if (pe == -1) pe = s.length();
return s.substring(p, pe);
}
public static int extractIntOption(String opName, String s) {
int p = s.indexOf(opName+"=");
if (p == -1) return 0;
p+=opName.length()+1;
int pe = s.indexOf(',', p);
if (pe == -1) pe = s.length();
int v = 0;
try {
v = Integer.parseInt(s.substring(p, pe));
} catch (Exception e) {}
return v;
}
/**
* Clean out unwanted sub options supplied inside a primary option.
* For example to only had portfile remaining from:
* settings="--server:id=foo,portfile=bar"
* do settings = cleanOptions("--server:",Util.set("-portfile"),settings);
* now settings equals "--server:portfile=bar"
*
* @param optionPrefix The option name, including colon, eg --server:
* @param allowsSubOptions A set of the allowed sub options, id portfile etc.
* @param s The option settings string.
*/
public static String cleanSubOptions(String optionPrefix, Set<String> allowedSubOptions, String s) {
StringBuilder sb = new StringBuilder();
if (!s.startsWith(optionPrefix)) return "";
StringTokenizer st = new StringTokenizer(s.substring(optionPrefix.length()), ",");
while (st.hasMoreTokens()) {
String o = st.nextToken();
int p = o.indexOf('=');
if (p>0) {
String key = o.substring(0,p);
String val = o.substring(p+1);
if (allowedSubOptions.contains(key)) {
if (sb.length() > 0) sb.append(',');
sb.append(key+"="+val);
}
}
}
return sb.toString();
}
/**
* Convenience method to create a set with strings.
*/
public static Set<String> set(String... ss) {
Set<String> set = new HashSet<String>();
set.addAll(Arrays.asList(ss));
return set;
}
/**
* Normalize windows drive letter paths to upper case to enable string
* comparison.
*
* @param file File name to normalize
* @return The normalized string if file has a drive letter at the beginning,
* otherwise the original string.
*/
public static String normalizeDriveLetter(String file) {
if (file.length() > 2 && file.charAt(1) == ':') {
return Character.toUpperCase(file.charAt(0)) + file.substring(1);
} else if (file.length() > 3 && file.charAt(0) == '*'
&& file.charAt(2) == ':') {
// Handle a wildcard * at the beginning of the string.
return file.substring(0, 1) + Character.toUpperCase(file.charAt(1))
+ file.substring(2);
}
return file;
}
/**
* Locate the setting for the server properties.
*/
public static String findServerSettings(String[] args) {
for (String s : args) {
if (s.startsWith("--server:")) {
return s;
}
}
return null;
}
}
/*
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp;
import javax.lang.model.element.Element;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Name;
/** Utility class containing dependency information between packages
* and the pubapi for a package.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class Dependencies {
protected static final Context.Key<Dependencies> dependenciesKey =
new Context.Key<Dependencies>();
// The log to be used for error reporting.
protected Log log;
// Map from package name to packages that the package depends upon.
protected Map<Name,Set<Name>> deps;
// This is the set of all packages that are supplied
// through the java files at the command line.
protected Set<Name> explicitPackages;
// Map from a package name to its public api.
// Will the Name encode the module in the future?
// If not, this will have to change to map from Module+Name to public api.
protected Map<Name,StringBuffer> publicApiPerClass;
public static Dependencies instance(Context context) {
Dependencies instance = context.get(dependenciesKey);
if (instance == null)
instance = new Dependencies(context);
return instance;
}
private Dependencies(Context context) {
context.put(dependenciesKey, this);
log = Log.instance(context);
}
public void reset()
{
deps = new HashMap<Name, Set<Name>>();
explicitPackages = new HashSet<Name>();
publicApiPerClass = new HashMap<Name,StringBuffer>();
}
/**
* Fetch the set of dependencies that are relevant to the compile
* that has just been performed. I.e. we are only interested in
* dependencies for classes that were explicitly compiled.
* @return
*/
public Map<String,Set<String>> getDependencies() {
Map<String,Set<String>> new_deps = new HashMap<String,Set<String>>();
if (explicitPackages == null) return new_deps;
for (Name pkg : explicitPackages) {
Set<Name> set = deps.get(pkg);
if (set != null) {
Set<String> new_set = new_deps.get(pkg.toString());
if (new_set == null) {
new_set = new HashSet<String>();
// Modules beware....
new_deps.put(":"+pkg.toString(), new_set);
}
for (Name d : set) {
new_set.add(":"+d.toString());
}
}
}
return new_deps;
}
class CompareNames implements Comparator<Name> {
public int compare(Name a, Name b) {
return a.toString().compareTo(b.toString());
}
public boolean equals(Object obj) {
return super.equals(obj);
}
}
/**
* Convert the map from class names to their pubapi to a map
* from package names to their pubapi (which is the sorted concatenation
* of all the class pubapis)
*/
public Map<String,String> getPubapis() {
Map<String,String> publicApiPerPackage = new HashMap<String,String>();
if (publicApiPerClass == null) return publicApiPerPackage;
Name[] keys = publicApiPerClass.keySet().toArray(new Name[0]);
Arrays.sort(keys, new CompareNames());
StringBuffer newPublicApi = new StringBuffer();
int i=0;
String prevPkg = "";
for (Name k : keys) {
String cn = k.toString();
String pn = "";
int dp = cn.lastIndexOf('.');
if (dp != -1) {
pn = cn.substring(0,dp);
}
if (!pn.equals(prevPkg)) {
if (!prevPkg.equals("")) {
// Add default module name ":"
publicApiPerPackage.put(":"+prevPkg, newPublicApi.toString());
}
newPublicApi = new StringBuffer();
prevPkg = pn;
}
newPublicApi.append(publicApiPerClass.get(k));
i++;
}
if (!prevPkg.equals(""))
publicApiPerPackage.put(":"+prevPkg, newPublicApi.toString());
return publicApiPerPackage;
}
/**
* Visit the api of a class and construct a pubapi string and
* store it into the pubapi_perclass map.
*/
public void visitPubapi(Element e) {
Name n = ((ClassSymbol)e).fullname;
Name p = ((ClassSymbol)e).packge().fullname;
StringBuffer sb = publicApiPerClass.get(n);
assert(sb == null);
sb = new StringBuffer();
PubapiVisitor v = new PubapiVisitor(sb);
v.visit(e);
if (sb.length()>0) {
publicApiPerClass.put(n, sb);
}
explicitPackages.add(p);
}
/**
* Collect a dependency. curr_pkg is marked as depending on dep_pkg.
*/
public void collect(Name currPkg, Name depPkg) {
if (!currPkg.equals(depPkg)) {
Set<Name> theset = deps.get(currPkg);
if (theset==null) {
theset = new HashSet<Name>();
deps.put(currPkg, theset);
}
theset.add(depPkg);
}
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp;
import java.util.StringTokenizer;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.sjavac.server.CompilerThread;
import java.io.File;
/** Subclass to Resolve that overrides collect.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class JavaCompilerWithDeps extends JavaCompiler {
/** The dependency database
*/
protected Dependencies deps;
protected CompilerThread compilerThread;
public JavaCompilerWithDeps(Context context, CompilerThread t) {
super(context);
deps = Dependencies.instance(context);
compilerThread = t;
needRootClasses = true;
}
public static void preRegister(Context context, final CompilerThread t) {
context.put(compilerKey, new Context.Factory<JavaCompiler>() {
public JavaCompiler make(Context c) {
JavaCompiler instance = new JavaCompilerWithDeps(c, t);
c.put(JavaCompiler.class, instance);
return instance;
}
});
}
/** Collect the public apis of classes supplied explicitly for compilation.
* @param sym The class to visit.
*/
@Override
public void reportPublicApi(ClassSymbol sym) {
// The next test will catch when source files are located in the wrong directory!
// This ought to be moved into javac as a new warning, or perhaps as part
// of the auxiliary class warning.
// For example if sun.swing.BeanInfoUtils
// is in fact stored in: /mybuild/jdk/gensrc/javax/swing/beaninfo/BeanInfoUtils.java
// We do not need to test that BeanInfoUtils is stored in a file named BeanInfoUtils
// since this is checked earlier.
if (sym.sourcefile != null) {
// Rewrite sun.swing.BeanInfoUtils into /sun/swing/
StringBuilder pathb = new StringBuilder();
StringTokenizer qn = new StringTokenizer(sym.packge().toString(), ".");
boolean first = true;
while (qn.hasMoreTokens()) {
String o = qn.nextToken();
pathb.append("/");
pathb.append(o);
first = false;
}
pathb.append("/");
String path = pathb.toString();
// Now cut the uri to be: file:///mybuild/jdk/gensrc/javax/swing/beaninfo/
String p = sym.sourcefile.toUri().getPath();
// Do not use File.separatorChar here, a URI always uses slashes /.
int i = p.lastIndexOf("/");
String pp = p.substring(0,i+1);
// Now check if the truncated uri ends with the path. (It does not == failure!)
if (path.length() > 0 && !path.equals("/unnamed package/") && !pp.endsWith(path)) {
compilerThread.logError("Error: The source file "+sym.sourcefile.getName()+
" is located in the wrong package directory, because it contains the class "+
sym.getQualifiedName());
}
}
deps.visitPubapi(sym);
}
}
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp;
import java.util.Iterator;
import java.util.List;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementScanner6;
/** Utility class that constructs a textual representation
* of the public api of a class.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class PubapiVisitor extends ElementScanner6<Void, Void> {
StringBuffer sb;
// Important that it is 1! Part of protocol over wire, silly yes.
// Fix please.
int indent = 1;
public PubapiVisitor(StringBuffer sb) {
this.sb = sb;
}
String depth(int l) {
return " ".substring(0, l);
}
@Override
public Void visitType(TypeElement e, Void p) {
if (e.getModifiers().contains(Modifier.PUBLIC)
|| e.getModifiers().contains(Modifier.PROTECTED))
{
sb.append(depth(indent) + "TYPE " + e.getQualifiedName() + "\n");
indent += 2;
Void v = super.visitType(e, p);
indent -= 2;
return v;
}
return null;
}
@Override
public Void visitVariable(VariableElement e, Void p) {
if (e.getModifiers().contains(Modifier.PUBLIC)
|| e.getModifiers().contains(Modifier.PROTECTED)) {
sb.append(depth(indent)).append("VAR ")
.append(makeVariableString(e)).append("\n");
}
// Safe to not recurse here, because the only thing
// to visit here is the constructor of a variable declaration.
// If it happens to contain an anonymous inner class (which it might)
// then this class is never visible outside of the package anyway, so
// we are allowed to ignore it here.
return null;
}
@Override
public Void visitExecutable(ExecutableElement e, Void p) {
if (e.getModifiers().contains(Modifier.PUBLIC)
|| e.getModifiers().contains(Modifier.PROTECTED)) {
sb.append(depth(indent)).append("METHOD ")
.append(makeMethodString(e)).append("\n");
}
return null;
}
/**
* Creates a String representation of a method element with everything
* necessary to track all public aspects of it in an API.
* @param e Element to create String for.
* @return String representation of element.
*/
protected String makeMethodString(ExecutableElement e) {
StringBuilder result = new StringBuilder();
for (Modifier modifier : e.getModifiers()) {
result.append(modifier.toString());
result.append(" ");
}
result.append(e.getReturnType().toString());
result.append(" ");
result.append(e.toString());
List<? extends TypeMirror> thrownTypes = e.getThrownTypes();
if (!thrownTypes.isEmpty()) {
result.append(" throws ");
for (Iterator<? extends TypeMirror> iterator = thrownTypes
.iterator(); iterator.hasNext();) {
TypeMirror typeMirror = iterator.next();
result.append(typeMirror.toString());
if (iterator.hasNext()) {
result.append(", ");
}
}
}
return result.toString();
}
/**
* Creates a String representation of a variable element with everything
* necessary to track all public aspects of it in an API.
* @param e Element to create String for.
* @return String representation of element.
*/
protected String makeVariableString(VariableElement e) {
StringBuilder result = new StringBuilder();
for (Modifier modifier : e.getModifiers()) {
result.append(modifier.toString());
result.append(" ");
}
result.append(e.asType().toString());
result.append(" ");
result.append(e.toString());
Object value = e.getConstantValue();
if (value != null) {
result.append(" = ");
if (e.asType().toString().equals("char")) {
int v = (int)value.toString().charAt(0);
result.append("'\\u"+Integer.toString(v,16)+"'");
} else {
result.append(value.toString());
}
}
return result.toString();
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp;
import com.sun.tools.javac.comp.Resolve;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.code.Symbol;
/** Subclass to Resolve that overrides collect.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class ResolveWithDeps extends Resolve {
/** The dependency database
*/
protected Dependencies deps;
protected ResolveWithDeps(Context context) {
super(context);
deps = Dependencies.instance(context);
}
public static void preRegister(Context context) {
context.put(resolveKey, new Context.Factory<Resolve>() {
public Resolve make(Context c) {
Resolve instance = new ResolveWithDeps(c);
c.put(Resolve.class, instance);
return instance;
}
});
}
/** Collect dependencies in the enclosing class
* @param from The enclosing class sym
* @param to The enclosing classes references this sym.
* */
@Override
public void reportDependence(Symbol from, Symbol to) {
// Capture dependencies between the packages.
deps.collect(from.packge().fullname, to.packge().fullname);
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp;
import java.io.*;
import java.net.URI;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.NestingKind;
import javax.tools.JavaFileObject;
/**
* The SmartFileObject will return an outputstream that cache the written data
* and compare the new content with the old content on disk. Only if they differ,
* will the file be updated.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class SmartFileObject implements JavaFileObject {
JavaFileObject file;
PrintWriter stdout;
public SmartFileObject(JavaFileObject r, PrintWriter pw) {
file = r;
stdout = pw;
}
@Override
public boolean equals(Object other) {
return file.equals(other);
}
@Override
public int hashCode() {
return file.hashCode();
}
public Kind getKind() {
return file.getKind();
}
public boolean isNameCompatible(String simpleName, Kind kind) {
return file.isNameCompatible(simpleName, kind);
}
public URI toUri() {
return file.toUri();
}
public String getName() {
return file.getName();
}
public InputStream openInputStream() throws IOException {
return file.openInputStream();
}
public OutputStream openOutputStream() throws IOException {
return file.openOutputStream();
}
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return file.getCharContent(ignoreEncodingErrors);
}
static String lineseparator = System.getProperty("line.separator");
public Writer openWriter() throws IOException {
StringBuilder s = new StringBuilder();
try (BufferedReader r = new BufferedReader(file.openReader(true))) {
while (r.ready()) {
s.append(r.readLine()+lineseparator);
}
} catch (FileNotFoundException e) {
// Perfectly ok.
}
return new SmartWriter(file, s.toString(), file.getName(), stdout);
}
public long getLastModified() {
return file.getLastModified();
}
public boolean delete() {
return file.delete();
}
public Modifier getAccessLevel() {
return file.getAccessLevel();
}
public NestingKind getNestingKind() {
return file.getNestingKind();
}
public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
return file.openReader(ignoreEncodingErrors);
}
}
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册