| /* |
| * Copyright 2014 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.resources.gss; |
| |
| import com.google.gwt.core.ext.typeinfo.JClassType; |
| import com.google.gwt.core.ext.typeinfo.JType; |
| import com.google.gwt.core.ext.typeinfo.NotFoundException; |
| import com.google.gwt.resources.client.DataResource; |
| import com.google.gwt.resources.client.ImageResource; |
| import com.google.gwt.resources.ext.ResourceContext; |
| import com.google.gwt.resources.ext.ResourceGeneratorUtil; |
| import com.google.gwt.resources.gss.ast.CssDotPathNode; |
| import com.google.gwt.resources.gss.ast.CssJavaExpressionNode; |
| import com.google.gwt.thirdparty.common.css.SourceCodeLocation; |
| import com.google.gwt.thirdparty.common.css.compiler.ast.CssFunctionArgumentsNode; |
| import com.google.gwt.thirdparty.common.css.compiler.ast.CssFunctionNode; |
| import com.google.gwt.thirdparty.common.css.compiler.ast.CssValueNode; |
| import com.google.gwt.thirdparty.common.css.compiler.ast.ErrorManager; |
| import com.google.gwt.thirdparty.common.css.compiler.ast.GssError; |
| import com.google.gwt.thirdparty.common.css.compiler.ast.GssFunction; |
| import com.google.gwt.thirdparty.common.css.compiler.ast.GssFunctionException; |
| import com.google.gwt.thirdparty.common.css.compiler.gssfunctions.GssFunctions; |
| import com.google.gwt.thirdparty.guava.common.annotations.VisibleForTesting; |
| import com.google.gwt.thirdparty.guava.common.collect.ImmutableList; |
| |
| import java.util.List; |
| |
| /** |
| * Gss function that create the needed nodes in order to correctly get the url of a resource. |
| */ |
| public class ResourceUrlFunction implements GssFunction { |
| |
| @VisibleForTesting |
| interface MethodByPathHelper { |
| JType getReturnType(ResourceContext context, List<String> pathElements) |
| throws NotFoundException; |
| } |
| |
| private static class MethodByPathHelperImpl implements MethodByPathHelper { |
| @Override |
| public JType getReturnType(ResourceContext context, List<String> pathElements) |
| throws NotFoundException { |
| return ResourceGeneratorUtil.getMethodByPath(context.getClientBundleType(), |
| pathElements, null).getReturnType(); |
| } |
| } |
| |
| private final ResourceContext context; |
| private final MethodByPathHelper methodByPathHelper; |
| private final JClassType dataResourceType; |
| private final JClassType imageResourceType; |
| |
| public static String getName() { |
| return "resourceUrl"; |
| } |
| |
| public ResourceUrlFunction(ResourceContext context) { |
| this(context, new MethodByPathHelperImpl()); |
| } |
| |
| @VisibleForTesting |
| ResourceUrlFunction(ResourceContext context, MethodByPathHelper methodByPathHelper) { |
| this.context = context; |
| this.methodByPathHelper = methodByPathHelper; |
| this.dataResourceType = context.getGeneratorContext().getTypeOracle() |
| .findType(DataResource.class.getCanonicalName()); |
| this.imageResourceType = context.getGeneratorContext().getTypeOracle() |
| .findType(ImageResource.class.getCanonicalName()); |
| } |
| |
| @Override |
| public Integer getNumExpectedArguments() { |
| return 1; |
| } |
| |
| @Override |
| public List<CssValueNode> getCallResultNodes(List<CssValueNode> cssValueNodes, |
| ErrorManager errorManager) throws GssFunctionException { |
| CssValueNode functionToEval = cssValueNodes.get(0); |
| String value = functionToEval.getValue(); |
| SourceCodeLocation location = functionToEval.getSourceCodeLocation(); |
| |
| String javaExpression = buildJavaExpression(value, location, errorManager); |
| |
| CssFunctionNode urlNode = buildUrlNode(javaExpression, location); |
| |
| return ImmutableList.<CssValueNode>of(urlNode); |
| } |
| |
| @Override |
| public String getCallResultString(List<String> strings) throws GssFunctionException { |
| return strings.get(0); |
| } |
| |
| private String buildJavaExpression(String value, SourceCodeLocation location, |
| ErrorManager errorManager) throws GssFunctionException { |
| CssDotPathNode dotPathValue = new CssDotPathNode(value, "", "", location); |
| |
| assertMethodIsValidResource(location, dotPathValue.getPathElements(), errorManager); |
| |
| return context.getImplementationSimpleSourceName() + ".this." |
| + dotPathValue.getValue() + ".getSafeUri().asString()"; |
| } |
| |
| private void assertMethodIsValidResource(SourceCodeLocation location, List<String> pathElements, |
| ErrorManager errorManager) throws GssFunctionException { |
| JType methodType; |
| |
| try { |
| methodType = methodByPathHelper.getReturnType(context, pathElements); |
| } catch (NotFoundException e) { |
| String message = e.getMessage() != null ? e.getMessage() : "Invalid path"; |
| errorManager.report(new GssError(message, location)); |
| throw new GssFunctionException(message, e); |
| } |
| |
| if (!dataResourceType.isAssignableFrom((JClassType) methodType) && |
| !imageResourceType.isAssignableFrom((JClassType) methodType)) { |
| String message = "Invalid method type for url substitution: " + methodType + ". " + |
| "Only DataResource and ImageResource are supported."; |
| errorManager.report(new GssError(message, location)); |
| throw new GssFunctionException(message); |
| } |
| } |
| |
| private CssFunctionNode buildUrlNode(String javaExpression, SourceCodeLocation location) { |
| CssFunctionNode urlNode = GssFunctions.createUrlNode("", location); |
| CssJavaExpressionNode cssJavaExpressionNode = new CssJavaExpressionNode(javaExpression); |
| CssFunctionArgumentsNode arguments = |
| new CssFunctionArgumentsNode(ImmutableList.<CssValueNode>of(cssJavaExpressionNode)); |
| urlNode.setArguments(arguments); |
| |
| return urlNode; |
| } |
| } |