blob: 9310c122c9344de828c77e6a5d4d54500a557738 [file] [log] [blame]
/*******************************************************************************
* 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.AbstractFeatureListNode;
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.ApogyCoreInvocatorFactory;
import org.eclipse.apogy.core.invocator.TypeMember;
import org.eclipse.apogy.core.invocator.Variable;
import org.eclipse.apogy.core.invocator.VariableFeatureReference;
import org.eclipse.emf.ecore.EAttribute;
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 Apogy variable.
*
*/
public class VariableProxy extends ScriptableObject {
private static final long serialVersionUID = 1L;
private VariableFeatureReference variableFeatureReference;
private Variable variable;
private JavaScriptProgram program;
public VariableProxy() {
// Rhino requires an empty constructor
}
/**
*
* @param variable Apogy variable
* @param program JavaScriptProgram being executed
* @throws NoSuchMethodException
* @throws SecurityException
*/
public VariableProxy(Variable variable, JavaScriptProgram program) throws NoSuchMethodException, SecurityException {
this.variable = variable;
this.program = program;
init();
}
private void init() throws NoSuchMethodException, SecurityException {
this.variableFeatureReference = ApogyCoreInvocatorFactory.eINSTANCE.createVariableFeatureReference();
this.variableFeatureReference.setVariable(this.variable);
for (EOperation op : ApogyCommonEMFFacade.INSTANCE
.getAllAvailableEOperations(this.variable.getVariableType().getInterfaceClass())) {
defineProperty(op.getName(), new OperationCallInvoker(this.program, this.variableFeatureReference, op), 0);
}
for (EStructuralFeature structuralFeature : this.variable.getVariableType().getInterfaceClass()
.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);
}
}
for (TypeMember typeMember : this.variable.getVariableType().getMembers()) {
recursiveInit(typeMember);
}
}
private void recursiveInit(TypeMember typeMember) throws NoSuchMethodException, SecurityException {
// 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);
for (TypeMember subMember : typeMember.getMemberType().getMembers()) {
recursiveInit(subMember);
}
}
@Override
public String getClassName() {
return "Proxy";
}
public String getName() {
return this.variable.getName();
}
/**
* Gets a reference of the EObject wrapped by {@link VariableProxy}
*
*/
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 {@VariableProxy})
*
* @param self The JavaScript object
* @return the attribute
*/
@SuppressWarnings("unused")
public Object get(Scriptable self) throws NoSuchMethodException, SecurityException {
VariableFeatureReference subVariableFeatureReference = VariableFeatureReferenceUtil
.clone(VariableProxy.this.variableFeatureReference);
ListRootNode listRootNode = ApogyCommonEMFFactory.eINSTANCE.createListRootNode();
listRootNode.setSourceClass(VariableProxy.this.variable.getVariableType().getInterfaceClass());
subVariableFeatureReference.setFeatureRoot(listRootNode);
AbstractFeatureListNode leaf = ApogyCommonEMFFacade.INSTANCE
.getLeaf(subVariableFeatureReference.getFeatureRoot());
ListFeatureNode node = ApogyCommonEMFFactory.eINSTANCE.createListFeatureNode();
node.setStructuralFeature(this.feature);
leaf.setChild(node);
Scriptable object = new ReferenceProxy(subVariableFeatureReference, VariableProxy.this.program);
object.setParentScope(VariableProxy.this);
return object;
}
}
/**
* Gets a type member of the EObject wrapped by {@link @VariableProxy}
*
*/
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 {@VariableProxy})
*
* @param self The JavaScript object
* @return the attribute
*/
@SuppressWarnings("unused")
public Object get(Scriptable self) throws NoSuchMethodException, SecurityException {
VariableFeatureReference subVariableFeatureReference = EcoreUtil
.copy(VariableProxy.this.variableFeatureReference);
VariableFeatureReferenceUtil util = new VariableFeatureReferenceUtil();
util.createTypeMemberHierarchy(subVariableFeatureReference, this.typeMember);
TypeMemberProxy object = new TypeMemberProxy(subVariableFeatureReference, VariableProxy.this.program);
object.setParentScope(VariableProxy.this);
return object;
}
}
}