Java tutorial
/******************************************************************************* * Copyright (c) 2013 Guillaume Hillairet. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Guillaume Hillairet - initial API and implementation *******************************************************************************/ package org.eclipselabs.emfjson.gwt.map; import static org.eclipselabs.emfjson.gwt.common.Constants.EJS_REF_KEYWORD; import static org.eclipselabs.emfjson.gwt.common.ModelUtil.getEObjectURI; import static org.eclipselabs.emfjson.gwt.common.ModelUtil.getEReference; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.emf.common.util.Callback; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.InternalEList; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONValue; class EReferenceResolver { private Deserializer deserializer; EReferenceResolver(Deserializer deserializer) { this.deserializer = deserializer; } void resolve(Map<EObject, JSONObject> processed, Resource resource, final Callback<EObject> callback) { resolve(processed.keySet().iterator(), resource, processed, callback); } void resolve(Map<EObject, JSONObject> processed, Resource resource) { for (EObject eObject : processed.keySet()) { resolve(eObject, processed.get(eObject), resource, processed); } } void resolve(EObject eObject, JSONObject node, Resource resource, Map<EObject, JSONObject> processed) { if (node == null) return; final EClass eClass = eObject.eClass(); for (String key : node.keySet()) { JSONValue value = node.get(key); EReference reference = getEReference(eClass, key); if (isCandidate(reference)) { JSONArray array = value.isArray(); if (array != null) { for (int i = 0; i < array.size(); i++) { JSONValue current = array.get(i); createProxyReference(eObject, current.isObject(), reference, resource); } } else { createProxyReference(eObject, value.isObject(), reference, resource); } } } } void resolve(final Iterator<EObject> iterator, final Resource resource, final Map<EObject, JSONObject> processed, final Callback<EObject> callback) { if (iterator.hasNext()) { EObject eObject = iterator.next(); JSONObject node = processed.get(eObject); EClass eClass = eObject.eClass(); Map<EReference, JSONValue> pairs = new HashMap<EReference, JSONValue>(); for (String key : node.keySet()) { JSONValue value = node.get(key); EReference reference = getEReference(eClass, key); if (isCandidate(reference)) pairs.put(reference, value); } resolve(eObject, resource, pairs, pairs.keySet().iterator(), new Callback<EObject>() { @Override public void onFailure(Throwable caught) { callback.onFailure(caught); } @Override public void onSuccess(EObject result) { resolve(iterator, resource, processed, callback); } }); } else { callback.onSuccess(null); } } void createProxyReferenceEach(final EObject eObject, final EReference reference, final Resource resource, final JSONArray array, int pos, final Callback<EObject> callback) { if (pos < array.size()) { JSONObject current = array.get(pos).isObject(); final int next = ++pos; if (current != null) { createProxyReference(eObject, current, reference, resource, new Callback<EObject>() { @Override public void onFailure(Throwable caught) { callback.onFailure(caught); } @Override public void onSuccess(EObject result) { createProxyReferenceEach(eObject, reference, resource, array, next, callback); } }); } else { createProxyReferenceEach(eObject, reference, resource, array, next, callback); } } else { callback.onSuccess(eObject); } } void resolve(final EObject eObject, final Resource resource, final Map<EReference, JSONValue> pairs, final Iterator<EReference> keys, final Callback<EObject> callback) { if (keys.hasNext()) { EReference reference = keys.next(); JSONValue value = pairs.get(reference); JSONArray array = value.isArray(); if (array != null && reference.isMany()) { createProxyReferenceEach(eObject, reference, resource, array, 0, new Callback<EObject>() { @Override public void onSuccess(EObject result) { resolve(eObject, resource, pairs, keys, callback); } @Override public void onFailure(Throwable caught) { callback.onFailure(caught); } }); } JSONObject object = value.isObject(); if (object != null && !reference.isMany()) { createProxyReference(eObject, object, reference, resource, new Callback<EObject>() { @Override public void onSuccess(EObject result) { resolve(eObject, resource, pairs, keys, callback); } @Override public void onFailure(Throwable caught) { callback.onFailure(caught); } }); } } else { callback.onSuccess(eObject); } } EObject createProxyReference(final EObject eObject, JSONObject node, final EReference reference, final Resource resource) { EObject proxy = getOrCreateProxyReference(reference, node, resource); if (proxy != null && reference.isMany()) { @SuppressWarnings("unchecked") InternalEList<EObject> values = (InternalEList<EObject>) eObject.eGet(reference); values.addUnique(proxy); } else if (proxy != null) { eObject.eSet(reference, proxy); } return proxy; } void createProxyReference(final EObject eObject, JSONObject node, final EReference reference, final Resource resource, final Callback<EObject> callback) { getOrCreateProxyReference(reference, node, resource, new Callback<EObject>() { @Override public void onFailure(Throwable caught) { callback.onFailure(caught); } @Override public void onSuccess(EObject result) { if (result != null && reference.isMany()) { @SuppressWarnings("unchecked") InternalEList<EObject> values = (InternalEList<EObject>) eObject.eGet(reference); values.addUnique(result); } else if (result != null) { eObject.eSet(reference, result); } callback.onSuccess(result); } }); } void getOrCreateProxyReference(final EReference reference, final JSONObject node, final Resource resource, final Callback<EObject> callback) { findEObject(resource, node, new Callback<EObject>() { @Override public void onFailure(Throwable caught) { callback.onFailure(caught); } @Override public void onSuccess(EObject obj) { if (obj == null && node != null) { JSUtil.findEClass(reference.getEReferenceType(), node, resource, deserializer.getNamespaces(), new Callback<EClass>() { @Override public void onSuccess(EClass result) { ProxyFactory factory = deserializer.getProxyFactory(); EObject proxy = factory.createProxy(resource, result, node); callback.onSuccess(proxy); } @Override public void onFailure(Throwable caught) { callback.onFailure(caught); } }); } else { callback.onSuccess(obj); } } }); } EObject getOrCreateProxyReference(final EReference reference, final JSONObject node, final Resource resource) { EObject eObject = findEObject(resource, node); if (eObject == null && node != null) { EClass refClass = JSUtil.findEClass(reference.getEReferenceType(), node, resource, deserializer.getNamespaces()); eObject = deserializer.getProxyFactory().createProxy(resource, refClass, node); } return eObject; } void findEObject(Resource resource, JSONValue node, Callback<EObject> callback) { if (node.isObject() != null) { final URI objectURI = getEObjectURI(node.isObject().get(EJS_REF_KEYWORD), resource, deserializer.getNamespaces()); resource.getResourceSet().getEObject(objectURI, callback); } else { callback.onFailure(new Throwable("Fail find EObject reference from " + node)); } } EObject findEObject(Resource resource, JSONValue node) { if (node.isObject() != null) { JSONValue ref = node.isObject().get(EJS_REF_KEYWORD); final URI objectURI = getEObjectURI(ref, resource, deserializer.getNamespaces()); return resource.getResourceSet().getEObject(objectURI, true); } else { return null; } } boolean isCandidate(EReference reference) { return reference != null && !reference.isContainment() && !reference.isDerived() && !reference.isTransient(); } }