blob: 61d4fc1abafeda0adf2dce5ff3c623400dbd56cf [file] [log] [blame]
/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.javac;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.util.Util;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
/**
* Builds a {@link CompilationUnit}.
*/
public abstract class CompilationUnitBuilder {
static class GeneratedCompilationUnitBuilder extends CompilationUnitBuilder {
private final GeneratedUnit generatedUnit;
public GeneratedCompilationUnitBuilder(GeneratedUnit generatedUnit) {
this.generatedUnit = generatedUnit;
}
@Override
public ContentId getContentId() {
return new ContentId(getTypeName(), generatedUnit.getStrongHash());
}
@Override
public String getLocation() {
return getLocationFor(generatedUnit);
}
@Override
public String getSourceMapPath() {
return generatedUnit.getSourceMapPath();
}
@Override
public String getTypeName() {
return generatedUnit.getTypeName();
}
@Override
protected String doGetSource() {
return generatedUnit.getSource();
}
@Override
protected CompilationUnit makeUnit(List<CompiledClass> compiledClasses,
List<JDeclaredType> types, Dependencies dependencies,
Collection<? extends JsniMethod> jsniMethods, MethodArgNamesLookup methodArgs,
CategorizedProblem[] problems) {
return new GeneratedCompilationUnit(generatedUnit, compiledClasses, types, dependencies,
jsniMethods, methodArgs, problems);
}
}
static class ResourceCompilationUnitBuilder extends CompilationUnitBuilder {
/**
* Not valid until source has been read.
*/
private ContentId contentId;
private long lastModifed = -1;
private final Resource resource;
private final String typeName;
private ResourceCompilationUnitBuilder(Resource resource) {
this.typeName = Shared.toTypeName(resource.getPath());
this.resource = resource;
}
@Override
public ContentId getContentId() {
if (contentId == null) {
getSource();
}
return contentId;
}
public long getLastModified() {
if (lastModifed < 0) {
return resource.getLastModified();
} else {
// Value when the source was actually read.
return lastModifed;
}
}
@Override
public String getLocation() {
return resource.getLocation();
}
public Resource getResource() {
return resource;
}
@Override
public String getSourceMapPath() {
return getSourceMapPathFor(resource);
}
@Override
public String getTypeName() {
return typeName;
}
@Override
protected String doGetSource() {
/*
* Pin the mod date first to be conservative, we'd rather a unit be seen
* as too stale than too fresh.
*/
lastModifed = resource.getLastModified();
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
try {
InputStream in = resource.openContents();
/**
* In most cases openContents() will throw an exception, however in the case of a
* ZipFileResource it might return null causing an NPE in Util.copyNoClose(),
* see issue 4359.
*/
if (in == null) {
throw new RuntimeException("Unexpected error reading resource '" + resource + "'");
}
Util.copy(in, out);
} catch (IOException e) {
throw new RuntimeException("Unexpected error reading resource '" + resource + "'", e);
}
byte[] content = out.toByteArray();
contentId = new ContentId(getTypeName(), Util.computeStrongName(content));
return Util.toString(content);
}
@Override
protected CompilationUnit makeUnit(List<CompiledClass> compiledClasses,
List<JDeclaredType> types, Dependencies dependencies,
Collection<? extends JsniMethod> jsniMethods, MethodArgNamesLookup methodArgs,
CategorizedProblem[] problems) {
return new SourceFileCompilationUnit(getResource(), getContentId(), compiledClasses, types,
dependencies, jsniMethods, methodArgs, problems, getLastModified());
}
}
static final class GeneratedCompilationUnit extends CompilationUnitImpl {
private final GeneratedUnit generatedUnit;
public GeneratedCompilationUnit(GeneratedUnit generatedUnit,
List<CompiledClass> compiledClasses, List<JDeclaredType> types, Dependencies dependencies,
Collection<? extends JsniMethod> jsniMethods, MethodArgNamesLookup methodArgs,
CategorizedProblem[] problems) {
super(compiledClasses, types, dependencies, jsniMethods, methodArgs, problems);
this.generatedUnit = generatedUnit;
}
@Override
public CachedCompilationUnit asCachedCompilationUnit() {
return new CachedCompilationUnit(this, astToken);
}
@Override
public long getLastModified() {
return generatedUnit.creationTime();
}
@Override
public String getResourceLocation() {
return getLocationFor(generatedUnit);
}
@Override
public String getResourcePath() {
return Shared.toPath(generatedUnit.getTypeName());
}
@Override
public String getTypeName() {
return generatedUnit.getTypeName();
}
@Deprecated
@Override
public boolean isGenerated() {
return true;
}
@Deprecated
@Override
public boolean isSuperSource() {
return false;
}
@Override
ContentId getContentId() {
return new ContentId(getTypeName(), generatedUnit.getStrongHash());
}
String getSource() {
return generatedUnit.getSource();
}
}
public static CompilationUnitBuilder create(GeneratedUnit generatedUnit) {
return new GeneratedCompilationUnitBuilder(generatedUnit);
}
public static CompilationUnitBuilder create(Resource resource) {
return new ResourceCompilationUnitBuilder(resource);
}
/**
* Given a resource, returns the filename that will appear in the source map.
*/
public static String getSourceMapPathFor(Resource resource) {
return resource.getPathPrefix() + resource.getPath();
}
static String getLocationFor(GeneratedUnit generatedUnit) {
String location = generatedUnit.optionalFileLocation();
if (location != null) {
return location;
}
return "generated://" + generatedUnit.getStrongHash() + "/"
+ Shared.toPath(generatedUnit.getTypeName());
}
private List<CompiledClass> compiledClasses;
private Dependencies dependencies;
private Collection<? extends JsniMethod> jsniMethods;
private MethodArgNamesLookup methodArgs;
private CategorizedProblem[] problems;
/**
* Caches source until JSNI methods can be collected.
*/
private transient String source;
private List<JDeclaredType> types;
protected CompilationUnitBuilder() {
}
public CompilationUnit build() {
// Free the source now.
source = null;
assert compiledClasses != null;
assert types != null;
assert dependencies != null;
assert jsniMethods != null;
assert methodArgs != null;
return makeUnit(compiledClasses, types, dependencies, jsniMethods, methodArgs, problems);
}
public abstract ContentId getContentId();
/**
* Returns the location that should appear in JDT error messages.
*/
public abstract String getLocation();
public String getSource() {
if (source == null) {
source = doGetSource();
}
return source;
}
/**
* Returns the location for this resource as it should appear in a sourcemap.
* For a regular source file, it should be a path relative to one of the classpath entries
* from the ResourceLoader. For generated files, it should be "gen/" followed by the path where
* the source file would show up in the generated files directory if the "-gen" compiler option
* were enabled.
*/
public abstract String getSourceMapPath();
/**
* Returns the type source name.
*/
public abstract String getTypeName();
public CompilationUnitBuilder setClasses(List<CompiledClass> compiledClasses) {
this.compiledClasses = compiledClasses;
return this;
}
public CompilationUnitBuilder setDependencies(Dependencies dependencies) {
this.dependencies = dependencies;
return this;
}
public CompilationUnitBuilder setJsniMethods(Collection<? extends JsniMethod> jsniMethods) {
this.jsniMethods = jsniMethods;
return this;
}
public CompilationUnitBuilder setMethodArgs(MethodArgNamesLookup methodArgs) {
this.methodArgs = methodArgs;
return this;
}
public CompilationUnitBuilder setProblems(CategorizedProblem[] problems) {
this.problems = problems;
return this;
}
public CompilationUnitBuilder setTypes(List<JDeclaredType> types) {
this.types = types;
return this;
}
@Override
public final String toString() {
return getLocation();
}
protected abstract String doGetSource();
protected abstract CompilationUnit makeUnit(List<CompiledClass> compiledClasses,
List<JDeclaredType> types, Dependencies dependencies,
Collection<? extends JsniMethod> jsniMethods, MethodArgNamesLookup methodArgs,
CategorizedProblem[] errors);
}