| /* |
| * 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.user.linker.rpc; |
| |
| 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.EmittedArtifact; |
| import com.google.gwt.core.ext.linker.EmittedArtifact.Visibility; |
| import com.google.gwt.core.ext.linker.LinkerOrder; |
| import com.google.gwt.core.ext.linker.LinkerOrder.Order; |
| import com.google.gwt.core.ext.linker.Shardable; |
| import com.google.gwt.core.ext.linker.SyntheticArtifact; |
| import com.google.gwt.dev.jjs.InternalCompilerException; |
| import com.google.gwt.dev.util.Util; |
| import com.google.gwt.user.rebind.rpc.ProxyCreator; |
| |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| /** |
| * Emit a file containing a map of RPC proxy classes to the partial path of the |
| * RPC policy file. |
| */ |
| @LinkerOrder(Order.PRE) |
| @Shardable |
| public class RpcPolicyManifestLinker extends AbstractLinker { |
| private static final String MANIFEST_TXT = "manifest.txt"; |
| |
| /** |
| * The main body of the manifest. It is built up as per-permutation manifests |
| * are looped over. |
| */ |
| private StringBuilder manifestBody = new StringBuilder(); |
| |
| @Override |
| public String getDescription() { |
| return "RPC policy file manifest"; |
| } |
| |
| @Override |
| public ArtifactSet link(TreeLogger logger, LinkerContext context, |
| ArtifactSet artifacts, boolean onePermutation) |
| throws UnableToCompleteException { |
| if (onePermutation) { |
| return artifacts; |
| } else { |
| for (EmittedArtifact art : artifacts.find(EmittedArtifact.class)) { |
| if (art.getPartialPath().startsWith(ProxyCreator.MANIFEST_ARTIFACT_DIR)) { |
| readOneManifest(logger, art.getContents(logger)); |
| } |
| } |
| |
| ArtifactSet toReturn = new ArtifactSet(artifacts); |
| SyntheticArtifact manifestArt = emitString(logger, |
| generateManifest(context), MANIFEST_TXT); |
| manifestArt.setVisibility(Visibility.LegacyDeploy); |
| toReturn.add(manifestArt); |
| return toReturn; |
| } |
| } |
| |
| /** |
| * Compute a manifest for all RPC policy files seen so far. |
| */ |
| private String generateManifest(LinkerContext context) { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("# Module " + context.getModuleName() + "\n"); |
| sb.append("# RPC service class, partial path of RPC policy file\n"); |
| sb.append(manifestBody.toString()); |
| return sb.toString(); |
| } |
| |
| /** |
| * Read one manifest and close the input stream. |
| */ |
| private void readOneManifest(TreeLogger logger, InputStream manifestStream) |
| throws UnableToCompleteException { |
| Map<String, String> entries = new HashMap<String, String>(); |
| try { |
| BufferedReader reader = new BufferedReader(new InputStreamReader( |
| manifestStream, Util.DEFAULT_ENCODING)); |
| String line; |
| while ((line = reader.readLine()) != null) { |
| int idx = line.indexOf(':'); |
| if (idx < 0) { |
| throw new InternalCompilerException( |
| "invalid selection information line: " + line); |
| } |
| String propName = line.substring(0, idx).trim(); |
| String propValue = line.substring(idx + 1).trim(); |
| entries.put(propName, propValue); |
| } |
| reader.close(); |
| } catch (IOException e) { |
| logger.log(TreeLogger.ERROR, "Unexpected IOException", e); |
| throw new UnableToCompleteException(); |
| } |
| |
| String serviceClass = entries.get("serviceClass"); |
| if (serviceClass == null) { |
| logger.log(TreeLogger.ERROR, |
| "Internal error: manifest file does not include a serviceClass"); |
| throw new UnableToCompleteException(); |
| } |
| String path = entries.get("path"); |
| if (path == null) { |
| logger.log(TreeLogger.ERROR, |
| "Internal error: manifest file does not include a path"); |
| throw new UnableToCompleteException(); |
| } |
| |
| manifestBody.append(serviceClass); |
| manifestBody.append(", "); |
| manifestBody.append(path); |
| manifestBody.append("\n"); |
| } |
| } |