blob: 5c16de1af318703e9f4dbf3b944ee4a00d7fae42 [file] [log] [blame]
/*
* Copyright 2011 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.web.bindery.requestfactory.vm.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Provides access to payload deobfuscation services for server and JVM-based
* clients. The deobfuscation data is baked into GWT-based clients by the
* generator.
*/
public class Deobfuscator {
/**
* Creates Deobfuscators.
*/
public static class Builder {
/**
* Load a pre-computed Builder from the classpath. The builder
* implementation is expected to have been generated by the annotation
* processor as part of the build process.
*
* @see com.google.web.bindery.requestfactory.apt.DeobfuscatorBuilder
* @see com.google.web.bindery.requestfactory.server.ResolverServiceLayer
*/
public static Builder load(Class<?> clazz, ClassLoader resolveClassesWith) {
Throwable ex;
try {
Class<?> found;
try {
// Used by the server
found = Class.forName(clazz.getName() + GENERATED_SUFFIX, false, resolveClassesWith);
} catch (ClassNotFoundException ignored) {
// Used by JRE-only clients
found = Class.forName(clazz.getName() + GENERATED_SUFFIX_LITE, false, resolveClassesWith);
}
Class<? extends Builder> builderClass = found.asSubclass(Builder.class);
Builder builder = builderClass.newInstance();
return builder;
} catch (ClassNotFoundException e) {
throw new RuntimeException("The RequestFactory ValidationTool must be run for the "
+ clazz.getCanonicalName() + " RequestFactory type");
} catch (InstantiationException e) {
ex = e;
} catch (IllegalAccessException e) {
ex = e;
}
throw new RuntimeException(ex);
}
private Deobfuscator d = new Deobfuscator();
{
d.domainToClientType = new HashMap<String, List<String>>();
d.operationData = new HashMap<OperationKey, OperationData>();
d.typeTokens = new HashMap<String, String>();
}
public Deobfuscator build() {
Deobfuscator toReturn = d;
toReturn.domainToClientType = Collections.unmodifiableMap(toReturn.domainToClientType);
toReturn.operationData = Collections.unmodifiableMap(toReturn.operationData);
toReturn.referencedTypes =
Collections.unmodifiableSet(new HashSet<String>(toReturn.typeTokens.values()));
toReturn.typeTokens = Collections.unmodifiableMap(toReturn.typeTokens);
d = null;
return toReturn;
}
public Builder merge(Deobfuscator existing) {
d.domainToClientType.putAll(existing.domainToClientType);
d.operationData.putAll(existing.operationData);
// referencedTypes recomputed in build()
d.typeTokens.putAll(existing.typeTokens);
return this;
}
public Builder withClientToDomainMappings(String domainBinaryName, List<String> value) {
List<String> clientBinaryNames;
switch (value.size()) {
case 0:
clientBinaryNames = Collections.emptyList();
break;
case 1:
clientBinaryNames = Collections.singletonList(value.get(0));
break;
default:
clientBinaryNames = Collections.unmodifiableList(new ArrayList<String>(value));
}
d.domainToClientType.put(domainBinaryName, clientBinaryNames);
return this;
}
public Builder withOperation(OperationKey key, OperationData data) {
d.operationData.put(key, data);
return this;
}
public Builder withRawTypeToken(String token, String binaryName) {
d.typeTokens.put(token, binaryName);
return this;
}
}
private static final String GENERATED_SUFFIX = "DeobfuscatorBuilder";
private static final String GENERATED_SUFFIX_LITE = GENERATED_SUFFIX + "Lite";
/**
* Maps domain types (e.g Foo) to client proxy types (e.g. FooAProxy,
* FooBProxy).
*/
private Map<String, List<String>> domainToClientType;
private Map<OperationKey, OperationData> operationData;
private Set<String> referencedTypes;
/**
* Map of obfuscated ids to binary class names.
*/
private Map<String, String> typeTokens;
Deobfuscator() {
}
/**
* Returns the client proxy types whose {@code @ProxyFor} is exactly
* {@code binaryTypeName}. Ordered such that the most-derived types will be
* iterated over first.
*/
public List<String> getClientProxies(String binaryTypeName) {
return domainToClientType.get(binaryTypeName);
}
/**
* Returns a method descriptor that should be invoked on the service object.
*/
public String getDomainMethodDescriptor(String operation) {
OperationData data = getData(operation);
return data == null ? null : data.getDomainMethodDescriptor();
}
public String getRequestContext(String operation) {
OperationData data = getData(operation);
return data == null ? null : data.getRequestContext();
}
public String getRequestContextMethodDescriptor(String operation) {
OperationData data = getData(operation);
return data == null ? null : data.getClientMethodDescriptor();
}
public String getRequestContextMethodName(String operation) {
OperationData data = getData(operation);
return data == null ? null : data.getMethodName();
}
/**
* Returns a type's binary name based on an obfuscated token.
*/
public String getTypeFromToken(String token) {
return typeTokens.get(token);
}
public boolean isReferencedType(String name) {
return referencedTypes.contains(name);
}
private OperationData getData(String operation) {
OperationData data = operationData.get(new OperationKey(operation));
return data;
}
}