/******************************************************************************* * Copyright (c) 2006-2013 The RCP Company and others. * 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: * The RCP Company - initial API and implementation *******************************************************************************/ package com.rcpcompany.uibindings.internal.scripting; import java.util.Iterator; import java.util.Map; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.list.WritableList; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.Platform; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.NotificationChain; import org.eclipse.emf.common.notify.impl.AdapterImpl; import org.eclipse.emf.common.util.BasicEMap; import org.eclipse.emf.common.util.BasicEMap.Entry; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.EMap; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.impl.EObjectImpl; import org.eclipse.emf.ecore.util.EcoreEMap; import org.eclipse.emf.ecore.util.InternalEList; import com.rcpcompany.uibindings.internal.InternalConstants; import com.rcpcompany.uibindings.scripting.IScriptDependency; import com.rcpcompany.uibindings.scripting.IScriptEngineDescriptor; import com.rcpcompany.uibindings.scripting.IScriptEngineFactory; import com.rcpcompany.uibindings.scripting.IScriptEnginePackage; import com.rcpcompany.uibindings.scripting.IScriptEvaluationContext; import com.rcpcompany.uibindings.scripting.IScriptExpression; import com.rcpcompany.uibindings.scripting.IScriptManager; import com.rcpcompany.uibindings.scripting.ScriptEngineException; import com.rcpcompany.uibindings.utils.IManagerRunnable; import com.rcpcompany.utils.basic.TSEMFUtils; import com.rcpcompany.utils.logging.LogUtils; /** * <!-- begin-user-doc --> An implementation of the model object '<em><b>Script Manager</b></em>'. * <!-- end-user-doc --> * <p> * The following features are implemented: * <ul> * <li>{@link com.rcpcompany.uibindings.internal.scripting.ScriptManagerImpl#getEngines <em>Engines * </em>}</li> * <li> * {@link com.rcpcompany.uibindings.internal.scripting.ScriptManagerImpl#getGlobalEvaluationContext * <em>Global Evaluation Context</em>}</li> * <li> * {@link com.rcpcompany.uibindings.internal.scripting.ScriptManagerImpl#getRegisteredEvaluationContexts * <em>Registered Evaluation Contexts</em>}</li> * <li>{@link com.rcpcompany.uibindings.internal.scripting.ScriptManagerImpl#getDependencies <em> * Dependencies</em>}</li> * </ul> * </p> * * @generated */ public class ScriptManagerImpl extends EObjectImpl implements IScriptManager { /** * The singleton manager. */ private static IScriptManager MANAGER = null; /** * Returns the singleton manager. * * @return the manager */ public static IScriptManager getManager() { if (MANAGER == null) { MANAGER = IScriptEngineFactory.eINSTANCE.createScriptManager(); } return MANAGER; } @Override public IScriptExpression addScript(String language, String script, Class<?> expectedClass, IScriptEvaluationContext evaluationContext, Map<String, Object> localVariables) throws ScriptEngineException { final IScriptEngineDescriptor engine = getEngines().get(language); if (engine == null) throw new ScriptEngineException("Not engine for language '" + language + "'"); /* * Find the¨evaluation context */ evaluationContext = getEvaluationContext(evaluationContext, localVariables); /* * Create an expression */ final IScriptExpression expression = IScriptEngineFactory.eINSTANCE.createScriptExpression(); expression.setEngine(engine); expression.setEvaluationContext(evaluationContext); expression.setScript(script); expression.setExpectedValueClass(expectedClass); expression.evaluate(); return expression; } @Override public IScriptEvaluationContext getEvaluationContext(IScriptEvaluationContext evaluationContext, Map<String, Object> localVariables) { if (evaluationContext == null) { evaluationContext = getGlobalEvaluationContext(); } if (localVariables != null) { /* * Look up an existing context with the same variables. */ for (final IScriptEvaluationContext cc : evaluationContext.getChildren()) { if (localVariables.equals(cc.getVariables().map())) return cc; } /* * Create new context */ final IScriptEvaluationContext ec = IScriptEngineFactory.eINSTANCE.createScriptEvaluationContext(); ec.setParent(evaluationContext); ec.getVariables().putAll(localVariables); evaluationContext = ec; } return evaluationContext; } /** * The cached value of the '{@link #getEngines() <em>Engines</em>}' map. <!-- begin-user-doc --> * <!-- end-user-doc --> * * @see #getEngines() * @generated * @ordered */ protected EMap<String, IScriptEngineDescriptor> engines; /** * The cached value of the '{@link #getGlobalEvaluationContext() * <em>Global Evaluation Context</em>}' reference. <!-- begin-user-doc --> <!-- end-user-doc --> * * @see #getGlobalEvaluationContext() * @generated * @ordered */ protected IScriptEvaluationContext globalEvaluationContext; /** * The cached value of the '{@link #getRegisteredEvaluationContexts() * <em>Registered Evaluation Contexts</em>}' map. <!-- begin-user-doc --> <!-- end-user-doc --> * * @see #getRegisteredEvaluationContexts() * @generated * @ordered */ protected EMap<EObject, IScriptEvaluationContext> registeredEvaluationContexts; /** * The cached value of the '{@link #getDependencies() <em>Dependencies</em>}' map. <!-- * begin-user-doc --> <!-- end-user-doc --> * * @see #getDependencies() * @generated * @ordered */ protected EMap<EObject, EList<IScriptDependency>> dependencies; /** * <!-- begin-user-doc --> <!-- end-user-doc --> * * @generated NOT */ protected ScriptManagerImpl() { super(); extensionReader(); getRegisteredEvaluationContexts().put(null, getGlobalEvaluationContext()); } /** * Reads all relevant extensions. */ private void extensionReader() { final IExtensionRegistry registry = Platform.getExtensionRegistry(); for (final IConfigurationElement ce : registry .getConfigurationElementsFor(InternalConstants.SCRIPT_ENGINES_EXTENSION_POINT)) { final String elementName = ce.getName(); if (elementName.equals(InternalConstants.ENGINE_TAG)) { final String language = ce.getAttribute(InternalConstants.LANGUAGE_TAG); if (language == null || language.length() == 0) { LogUtils.error(ce, InternalConstants.LANGUAGE_TAG + " must be specified. Ignored"); //$NON-NLS-1$ continue; } if (getEngines().get(language) != null) { LogUtils.error(ce, "Duplicate declaration of language '" + language + "'. Ignored."); continue; } final IScriptEngineDescriptor engine = IScriptEngineFactory.eINSTANCE.createScriptEngineDescriptor(); engine.init(language, ce); getEngines().put(language, engine); } else { LogUtils.error(ce, "Unknown tag: '" + ce.getName() + "'"); } } } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * * @generated */ @Override protected EClass eStaticClass() { return IScriptEnginePackage.Literals.SCRIPT_MANAGER; } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * * @generated */ @Override public EMap<String, IScriptEngineDescriptor> getEngines() { if (engines == null) { engines = new EcoreEMap<String, IScriptEngineDescriptor>( IScriptEnginePackage.Literals.STRING_TO_SCRIPT_ENGINE_MAP_ENTRY, StringToScriptEngineMapEntryImpl.class, this, IScriptEnginePackage.SCRIPT_MANAGER__ENGINES); } return engines; } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * * @generated NOT */ @Override public IScriptEvaluationContext getGlobalEvaluationContext() { if (globalEvaluationContext == null) { globalEvaluationContext = IScriptEngineFactory.eINSTANCE.createScriptEvaluationContext(); } return globalEvaluationContext; } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * * @generated */ @Override public EMap<EObject, IScriptEvaluationContext> getRegisteredEvaluationContexts() { if (registeredEvaluationContexts == null) { registeredEvaluationContexts = new EcoreEMap<EObject, IScriptEvaluationContext>( IScriptEnginePackage.Literals.EOBJECT_TO_SCRIPT_ENGINE_MAP_ENTRY, EObjectToScriptEngineMapEntryImpl.class, this, IScriptEnginePackage.SCRIPT_MANAGER__REGISTERED_EVALUATION_CONTEXTS); } return registeredEvaluationContexts; } @Override public IScriptEvaluationContext getRegisteredEvaluationContext(EObject obj) { while (obj != null) { final IScriptEvaluationContext context = getRegisteredEvaluationContexts().get(obj); if (context != null) return context; obj = obj.eContainer(); } return getGlobalEvaluationContext(); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * * @generated */ @Override public EMap<EObject, EList<IScriptDependency>> getDependencies() { if (dependencies == null) { dependencies = new EcoreEMap<EObject, EList<IScriptDependency>>( IScriptEnginePackage.Literals.EOBJECT_TO_SCRIPT_DEPENDENCY_LIST_MAP_ENTRY, EObjectToScriptDependencyListMapEntryImpl.class, this, IScriptEnginePackage.SCRIPT_MANAGER__DEPENDENCIES); } return dependencies; } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * * @generated */ @Override public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) { switch (featureID) { case IScriptEnginePackage.SCRIPT_MANAGER__ENGINES: return ((InternalEList<?>) getEngines()).basicRemove(otherEnd, msgs); case IScriptEnginePackage.SCRIPT_MANAGER__REGISTERED_EVALUATION_CONTEXTS: return ((InternalEList<?>) getRegisteredEvaluationContexts()).basicRemove(otherEnd, msgs); case IScriptEnginePackage.SCRIPT_MANAGER__DEPENDENCIES: return ((InternalEList<?>) getDependencies()).basicRemove(otherEnd, msgs); } return super.eInverseRemove(otherEnd, featureID, msgs); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * * @generated */ @Override public Object eGet(int featureID, boolean resolve, boolean coreType) { switch (featureID) { case IScriptEnginePackage.SCRIPT_MANAGER__ENGINES: if (coreType) return getEngines(); else return getEngines().map(); case IScriptEnginePackage.SCRIPT_MANAGER__GLOBAL_EVALUATION_CONTEXT: return getGlobalEvaluationContext(); case IScriptEnginePackage.SCRIPT_MANAGER__REGISTERED_EVALUATION_CONTEXTS: if (coreType) return getRegisteredEvaluationContexts(); else return getRegisteredEvaluationContexts().map(); case IScriptEnginePackage.SCRIPT_MANAGER__DEPENDENCIES: if (coreType) return getDependencies(); else return getDependencies().map(); } return super.eGet(featureID, resolve, coreType); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * * @generated */ @SuppressWarnings("unchecked") @Override public void eSet(int featureID, Object newValue) { switch (featureID) { case IScriptEnginePackage.SCRIPT_MANAGER__ENGINES: ((EStructuralFeature.Setting) getEngines()).set(newValue); return; case IScriptEnginePackage.SCRIPT_MANAGER__REGISTERED_EVALUATION_CONTEXTS: ((EStructuralFeature.Setting) getRegisteredEvaluationContexts()).set(newValue); return; case IScriptEnginePackage.SCRIPT_MANAGER__DEPENDENCIES: ((EStructuralFeature.Setting) getDependencies()).set(newValue); return; } super.eSet(featureID, newValue); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * * @generated */ @Override public void eUnset(int featureID) { switch (featureID) { case IScriptEnginePackage.SCRIPT_MANAGER__ENGINES: getEngines().clear(); return; case IScriptEnginePackage.SCRIPT_MANAGER__REGISTERED_EVALUATION_CONTEXTS: getRegisteredEvaluationContexts().clear(); return; case IScriptEnginePackage.SCRIPT_MANAGER__DEPENDENCIES: getDependencies().clear(); return; } super.eUnset(featureID); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * * @generated */ @Override public boolean eIsSet(int featureID) { switch (featureID) { case IScriptEnginePackage.SCRIPT_MANAGER__ENGINES: return engines != null && !engines.isEmpty(); case IScriptEnginePackage.SCRIPT_MANAGER__GLOBAL_EVALUATION_CONTEXT: return globalEvaluationContext != null; case IScriptEnginePackage.SCRIPT_MANAGER__REGISTERED_EVALUATION_CONTEXTS: return registeredEvaluationContexts != null && !registeredEvaluationContexts.isEmpty(); case IScriptEnginePackage.SCRIPT_MANAGER__DEPENDENCIES: return dependencies != null && !dependencies.isEmpty(); } return super.eIsSet(featureID); } private IObservableList myLanguageList = null; @Override public IObservableList getLanguageList() { if (myLanguageList == null) { myLanguageList = WritableList.withElementType(EcorePackage.Literals.ESTRING); myLanguageList.addAll(getEngines().keySet()); // TODO monitor changes.. } return myLanguageList; } private final Adapter myDependencyAdapter = new AdapterImpl() { @Override public void notifyChanged(Notification msg) { if (msg.isTouch()) return; checkChangedDependencies(msg); }; }; @Override public IScriptDependency addDependency(IScriptDependency dependency) { /* * Find the list of dependencies for the object of the specified dependency */ final EObject object = dependency.getObject(); EList<IScriptDependency> dList = getDependencies().get(object); if (dList == null) { final BasicEMap.Entry<EObject, EList<IScriptDependency>> entry = (Entry<EObject, EList<IScriptDependency>>) IScriptEngineFactory.eINSTANCE .create(IScriptEnginePackage.Literals.EOBJECT_TO_SCRIPT_DEPENDENCY_LIST_MAP_ENTRY); entry.setKey(object); getDependencies().add(entry); dList = entry.getValue(); object.eAdapters().add(myDependencyAdapter); } /* * See if we have an identical entry of the list */ for (final IScriptDependency d : dList) { if (d.equals(dependency)) return d; } dList.add(dependency); return dependency; } /** * Checks if any current {@link IScriptDependency} match the specified notification. * <p> * If one does match, all associated expressions are re-evaluated. * * @param msg the notification to check */ protected void checkChangedDependencies(Notification msg) { final EList<IScriptDependency> dList = getDependencies().get(msg.getNotifier()); /* * Should probably never happen! */ if (dList == null) return; for (final IScriptDependency d : dList) { if (d.getFeature() != msg.getFeature()) { continue; } if (d.getIndex() != -1) { if (d.getIndex() != msg.getPosition()) { continue; } } if (d.getKey() != null) { // TODO LogUtils.debug(this, "key=" + d.getKey() + "\nmsg=" + TSEMFUtils.toString(msg)); } /* * We have a match... */ for (final IScriptExpression e : d.getExpressions()) { IManagerRunnable.Factory.asyncExec("evaluate", e, new Runnable() { @Override public void run() { e.evaluate(); } }); } } } @Override public void pruneDependencies() { final Iterator<java.util.Map.Entry<EObject, EList<IScriptDependency>>> eIterator = getDependencies().entrySet() .iterator(); while (eIterator.hasNext()) { final java.util.Map.Entry<EObject, EList<IScriptDependency>> e = eIterator.next(); final EList<IScriptDependency> dList = e.getValue(); final Iterator<IScriptDependency> dIterator = dList.iterator(); while (dIterator.hasNext()) { final IScriptDependency d = dIterator.next(); if (!d.eIsSet(IScriptEnginePackage.Literals.SCRIPT_DEPENDENCY__EXPRESSIONS)) { dIterator.remove(); } } if (dList.isEmpty()) { e.getKey().eAdapters().remove(myDependencyAdapter); eIterator.remove(); } } } } // ScriptManagerImpl