| /******************************************************************************* |
| * Copyright (c) 2005-2014 Obeo |
| * |
| * 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: |
| * Obeo - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.sirius.query.legacy.gen.template.scripts; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.Stack; |
| import java.util.TreeSet; |
| |
| import org.eclipse.sirius.query.legacy.ecore.factories.FactoryException; |
| import org.eclipse.sirius.query.legacy.gen.template.TemplateConstants; |
| import org.eclipse.sirius.query.legacy.gen.template.eval.ENode; |
| import org.eclipse.sirius.query.legacy.gen.template.eval.ENodeCastException; |
| import org.eclipse.sirius.query.legacy.gen.template.eval.ENodeException; |
| import org.eclipse.sirius.query.legacy.gen.template.eval.ENodeIterator; |
| import org.eclipse.sirius.query.legacy.gen.template.eval.ENodeList; |
| import org.eclipse.sirius.query.legacy.gen.template.eval.LaunchManager; |
| import org.eclipse.sirius.query.legacy.gen.template.expressions.TemplateCallExpression; |
| import org.eclipse.sirius.query.legacy.gen.template.scripts.imports.EvalJavaService; |
| import org.eclipse.sirius.query.legacy.gen.template.scripts.imports.EvalModel; |
| import org.eclipse.sirius.query.legacy.gen.template.scripts.imports.services.SystemServicesFactory; |
| |
| /** |
| * Abstract generator configuration. |
| * |
| * |
| */ |
| public abstract class AbstractScript implements IScript { |
| |
| /** |
| * The identifier of the internal extension point specifying the |
| * implementation to use with an acceleo script loader. |
| */ |
| public static final String SCRIPT_LOADER_EXTENSION_ID = "org.eclipse.sirius.query.legacy.gen.scriptloader"; //$NON-NLS-1$ |
| |
| /* (non-Javadoc) */ |
| public ENode eGet(TemplateCallExpression call, ENode node, ENode[] args, LaunchManager mode, boolean recursiveSearch) throws FactoryException, ENodeException { |
| // Services to apply on an ENode or an ENodeList |
| Iterator imports = this.imports.iterator(); |
| while (imports.hasNext()) { |
| final IEvalSettings anImport = (IEvalSettings) imports.next(); |
| if (anImport instanceof EvalJavaService) { |
| if ((recursiveSearch || !((EvalJavaService) anImport).hasScriptContext()) && anImport.validateCall(call)) { |
| ((EvalJavaService) anImport).setMode(EvalJavaService.MODE_ENODE); |
| ENode sub = anImport.eGet(call, node, args, mode, false); |
| if (sub != null) { |
| return sub; |
| } |
| ((EvalJavaService) anImport).setMode(EvalJavaService.MODE_LIST); |
| sub = anImport.eGet(call, node, args, mode, false); |
| if (sub != null) { |
| return sub; |
| } |
| } |
| } |
| } |
| // Templates to apply on an EObject or an ENodeList |
| ENode eval; |
| if (validateCall(call)) { |
| if (node.isEObject()) { |
| eval = eGetTemplate(node, call.getLink(), args, mode); |
| } else if (node.isList()) { |
| // Iterate on the list |
| boolean found = false; |
| final ENodeList res = new ENodeList(); |
| try { |
| if (node.getList().size() == 0 && recursiveSearch /* |
| * ENode |
| * services |
| * OK |
| */) { |
| found = true; |
| } |
| final ENodeIterator it = node.getList().iterator(); |
| while (it.hasNext()) { |
| final ENode child = eGet(call, it.next(), args, mode, recursiveSearch); |
| if (child != null) { |
| found = true; |
| res.add(child); |
| } |
| } |
| } catch (final ENodeCastException e) { |
| // Never catch |
| } |
| if (found) { |
| eval = new ENode(res, node); |
| } else { |
| eval = null; |
| } |
| } else { |
| eval = null; |
| } |
| } else { |
| eval = null; |
| } |
| if (eval == null) { |
| if (recursiveSearch) { |
| // Other imports |
| imports = this.imports.iterator(); |
| while (imports.hasNext()) { |
| final IEvalSettings anImport = (IEvalSettings) imports.next(); |
| if (anImport.validateCall(call)) { |
| if (anImport instanceof SpecificScript) { |
| final ENode sub = ((SpecificScript) anImport).eGetTemplate(node, call.getLink(), args, mode); |
| if (sub != null) { |
| return sub; |
| } |
| } else if (anImport instanceof EvalJavaService) { |
| ((EvalJavaService) anImport).setMode(EvalJavaService.MODE_DEFAULT); |
| final ENode sub = anImport.eGet(call, node, args, mode, false); |
| if (sub != null) { |
| return sub; |
| } |
| } else if (anImport instanceof EvalModel |
| && (TemplateConstants.LINK_PREFIX_METAMODEL.equals(call.getPrefix()) || TemplateConstants.LINK_PREFIX_METAMODEL_SHORT.equals(call.getPrefix()))) { |
| if (node.isEObject()) { |
| final ENode sub = anImport.eGet(call, node, args, mode, false); |
| if (sub != null) { |
| return sub; |
| } |
| } else if (node.isList()) { |
| // Iterate on the list |
| boolean found = false; |
| final ENodeList res = new ENodeList(); |
| try { |
| if (node.getList().size() == 0 && recursiveSearch) { |
| found = true; |
| } |
| final ENodeIterator it = node.getList().iterator(); |
| while (it.hasNext()) { |
| final ENode next = it.next(); |
| final ENode child = anImport.eGet(call, next, args, mode, false); |
| if (child != null) { |
| found = true; |
| res.add(child); |
| } |
| } |
| } catch (final ENodeCastException e) { |
| // Never catch |
| } |
| if (found) { |
| return new ENode(res, node); |
| } |
| } else { |
| final ENode sub = anImport.eGet(call, node, args, mode, false); |
| if (sub != null) { |
| return sub; |
| } |
| } |
| } else { |
| final ENode sub = anImport.eGet(call, node, args, mode, false); |
| if (sub != null) { |
| return sub; |
| } |
| } |
| } |
| } |
| } else { |
| // Other imports |
| imports = this.imports.iterator(); |
| while (imports.hasNext()) { |
| final IEvalSettings anImport = (IEvalSettings) imports.next(); |
| if (anImport instanceof AbstractScript && !(anImport instanceof SpecificScript) && !(anImport instanceof EmptyScript) && anImport.validateCall(call)) { |
| final ENode sub = anImport.eGet(call, node, args, mode, false); |
| if (sub != null) { |
| return sub; |
| } |
| } else if (anImport instanceof EvalJavaService && !((EvalJavaService) anImport).hasScriptContext() && anImport.validateCall(call)) { |
| ((EvalJavaService) anImport).setMode(EvalJavaService.MODE_DEFAULT); |
| final ENode sub = anImport.eGet(call, node, args, mode, false); |
| if (sub != null) { |
| return sub; |
| } |
| } |
| } |
| } |
| } |
| if (eval == null && node.isNull()) { |
| return node; |
| } else { |
| return eval; |
| } |
| } |
| |
| /** |
| * Computes a child node of generation for a node and a template name. The |
| * template is evaluated on an EObject, so the given node must be an |
| * EObject. |
| * |
| * @param node |
| * is the parent node of generation |
| * @param name |
| * is the template name |
| * @param args |
| * is the list of arguments |
| * @param mode |
| * is the mode in which to launch, one of the mode constants |
| * defined - RUN_MODE or DEBUG_MODE |
| * @return the child node of generation, or null if the template doesn't |
| * exist, or null if the type of the node isn't valid |
| * @throws ENodeException |
| * @throws FactoryException |
| */ |
| public abstract ENode eGetTemplate(ENode node, String name, ENode[] args, LaunchManager mode) throws ENodeException, FactoryException; |
| |
| /* (non-Javadoc) */ |
| public void addImport(IEvalSettings element) { |
| if (element != null) { |
| this.imports.add(element); |
| } |
| } |
| |
| /* (non-Javadoc) */ |
| public void removeImport(IEvalSettings element) { |
| if (element != null) { |
| this.imports.remove(element); |
| } |
| } |
| |
| /* (non-Javadoc) */ |
| public void clearImports() { |
| imports.clear(); |
| } |
| |
| /** |
| * All the elements that are used after this one during generation. |
| */ |
| protected Set imports = new TreeSet(new Comparator() { |
| public int compare(Object arg0, Object arg1) { |
| // Remark : Low priority for EvalModel |
| if (!(arg0 instanceof EvalModel) && arg1 instanceof EvalModel) { |
| return -1; |
| } else { |
| return 1; |
| } |
| } |
| }); |
| |
| /** |
| * @return the imports |
| */ |
| public Set getImports() { |
| return imports; |
| } |
| |
| /** |
| * Returns the factory that produces the system services for this script. |
| * |
| * @return the factory that produces the system services for this script |
| */ |
| protected SystemServicesFactory getSystemServicesFactory() { |
| if (systemServicesFactory == null) { |
| systemServicesFactory = createSystemServicesFactory(); |
| } |
| return systemServicesFactory; |
| } |
| |
| private SystemServicesFactory systemServicesFactory = null; |
| |
| /** |
| * Creates the factory that produces the system services for this script. |
| * |
| * @return the new factory |
| */ |
| protected SystemServicesFactory createSystemServicesFactory() { |
| return new SystemServicesFactory(); |
| } |
| |
| /* (non-Javadoc) */ |
| public IScript[] goToSpecifics() { |
| if (goToSpecifics == null) { |
| if (AbstractScript.getScriptLoader() != null) { |
| goToSpecifics = AbstractScript.getScriptLoader().goToSpecifics(this); |
| } |
| } |
| return goToSpecifics; |
| } |
| |
| private IScript[] goToSpecifics = null; |
| |
| /* (non-Javadoc) */ |
| public IScript getSpecific() { |
| return specific; |
| } |
| |
| /* (non-Javadoc) */ |
| public void setSpecific(IScript specific) { |
| this.specific = specific; |
| this.goToSpecifics = null; |
| } |
| |
| /** |
| * The more specific script. The specific script is used before this one to |
| * resolve the links. |
| */ |
| protected IScript specific = null; |
| |
| /* (non-Javadoc) */ |
| public File getFile() { |
| return null; |
| } |
| |
| /* (non-Javadoc) */ |
| public Object contextPeek(Object key) { |
| final Stack stack = (Stack) context.get(key); |
| if (stack != null && !stack.isEmpty()) { |
| final Object result = stack.peek(); |
| if (result instanceof ENode) { |
| return ((ENode) result).copy(); |
| } else if (result instanceof ENode[]) { |
| final ENode[] copy = new ENode[((ENode[]) result).length]; |
| for (int i = 0; i < copy.length; i++) { |
| copy[i] = ((ENode[]) result)[i].copy(); |
| } |
| return copy; |
| } else { |
| return result; |
| } |
| } else { |
| return null; |
| } |
| } |
| |
| /* (non-Javadoc) */ |
| public Object contextAt(Object key, int index) { |
| final Stack stack = (Stack) context.get(key); |
| if (stack != null) { |
| if (index >= 0 && index < stack.size()) { |
| final Object result = stack.elementAt(stack.size() - index - 1); |
| if (result instanceof ENode) { |
| return ((ENode) result).copy(); |
| } else if (result instanceof ENode[]) { |
| final ENode[] copy = new ENode[((ENode[]) result).length]; |
| for (int i = 0; i < copy.length; i++) { |
| copy[i] = ((ENode[]) result)[i].copy(); |
| } |
| return copy; |
| } else { |
| return result; |
| } |
| } else { |
| return null; |
| } |
| } else { |
| return null; |
| } |
| } |
| |
| /* (non-Javadoc) */ |
| public void contextPush(Object key, Object value) { |
| Stack stack = (Stack) context.get(key); |
| if (stack == null) { |
| stack = new Stack(); |
| context.put(key, stack); |
| } |
| stack.push(value); |
| } |
| |
| /* (non-Javadoc) */ |
| public void contextPop(Object key) { |
| final Stack stack = (Stack) context.get(key); |
| if (stack != null) { |
| stack.pop(); |
| } |
| } |
| |
| /** |
| * Context that is used during generation. |
| */ |
| private final Map context = new HashMap(); |
| |
| /** |
| * Resolves the type of the next step for the type of the previous node, and |
| * the new link. |
| * |
| * @param type |
| * is the type of the previous node |
| * @param call |
| * is the new link |
| * @return the type of the next step |
| */ |
| public Object resolveType(Object type, TemplateCallExpression call) { |
| return resolveType(type, call, 0); |
| } |
| |
| /* (non-Javadoc) */ |
| public Object resolveType(Object type, TemplateCallExpression call, int depth) { |
| if (depth < 1) { |
| final Iterator imports = this.imports.iterator(); |
| while (imports.hasNext()) { |
| final IEvalSettings anImport = (IEvalSettings) imports.next(); |
| if (anImport.validateCall(call)) { |
| final Object resolvedType = anImport.resolveType(type, call, 1); |
| if (resolvedType != null) { |
| return resolvedType; |
| } |
| } |
| } |
| } |
| if (call.getLink().equals(TemplateConstants.LINK_NAME_INDEX) && call.getFirstArgument() == null && "".equals(call.getPrefix())) { |
| return IEvalSettings.GENERIC_TYPE; |
| } else if (call.getLink().equals(TemplateConstants.LINK_NAME_ARGS) && call.getArguments() != null && call.getArguments().size() == 1 && "".equals(call.getPrefix())) { |
| return IEvalSettings.GENERIC_TYPE; |
| } |
| return null; |
| } |
| |
| /** |
| * Gets the proposals of the next step for the type of the previous node. |
| * |
| * @param type |
| * is the type of the previous node |
| * @return the proposals of the next step |
| */ |
| public Object[] getCompletionProposals(Object type) { |
| return getCompletionProposals(type, 0); |
| } |
| |
| /* (non-Javadoc) */ |
| public Object[] getCompletionProposals(Object type, int depth) { |
| final List result = new ArrayList(); |
| if (depth < 1) { |
| final TreeSet orderedImports = new TreeSet(new Comparator() { |
| public int compare(Object arg0, Object arg1) { |
| // Remark : High priority for EvalModel |
| if (arg0 instanceof EvalModel && !(arg1 instanceof EvalModel)) { |
| return -1; |
| } else { |
| return 1; |
| } |
| } |
| }); |
| orderedImports.addAll(this.imports); |
| final Iterator imports = orderedImports.iterator(); |
| while (imports.hasNext()) { |
| final IEvalSettings anImport = (IEvalSettings) imports.next(); |
| result.addAll(Arrays.asList(anImport.getCompletionProposals(type, 1))); |
| } |
| } |
| return result.toArray(); |
| } |
| |
| /* (non-Javadoc) */ |
| @Override |
| public String toString() { |
| final StringBuffer text = new StringBuffer(""); //$NON-NLS-1$ |
| text.append(TemplateConstants.IMPORT_BEGIN); |
| text.append('\n'); |
| final Iterator imports = this.imports.iterator(); |
| while (imports.hasNext()) { |
| final IEvalSettings anImport = (IEvalSettings) imports.next(); |
| // Remark : toString -> Keep EvalModel only |
| if (anImport instanceof EvalModel) { |
| final String importValue = ((EvalModel) anImport).getUri(); |
| if (importValue.length() > 0) { |
| text.append(TemplateConstants.MODELTYPE_WORD); |
| text.append(' '); |
| text.append(importValue); |
| text.append('\n'); |
| } |
| } |
| } |
| text.append(TemplateConstants.IMPORT_END); |
| text.append("\n\n"); //$NON-NLS-1$ |
| return text.toString(); |
| } |
| |
| /** |
| * @return the script loader that converts the script's content before |
| * loading |
| */ |
| protected static IScriptLoader getScriptLoader() { |
| if (AbstractScript.scriptLoader == null) { |
| return new DefaultScriptLoader(); |
| } |
| return AbstractScript.scriptLoader; |
| } |
| |
| private static IScriptLoader scriptLoader = null; |
| |
| } |