org.eclipselabs.emfjson.gwt.map.EReferenceResolver.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipselabs.emfjson.gwt.map.EReferenceResolver.java

Source

/*******************************************************************************
 * 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();
    }
}