blob: c0367fa32c123f83d612b4edff3563cf73430c37 [file] [log] [blame]
/*
* Copyright 2010 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.core.ext.linker.impl;
import com.google.gwt.core.ext.LinkerContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.SelectionProperty;
import com.google.gwt.dev.util.StringKey;
import com.google.gwt.dev.util.collect.HashSet;
import com.google.gwt.dev.util.collect.Lists;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* A utility class to help linkers generate a list of permutation mappings and
* and then either output them to javascript code which selects the correct
* permutation, or to a file which can be parsed by server side code.
*/
public class PermutationsUtil {
/**
* This represents the combination of a unique content hash (i.e. the MD5 of
* the bytes to be written into the cache.html file) and a soft permutation
* id.
*/
protected static class PermutationId extends StringKey {
private final int softPermutationId;
private final String strongName;
public PermutationId(String strongName, int softPermutationId) {
super(strongName + ":" + softPermutationId);
this.strongName = strongName;
this.softPermutationId = softPermutationId;
}
public int getSoftPermutationId() {
return softPermutationId;
}
public String getStrongName() {
return strongName;
}
}
/**
* This maps each unique permutation to the property settings for that
* compilation. A single compilation can have multiple property settings if
* the compiles for those settings yielded the exact same compiled output.
*/
protected SortedMap<PermutationId, List<Map<String, String>>> propMapsByPermutation =
new TreeMap<PermutationId, List<Map<String, String>>>();
/**
* Uses the internal map to insert JS to select a permutation into the
* selection script.
*
* @param selectionScript
* @param logger
* @param context
* @return the modified selectionScript buffer
* @throws UnableToCompleteException
*/
public StringBuffer addPermutationsJs(StringBuffer selectionScript,
TreeLogger logger, LinkerContext context)
throws UnableToCompleteException {
int startPos;
PropertiesUtil.addPropertiesJs(selectionScript, logger, context);
// Possibly add permutations
startPos = selectionScript.indexOf("// __PERMUTATIONS_END__");
if (startPos != -1) {
StringBuffer text = new StringBuffer();
if (propMapsByPermutation.size() == 0) {
// Hosted mode link.
text.append("alert(\"GWT module '" + context.getModuleName()
+ "' may need to be (re)compiled\");");
text.append("return;");
} else if (propMapsByPermutation.size() == 1) {
// Just one distinct compilation; no need to evaluate properties
text.append("strongName = '"
+ propMapsByPermutation.keySet().iterator().next().getStrongName()
+ "';");
} else {
Set<String> propertiesUsed = new HashSet<String>();
for (PermutationId permutationId : propMapsByPermutation.keySet()) {
for (Map<String, String> propertyMap : propMapsByPermutation.get(permutationId)) {
// unflatten([v1, v2, v3], 'strongName' + ':softPermId');
// The soft perm ID is concatenated to improve string interning
text.append("unflattenKeylistIntoAnswers([");
boolean needsComma = false;
for (SelectionProperty p : context.getProperties()) {
if (p.tryGetValue() != null) {
continue;
} else if (p.isDerived()) {
continue;
}
if (needsComma) {
text.append(",");
} else {
needsComma = true;
}
text.append("'" + propertyMap.get(p.getName()) + "'");
propertiesUsed.add(p.getName());
}
text.append("], '").append(permutationId.getStrongName()).append(
"'");
/*
* For compatibility with older linkers, skip the soft permutation
* if it's 0
*/
if (permutationId.getSoftPermutationId() != 0) {
text.append(" + ':").append(permutationId.getSoftPermutationId()).append(
"'");
}
text.append(");\n");
}
}
// strongName = answers[compute('p1')][compute('p2')];
text.append("strongName = answers[");
boolean needsIndexMarkers = false;
for (SelectionProperty p : context.getProperties()) {
if (!propertiesUsed.contains(p.getName())) {
continue;
}
if (needsIndexMarkers) {
text.append("][");
} else {
needsIndexMarkers = true;
}
text.append("computePropValue('" + p.getName() + "')");
}
text.append("];");
}
selectionScript.insert(startPos, text);
}
return selectionScript;
}
public SortedMap<PermutationId, List<Map<String, String>>> getPermutationsMap() {
return propMapsByPermutation;
}
/**
* Find all instances of {@link SelectionInformation} and add them to the
* internal map of selection information.
*/
public void setupPermutationsMap(ArtifactSet artifacts) {
propMapsByPermutation =
new TreeMap<PermutationId, List<Map<String, String>>>();
for (SelectionInformation selInfo : artifacts.find(SelectionInformation.class)) {
TreeMap<String, String> entries = selInfo.getPropMap();
PermutationId permutationId = new PermutationId(selInfo.getStrongName(),
selInfo.getSoftPermutationId());
if (!propMapsByPermutation.containsKey(permutationId)) {
propMapsByPermutation.put(permutationId,
Lists.<Map<String, String>> create(entries));
} else {
propMapsByPermutation.put(permutationId, Lists.add(
propMapsByPermutation.get(permutationId), entries));
}
}
}
}