| /* |
| * 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.client.impl; |
| |
| import com.google.gwt.autobean.shared.AutoBean; |
| import com.google.gwt.autobean.shared.AutoBeanUtils; |
| import com.google.gwt.editor.client.Editor; |
| import com.google.gwt.editor.client.EditorContext; |
| import com.google.gwt.editor.client.EditorVisitor; |
| import com.google.gwt.editor.client.impl.AbstractEditorDelegate; |
| import com.google.gwt.editor.client.impl.BaseEditorDriver; |
| import com.google.gwt.editor.client.impl.DelegateMap; |
| import com.google.gwt.editor.client.impl.DelegateMap.KeyMethod; |
| import com.google.gwt.editor.client.impl.SimpleViolation; |
| import com.google.gwt.event.shared.EventBus; |
| import com.google.gwt.requestfactory.client.HasRequestContext; |
| import com.google.gwt.requestfactory.client.RequestFactoryEditorDriver; |
| import com.google.gwt.requestfactory.shared.EntityProxy; |
| import com.google.gwt.requestfactory.shared.RequestContext; |
| import com.google.gwt.requestfactory.shared.RequestFactory; |
| import com.google.gwt.requestfactory.shared.ValueProxy; |
| import com.google.gwt.requestfactory.shared.Violation; |
| import com.google.gwt.requestfactory.shared.impl.Constants; |
| |
| import java.util.Iterator; |
| import java.util.List; |
| |
| /** |
| * Contains utility methods for top-level driver implementations. |
| * |
| * @param <R> the type being edited |
| * @param <E> the type of Editor |
| */ |
| public abstract class AbstractRequestFactoryEditorDriver<R, E extends Editor<R>> |
| extends BaseEditorDriver<R, E> implements RequestFactoryEditorDriver<R, E> { |
| |
| /** |
| * Adapts a RequestFactory Violation object to the SimpleViolation interface. |
| */ |
| static class SimpleViolationAdapter extends SimpleViolation { |
| private final Violation v; |
| |
| /** |
| * @param source |
| */ |
| private SimpleViolationAdapter(Violation v) { |
| this.v = v; |
| } |
| |
| public Object getKey() { |
| return v.getOriginalProxy(); |
| } |
| |
| public String getMessage() { |
| return v.getMessage(); |
| } |
| |
| public String getPath() { |
| return v.getPath(); |
| } |
| |
| public Object getUserDataObject() { |
| return v; |
| } |
| } |
| /** |
| * Provides a source of SimpleViolation objects based on RequestFactory's |
| * simplified Violation interface. |
| */ |
| static class ViolationIterable implements Iterable<SimpleViolation> { |
| |
| private final Iterable<Violation> violations; |
| |
| public ViolationIterable(Iterable<Violation> violations) { |
| this.violations = violations; |
| } |
| |
| public Iterator<SimpleViolation> iterator() { |
| final Iterator<Violation> source = violations.iterator(); |
| return new Iterator<SimpleViolation>() { |
| public boolean hasNext() { |
| return source.hasNext(); |
| } |
| |
| public SimpleViolation next() { |
| return new SimpleViolationAdapter(source.next()); |
| } |
| |
| public void remove() { |
| source.remove(); |
| } |
| }; |
| } |
| } |
| |
| /** |
| * Since the ValueProxy is being mutated in-place, we need a way to stabilize |
| * its hashcode for future equality checks. |
| */ |
| private static class ValueProxyHolder { |
| private final ValueProxy proxy; |
| |
| public ValueProxyHolder(ValueProxy proxy) { |
| this.proxy = proxy; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| return proxy.equals(((ValueProxyHolder) o).proxy); |
| } |
| |
| @Override |
| public int hashCode() { |
| return proxy.getClass().hashCode(); |
| } |
| } |
| |
| private static final DelegateMap.KeyMethod PROXY_ID_KEY = new DelegateMap.KeyMethod() { |
| public Object key(Object object) { |
| if (object instanceof EntityProxy) { |
| return ((EntityProxy) object).stableId(); |
| } else if (object instanceof ValueProxy) { |
| AutoBean<?> bean = AutoBeanUtils.getAutoBean(object); |
| // Possibly replace an editable ValueProxy with its immutable base |
| AutoBean<?> parent = bean.getTag(Constants.PARENT_OBJECT); |
| if (parent != null) { |
| object = parent.as(); |
| } |
| return new ValueProxyHolder((ValueProxy) object); |
| } |
| return null; |
| } |
| }; |
| |
| private EventBus eventBus; |
| private List<String> paths; |
| private RequestFactory factory; |
| private RequestContext saveRequest; |
| |
| public void display(R object) { |
| edit(object, null); |
| } |
| |
| public void edit(R object, final RequestContext saveRequest) { |
| this.saveRequest = saveRequest; |
| // Provide the delegate and maybe the editor with the RequestContext |
| accept(new EditorVisitor() { |
| @Override |
| public <T> void endVisit(EditorContext<T> ctx) { |
| RequestFactoryEditorDelegate<?, ?> delegate = (RequestFactoryEditorDelegate<?, ?>) ctx.getEditorDelegate(); |
| if (delegate != null) { |
| delegate.setRequestContext(saveRequest); |
| } |
| Editor<T> editor = ctx.getEditor(); |
| if (editor instanceof HasRequestContext) { |
| ((HasRequestContext<T>) editor).setRequestContext(saveRequest); |
| } |
| } |
| }); |
| doEdit(object); |
| } |
| |
| public RequestContext flush() { |
| checkSaveRequest(); |
| doFlush(); |
| return saveRequest; |
| } |
| |
| public String[] getPaths() { |
| return paths.toArray(new String[paths.size()]); |
| } |
| |
| public void initialize(E editor) { |
| doInitialize(null, null, editor); |
| } |
| |
| public void initialize(EventBus eventBus, RequestFactory requestFactory, |
| E editor) { |
| assert eventBus != null : "eventBus must not be null"; |
| assert requestFactory != null : "requestFactory must not be null"; |
| doInitialize(eventBus, requestFactory, editor); |
| } |
| |
| public void initialize(RequestFactory requestFactory, E editor) { |
| initialize(requestFactory.getEventBus(), requestFactory, editor); |
| } |
| |
| public boolean setViolations(Iterable<Violation> violations) { |
| return doSetViolations(new ViolationIterable(violations)); |
| } |
| |
| protected void checkSaveRequest() { |
| if (saveRequest == null) { |
| throw new IllegalStateException("edit() was called with a null Request"); |
| } |
| } |
| |
| @Override |
| protected void configureDelegate(AbstractEditorDelegate<R, E> rootDelegate) { |
| ((RequestFactoryEditorDelegate<R, E>) rootDelegate).initialize(eventBus, |
| factory, "", getEditor()); |
| } |
| |
| protected void doInitialize(EventBus eventBus, RequestFactory requestFactory, |
| E editor) { |
| this.eventBus = eventBus; |
| this.factory = requestFactory; |
| super.doInitialize(editor); |
| PathCollector c = new PathCollector(); |
| accept(c); |
| this.paths = c.getPaths(); |
| } |
| |
| @Override |
| protected KeyMethod getViolationKeyMethod() { |
| return PROXY_ID_KEY; |
| } |
| } |