package org.sigmah.linker;
/*
* #%L
* Sigmah
* %%
* Copyright (C) 2010 - 2016 URD
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.SortedSet;
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.AbstractLinker;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.CompilationResult;
import com.google.gwt.core.ext.linker.EmittedArtifact;
import com.google.gwt.core.ext.linker.LinkerOrder;
import com.google.gwt.core.ext.linker.LinkerOrder.Order;
import com.google.gwt.core.ext.linker.SelectionProperty;
/**
* Generates manifest files for offline mode.
* A manifest is created for each permutation (named browser.language.manifest).
*
* @author Raphaƫl Calabro <rcalabro at ideia.fr>
*/
@LinkerOrder(Order.POST)
public class ManifestGenerationLinker extends AbstractLinker {
public static final Boolean PREFER_ONLINE = true;
public static final String MODULE_NAME = "sigmah";
@Override
public String getDescription() {
return "Generates HTML5 manifests for each browsers.";
}
@Override
public ArtifactSet link(TreeLogger logger, LinkerContext context, ArtifactSet artifacts) throws UnableToCompleteException {
final ArtifactSet artifactSet = new ArtifactSet(artifacts);
final SortedSet<EmittedArtifact> emittedArtifacts = artifacts.find(EmittedArtifact.class);
final SortedSet<CompilationResult> compilationResults = artifacts.find(CompilationResult.class);
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
final HashMap<Manifest, StringBuilder> manifests = new HashMap<>();
final Map<String, Manifest> permutationMap = new HashMap<>();
for(final CompilationResult compilationResult : compilationResults) {
final String permutationName = compilationResult.getStrongName();
for(final SortedMap<SelectionProperty, String> map : compilationResult.getPropertyMap()) {
String userAgent = null;
String locale = null;
for(Map.Entry<SelectionProperty, String> entry : map.entrySet()) {
if(entry.getKey().getName().equals("user.agent")) {
userAgent = entry.getValue();
}
if(entry.getKey().getName().equals("locale")) {
locale = entry.getValue();
}
}
final Manifest manifest = new Manifest(userAgent, locale);
System.out.println(" Permutation '" + permutationName + "' : " + manifest);
permutationMap.put(permutationName, manifest);
addManifest(manifests, manifest, dateFormat);
}
}
if(permutationMap.isEmpty()) {
addManifest(manifests, new Manifest(), dateFormat);
}
appendToAll(manifests, MODULE_NAME + ".nocache.js\n");
appendToAll(manifests, MODULE_NAME + ".extra.nocache.js\n");
for(EmittedArtifact artifact : emittedArtifacts) {
if(EmittedArtifact.Visibility.Public.matches(artifact.getVisibility())) {
final String partialPath = artifact.getPartialPath();
Manifest manifest = null;
for(Map.Entry<String, Manifest> entry : permutationMap.entrySet()) {
if(partialPath.contains(entry.getKey())) {
manifest = entry.getValue();
break;
}
}
final StringBuilder manifestBuilder = manifests.get(manifest);
if(manifestBuilder != null) {
manifestBuilder.append(artifact.getPartialPath())
.append("\n");
} else if(!partialPath.startsWith("manuals/")) {
appendToAll(manifests, artifact.getPartialPath())
.appendToAll(manifests, "\n");
}
}
}
// Generating offline fallback sources
appendToAll(manifests, "FALLBACK:\nonline.nocache.json offline.nocache.json\n");
artifactSet.add(emitString(logger, "{\"online\": false}", "offline.nocache.json"));
artifactSet.add(emitString(logger, "{\"online\": true}", "online.nocache.json"));
appendToAll(manifests, "is_online.nocache.js is_offline.nocache.js\n");
artifactSet.add(emitString(logger, "window.online = false;", "is_offline.nocache.js"));
artifactSet.add(emitString(logger, "window.online = true;", "is_online.nocache.js"));
appendToAll(manifests, "export export_offline.html\n");
artifactSet.add(emitString(logger, "<html><header><title>Sigmah</title></header><body>Export functionality is only available when online.</body></html>", "export_offline.html"));
if(PREFER_ONLINE) {
appendToAll(manifests, "SETTINGS:\nprefer-online\n");
}
appendToAll(manifests, "NETWORK:\n*");
for(Map.Entry<Manifest, StringBuilder> entry : manifests.entrySet()) {
artifactSet.add(emitString(logger, entry.getValue().toString(), entry.getKey().toFileName()));
}
return artifactSet;
}
private void addManifest(final HashMap<Manifest, StringBuilder> manifests, final Manifest manifest, final SimpleDateFormat dateFormat) {
StringBuilder userAgentManifest = manifests.get(manifest);
if(userAgentManifest == null) {
userAgentManifest = new StringBuilder("CACHE MANIFEST\n")
.append("# Generation date: ")
.append(dateFormat.format(new Date()))
.append("\n");
manifests.put(manifest, userAgentManifest);
}
}
private ManifestGenerationLinker appendToAll(Map<Manifest, StringBuilder> map, String s) {
for(StringBuilder stringBuilder : map.values()) {
stringBuilder.append(s);
}
return this;
}
}