| /******************************************************************************* |
| * Copyright (c) 2018 Agence spatiale canadienne / Canadian Space Agency |
| * 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: |
| * Mathieu Larose (Savoir-faire Linux) - Initial API and implementation |
| * |
| * SPDX-License-Identifier: EPL-1.0 |
| * |
| *******************************************************************************/ |
| package org.eclipse.apogy.core.programs.javascript; |
| |
| import java.lang.reflect.Method; |
| |
| import org.eclipse.apogy.common.emf.ApogyCommonEMFFacade; |
| import org.eclipse.apogy.common.emf.ApogyCommonEMFFactory; |
| import org.eclipse.apogy.common.emf.ListFeatureNode; |
| import org.eclipse.apogy.common.emf.ListRootNode; |
| import org.eclipse.apogy.core.invocator.ApogyCoreInvocatorFacade; |
| import org.eclipse.apogy.core.invocator.TypeMember; |
| import org.eclipse.apogy.core.invocator.TypeMemberReferenceListElement; |
| import org.eclipse.apogy.core.invocator.VariableFeatureReference; |
| import org.eclipse.emf.ecore.EAttribute; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EOperation; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.mozilla.javascript.Scriptable; |
| import org.mozilla.javascript.ScriptableObject; |
| |
| /** |
| * Proxy for an EObject obtained through a {@link TypeMember} |
| * |
| */ |
| public class TypeMemberProxy extends ScriptableObject { |
| private static final long serialVersionUID = 1L; |
| |
| private VariableFeatureReference variableFeatureReference; |
| private JavaScriptProgram program; |
| |
| public TypeMemberProxy() { |
| // Rhino requires an empty constructor |
| } |
| |
| /** |
| * |
| * @param variableFeatureReference {@link VariableFeaturerReference} |
| * representing the EObject wrapped by this |
| * classs |
| * @param program JavaScriptProgram being executed |
| * @throws NoSuchMethodException |
| * @throws SecurityException |
| */ |
| public TypeMemberProxy(VariableFeatureReference variableFeatureReference, JavaScriptProgram program) |
| throws NoSuchMethodException, SecurityException { |
| this.variableFeatureReference = variableFeatureReference; |
| this.program = program; |
| init(); |
| } |
| |
| private void init() throws NoSuchMethodException, SecurityException { |
| EObject instance = ApogyCoreInvocatorFacade.INSTANCE.getInstance(this.variableFeatureReference); |
| |
| for (EOperation operation : ApogyCommonEMFFacade.INSTANCE.getAllAvailableEOperations(instance.eClass())) { |
| defineProperty(operation.getName(), |
| new OperationCallInvoker(this.program, this.variableFeatureReference, operation), 0); |
| } |
| |
| for (EStructuralFeature structuralFeature : instance.eClass().getEAllStructuralFeatures()) { |
| if (structuralFeature instanceof EReference) { |
| ReferenceGetter referenceGetter = new ReferenceGetter(structuralFeature); |
| Method getter = ReferenceGetter.class.getDeclaredMethod("get", new Class[] { Scriptable.class }); |
| defineProperty(structuralFeature.getName(), referenceGetter, getter, null, 0); |
| } else if (structuralFeature instanceof EAttribute) { |
| AttributeGetter attributeGetter = new AttributeGetter(this.variableFeatureReference, structuralFeature); |
| Method getter = AttributeGetter.class.getDeclaredMethod("get", new Class[] { Scriptable.class }); |
| defineProperty(structuralFeature.getName(), attributeGetter, getter, null, 0); |
| } |
| } |
| |
| TypeMemberReferenceListElement child = this.variableFeatureReference.getTypeMemberReferenceListElement(); |
| |
| while (child != null) { |
| for (TypeMember typeMember : child.getTypeMember().getMemberType().getMembers()) { |
| // If the property already exists and is read-only, defineProperty |
| // is ignored. |
| // |
| // Delete the property in case it already exists and is |
| // read-only (which is likely the case since we defined read-only |
| // properties for all EReferences in the loop above). |
| delete(typeMember.getName()); |
| |
| TypeMemberGetter typeMemberGetter = new TypeMemberGetter(typeMember); |
| Method getter = TypeMemberGetter.class.getDeclaredMethod("get", new Class[] { Scriptable.class }); |
| defineProperty(typeMember.getName(), typeMemberGetter, getter, null, 0); |
| } |
| |
| child = child.getChild(); |
| |
| } |
| } |
| |
| @Override |
| public String getClassName() { |
| return "TypeMemberProxy"; |
| } |
| |
| /** |
| * Gets a reference of the EObject wrapped by {@link TypeMemberProxy} |
| * |
| */ |
| private class ReferenceGetter { |
| private final EStructuralFeature feature; |
| |
| public ReferenceGetter(EStructuralFeature feature) { |
| this.feature = feature; |
| } |
| |
| /** |
| * Returns the reference (represented by this class) of the EObject (represented |
| * by {@TypeMemberProxy}) |
| * |
| * @param self The JavaScript object |
| * @return the attribute |
| */ |
| @SuppressWarnings("unused") |
| public Object get(Scriptable self) throws NoSuchMethodException, SecurityException { |
| assert TypeMemberProxy.this.variableFeatureReference.getFeatureRoot() == null; |
| |
| VariableFeatureReference subVariableFeatureReference = EcoreUtil |
| .copy(TypeMemberProxy.this.variableFeatureReference); |
| |
| ListRootNode root = ApogyCommonEMFFactory.eINSTANCE.createListRootNode(); |
| ListFeatureNode node = ApogyCommonEMFFactory.eINSTANCE.createListFeatureNode(); |
| node.setStructuralFeature(this.feature); |
| root.setChild(node); |
| EObject instance = ApogyCoreInvocatorFacade.INSTANCE |
| .getInstance(TypeMemberProxy.this.variableFeatureReference); |
| root.setSourceClass(instance.eClass()); |
| subVariableFeatureReference.setFeatureRoot(root); |
| |
| Scriptable object = new ReferenceProxy(subVariableFeatureReference, TypeMemberProxy.this.program); |
| object.setParentScope(TypeMemberProxy.this); |
| return object; |
| } |
| } |
| |
| /** |
| * Gets a type member of the EObject wrapped by {@link TypeMemberProxy} |
| * |
| */ |
| private class TypeMemberGetter { |
| private final TypeMember typeMember; |
| |
| public TypeMemberGetter(TypeMember typeMember) { |
| this.typeMember = typeMember; |
| } |
| |
| /** |
| * Returns the type member (represented by this class) of the EObject |
| * (represented by {TypeMemberProxy}) |
| * |
| * @param self The JavaScript object |
| * @return the attribute |
| */ |
| @SuppressWarnings("unused") |
| public TypeMemberProxy get(Scriptable self) throws NoSuchMethodException, SecurityException { |
| VariableFeatureReference subVariableFeatureReference = EcoreUtil |
| .copy(TypeMemberProxy.this.variableFeatureReference); |
| |
| VariableFeatureReferenceUtil util = new VariableFeatureReferenceUtil(); |
| util.createTypeMemberHierarchy(subVariableFeatureReference, this.typeMember); |
| |
| return new TypeMemberProxy(subVariableFeatureReference, TypeMemberProxy.this.program); |
| } |
| } |
| } |