blob: 4ba585d8ba6a821038861d7772f99176b3ef7ad0 [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.uibinder.rebind.model;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.resources.css.ExtractClassNamesVisitor;
import com.google.gwt.resources.css.GenerateCssAst;
import com.google.gwt.resources.css.ast.CssStylesheet;
import com.google.gwt.resources.ext.ResourceGeneratorUtil;
import com.google.gwt.uibinder.attributeparsers.CssNameConverter;
import com.google.gwt.uibinder.rebind.MortalLogger;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Models a method returning a CssResource on a generated ClientBundle.
*/
public class ImplicitCssResource {
private static final CssNameConverter nameConverter = new CssNameConverter();
private final String packageName;
private final String className;
private final String name;
private final List<String> sources;
private final JClassType extendedInterface;
private final String body;
private final MortalLogger logger;
private final Set<JClassType> imports;
private File generatedFile;
private Set<String> cssClassNames;
private Set<String> normalizedCssClassNames;
/**
* Visible for testing only, get instances from {@link ImplicitClientBundle}.
*/
public ImplicitCssResource(String packageName, String className, String name,
String[] source, JClassType extendedInterface, String body,
MortalLogger logger, Set<JClassType> importTypes) {
this.packageName = packageName;
this.className = className;
this.name = name;
this.extendedInterface = extendedInterface;
this.body = body;
this.logger = logger;
this.imports = Collections.unmodifiableSet(importTypes);
sources = Arrays.asList(source);
}
/**
* @return the name of the CssResource interface
*/
public String getClassName() {
return className;
}
/**
* @return the set of CSS classnames in the underlying .css files
*
* @throws UnableToCompleteException if the user has called for a .css file we
* can't find.
*/
public Set<String> getCssClassNames() throws UnableToCompleteException {
List<URL> urls = getExternalCss();
if (cssClassNames == null) {
final File bodyFile = getGeneratedFile();
if (bodyFile != null) {
try {
urls.add(bodyFile.toURI().toURL());
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
assert urls.size() > 0;
CssStylesheet sheet = GenerateCssAst.exec(logger.getTreeLogger(),
urls.toArray(new URL[urls.size()]));
cssClassNames = ExtractClassNamesVisitor.exec(sheet,
imports.toArray(new JClassType[imports.size()]));
}
return cssClassNames;
}
/**
* @return the public interface that this CssResource implements
*/
public JClassType getExtendedInterface() {
return extendedInterface;
}
/**
* @return the set of CssResource types whose scopes are imported
*/
public Set<JClassType> getImports() {
return imports;
}
/**
* @return the name of this resource. This is both its method name in the
* owning {@link ImplicitClientBundle} and its ui:field name
*/
public String getName() {
return name;
}
/**
* @return css class names with dashed-names normalized like so: dashedNames
*/
public Set<String> getNormalizedCssClassNames()
throws UnableToCompleteException {
if (normalizedCssClassNames == null) {
Set<String> rawNames = getCssClassNames();
normalizedCssClassNames = new HashSet<String>();
for (String rawName : rawNames) {
normalizedCssClassNames.add(nameConverter.convertName(rawName));
}
}
return normalizedCssClassNames;
}
/**
* @return the package in which the generated CssResource interface should
* reside
*/
public String getPackageName() {
return packageName;
}
/**
* @return name of the generated type
*/
public String getQualifiedSourceName() {
if (packageName.length() == 0) {
return name;
}
return String.format("%s.%s", packageName, className);
}
/**
* @return the name of the .css file(s), separate by white space
*/
public Collection<String> getSource() {
if (body.length() == 0) {
return Collections.unmodifiableCollection(sources);
}
List<String> rtn = new ArrayList<String>(sources);
rtn.add(getBodyFileName());
return rtn;
}
private String getBodyFileName() {
return String.format("uibinder:%s.%s.css", packageName, className);
}
private List<URL> getExternalCss() throws UnableToCompleteException {
/*
* TODO(rjrjr,bobv) refactor ResourceGeneratorUtil.findResources so we can
* find them the same way ClientBundle does. For now, just look relative to
* this package
*/
ClassLoader classLoader = ImplicitCssResource.class.getClassLoader();
String path = packageName.replace(".", "/");
List<URL> urls = new ArrayList<URL>();
for (String s : sources) {
String resourcePath = path + '/' + s;
URL found = classLoader.getResource(resourcePath);
if (null == found) {
logger.die("Unable to find resource: " + resourcePath);
}
urls.add(found);
}
return urls;
}
private File getGeneratedFile() {
if (body.length() == 0) {
return null;
}
if (generatedFile == null) {
try {
File f = File.createTempFile(String.format("uiBinder_%s_%s",
packageName, className), ".css");
f.deleteOnExit();
BufferedWriter out = new BufferedWriter(new FileWriter(f));
out.write(body);
out.close();
generatedFile = f;
} catch (IOException e) {
throw new RuntimeException(e);
}
ResourceGeneratorUtil.addNamedFile(getBodyFileName(), generatedFile);
}
return generatedFile;
}
}