com.google.gwt.requestfactory.server.Resolver Maven / Gradle / Ivy
/*
* 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.requestfactory.server;
import com.google.gwt.autobean.server.impl.TypeUtils;
import com.google.gwt.autobean.shared.AutoBean;
import com.google.gwt.autobean.shared.AutoBeanUtils;
import com.google.gwt.autobean.shared.AutoBeanVisitor;
import com.google.gwt.autobean.shared.Splittable;
import com.google.gwt.autobean.shared.ValueCodex;
import com.google.gwt.requestfactory.shared.BaseProxy;
import com.google.gwt.requestfactory.shared.EntityProxy;
import com.google.gwt.requestfactory.shared.EntityProxyId;
import com.google.gwt.requestfactory.shared.impl.Constants;
import com.google.gwt.requestfactory.shared.impl.SimpleProxyId;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
* Responsible for converting between domain and client entities. This class has
* a small amount of temporary state used to handle graph cycles and assignment
* of synthetic ids.
*
* RequestFactory has moved to
* com.google.web.bindery.requestfactory
. This package will be
* removed in a future version of GWT.
*
* @see RequestState#getResolver()
*/
@Deprecated
class Resolver {
/**
* A parameterized type with a single parameter.
*/
private static class CollectionType implements ParameterizedType {
private final Class> rawType;
private final Class> elementType;
private CollectionType(Class> rawType, Class> elementType) {
this.rawType = rawType;
this.elementType = elementType;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof CollectionType)) {
return false;
}
CollectionType other = (CollectionType) o;
return rawType.equals(other.rawType)
&& elementType.equals(other.elementType);
}
public Type[] getActualTypeArguments() {
return new Type[] {elementType};
}
public Type getOwnerType() {
return null;
}
public Type getRawType() {
return rawType;
}
@Override
public int hashCode() {
return rawType.hashCode() * 13 + elementType.hashCode() * 7;
}
}
/**
* Used to map the objects being resolved and its API slice to the client-side
* value. This handles the case where a domain object is returned to the
* client mapped to two proxies of differing types.
*/
private static class ResolutionKey {
private final Object domainObject;
private final int hashCode;
private final Type requestedType;
public ResolutionKey(Object domainObject, Type requestedType) {
this.domainObject = domainObject;
this.requestedType = requestedType;
this.hashCode = System.identityHashCode(domainObject) * 13
+ requestedType.hashCode() * 7;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ResolutionKey)) {
return false;
}
ResolutionKey other = (ResolutionKey) o;
// Object identity comparison intentional
if (domainObject != other.domainObject) {
return false;
}
if (!requestedType.equals(other.requestedType)) {
return false;
}
return true;
}
@Override
public int hashCode() {
return hashCode;
}
/**
* For debugging use only.
*/
@Override
public String toString() {
return domainObject.toString() + " => " + requestedType.toString();
}
}
/**
* Returns the trailing {@code [n]} index value from a path.
*/
static int index(String path) {
int idx = path.lastIndexOf('[');
if (idx == -1) {
return -1;
}
return Integer.parseInt(path.substring(idx + 1, path.lastIndexOf(']')));
}
/**
* Returns {@code true} if the given prefix is one of the requested property
* references.
*/
static boolean matchesPropertyRef(Set propertyRefs, String newPrefix) {
return propertyRefs.contains(newPrefix.replaceAll("\\[\\d+\\]", ""));
}
/**
* Removes the trailing {@code [n]} from a path.
*/
static String snipIndex(String path) {
int idx = path.lastIndexOf('[');
if (idx == -1) {
return path;
}
return path.substring(0, idx);
}
/**
* Maps domain values to client values. This map prevents cycles in the object
* graph from causing infinite recursion.
*/
private final Map resolved = new HashMap();
private final ServiceLayer service;
private final RequestState state;
private int syntheticId;
/**
* Should only be called from {@link RequestState}.
*/
Resolver(RequestState state) {
this.state = state;
this.service = state.getServiceLayer();
}
/**
* Given a domain object, return a value that can be encoded by the client.
*
* @param domainValue the domain object to be converted into a client-side
* value
* @param assignableTo the type in the client to which the resolved value
* should be assignable. A value of {@code null} indicates that any
* resolution will suffice.
* @param propertyRefs the property references requested by the client
*/
public Object resolveClientValue(Object domainValue, Type assignableTo,
Set propertyRefs) {
return resolveClientValue(domainValue, assignableTo,
getPropertyRefs(propertyRefs), "");
}
/**
* Convert a client-side value into a domain value.
*
* @param maybeEntityProxy the client object to resolve
* @param detectDeadEntities if true
this method will throw a
* ReportableException containing a {@link DeadEntityException} if an
* EntityProxy cannot be resolved
*/
public Object resolveDomainValue(Object maybeEntityProxy,
boolean detectDeadEntities) {
if (maybeEntityProxy instanceof BaseProxy) {
AutoBean bean = AutoBeanUtils.getAutoBean((BaseProxy) maybeEntityProxy);
Object domain = bean.getTag(Constants.DOMAIN_OBJECT);
if (domain == null && detectDeadEntities) {
throw new ReportableException(new DeadEntityException(
"The requested entity is not available on the server"));
}
return domain;
} else if (maybeEntityProxy instanceof Collection>) {
Collection