/* Copyright (c) 2008 Arno Haase, Andr� Arnold. 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: Arno Haase - initial API and implementation Andr� Arnold */ package org.eclipse.xtend.middleend.xpand; import java.io.StringReader; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.emf.mwe.core.WorkflowContext; import org.eclipse.emf.mwe.core.issues.Issues; import org.eclipse.emf.mwe.core.monitor.ProgressMonitor; import org.eclipse.internal.xpand2.XpandTokens; import org.eclipse.internal.xpand2.ast.Definition; import org.eclipse.internal.xpand2.ast.ExpandStatement; import org.eclipse.internal.xpand2.ast.Template; import org.eclipse.internal.xpand2.parser.XpandParseFacade; import org.eclipse.internal.xtend.xtend.parser.ParseException; import org.eclipse.xpand2.XpandExecutionContextImpl; import org.eclipse.xpand2.XpandUtil; import org.eclipse.xpand2.output.Outlet; import org.eclipse.xpand2.output.Output; import org.eclipse.xpand2.output.OutputImpl; import org.eclipse.xpand2.output.PostProcessor; import org.eclipse.xtend.expression.AbstractExpressionsUsingWorkflowComponent; import org.eclipse.xtend.expression.Variable; import org.eclipse.xtend.middleend.LanguageContributor; import org.eclipse.xtend.middleend.xpand.internal.xpandlib.pr.XpandProtectedRegionResolver; import org.eclipse.xtend.middleend.xpand.plugin.OldXpandRegistryFactory; import org.eclipse.xtend.middleend.xtend.plugin.OldXtendRegistryFactory; /** * This workflow component executes an Xpand template based on the new backend implementation. It * combines the steps of parsing and transforming the source files, and of invoking the script. * * @author Arno Haase (http://www.haase-consulting.com) * @author Andr� Arnold */ public class XpandComponent extends AbstractExpressionsUsingWorkflowComponent { //TODO profiler private String _genPath = null; private String _srcPath = null; private String _expand = null; private String _fileEncoding = null; private boolean _automaticHyphens = false; private Output _output = null; private final List<Outlet> _outlets = new ArrayList<Outlet>(); private List<PostProcessor> _postprocessors = new ArrayList <PostProcessor>(); private List<Outlet> _initializedOutlets = new ArrayList<Outlet> (); private String _ignoreList; private boolean _defaultExcludes; private boolean _useBase64; private boolean _logStackTrace; public XpandComponent () { if (LanguageContributor.INSTANCE.getLanguageContributionByName (OldXtendRegistryFactory.LANGUAGE_NAME) == null) { LanguageContributor.INSTANCE.addLanguageContribution (OldXtendRegistryFactory.class); } if (LanguageContributor.INSTANCE.getLanguageContributionByName (OldXpandRegistryFactory.LANGUAGE_NAME) == null) { LanguageContributor.INSTANCE.addLanguageContribution (OldXpandRegistryFactory.class); } } public List<PostProcessor> getBeautifier() { return _postprocessors; } public void addBeautifier (PostProcessor beautifier) { _postprocessors.add (beautifier); } public List<PostProcessor> getPostprocessors() { return _postprocessors; } public void addPostprocessor (PostProcessor postprocessor) { _postprocessors.add (postprocessor); } public void setAutomaticHyphens(boolean automaticHyphens) { this._automaticHyphens = automaticHyphens; } @Override public String getLogMessage() { return "generating '" + _expand + "' => directory '" + _genPath + "'"; } public void setFileEncoding(final String fileEncoding) { _fileEncoding = fileEncoding; } public String getFileEncoding() { return _fileEncoding; } public void setExpand (String invoke) { _expand = invoke; } /** * @deprecated use outlets instead */ @Deprecated public void setGenPath(final String genPath) { _genPath = fixPath(genPath); } /** * * @deprecated use outlets instead */ @Deprecated public void setSrcPath(final String srcPath) { _srcPath = fixPath(srcPath); } public void setIgnoreList(String ignoreList) { _ignoreList = ignoreList; } public void setDefaultExcludes(boolean defaultExcludes) { _defaultExcludes = defaultExcludes; } public void setUseBase64(boolean useBase64) { _useBase64 = useBase64; } public void setLogStackTrace (boolean logStackTrace) { _logStackTrace = logStackTrace; } private String fixPath(final String p) { if (p.endsWith("\\")) return p.replace('\\', '/'); if (p.endsWith("/")) return p; return p + "/"; } @Override protected void invokeInternal2 (WorkflowContext wfContext, ProgressMonitor monitor, Issues issues) { // set up the execution context XpandExecutionContextImpl executionContext = new XpandExecutionContextImpl (getOutput(), null, getGlobalVars (wfContext), null, getNullEvaluationHandler()); if (_fileEncoding != null) executionContext.getResourceManager().setFileEncoding (_fileEncoding); final String code = XpandTokens.LT + "EXPAND " + _expand + XpandTokens.RT; final String filename = new String( _expand.substring(0, _expand.lastIndexOf(XpandUtil.NS_DELIM))); XpandBackendFacade bf = XpandBackendFacade.createForFile(filename, _fileEncoding, metaModels, _outlets ); final Map<String, Object> variables = new HashMap<String, Object> (); for (String name: wfContext.getSlotNames()) variables.put (name, wfContext.get (name)); XpandProtectedRegionResolver resolver = new XpandProtectedRegionResolver(_ignoreList, _defaultExcludes, getInitializedOutlets(), _fileEncoding, _useBase64); //XpandBackendFacade.executeStatement (code, _fileEncoding, metaModels, variables, _outlets, _advice); bf.executeStatement (code, variables, getGlobalVarsFromContext(getGlobalVars(wfContext)), _advice, resolver, _logStackTrace); } public void addOutlet (Outlet outlet) { _outlets.add(outlet); } public void setOutput (Output output) { _output = output; } private Output getOutput () { if (_output == null) { // lazy initialization OutputImpl out = new OutputImpl(); out.setAutomaticHyphens (_automaticHyphens); _output = out; } return _output; } private List<Outlet> getInitializedOutlets() { if (_initializedOutlets.isEmpty()) { final List<Outlet> result = new ArrayList<Outlet> (_outlets); if (result.isEmpty()) { if (_genPath != null) { // backward compatibility result.add (new Outlet (false, _fileEncoding, null, true, _genPath)); result.add (new Outlet (true, _fileEncoding, "APPEND", true, _genPath)); } if (_srcPath != null) result.add (new Outlet (false, _fileEncoding, "ONCE", false, _srcPath)); } for (Outlet o: result) { if (o.postprocessors.isEmpty()) for (PostProcessor pp: _postprocessors) o.addPostprocessor (pp); if (_fileEncoding != null) o.setFileEncoding(_fileEncoding); } _initializedOutlets = result; } return _initializedOutlets; } private ExpandStatement getStatement () { Template tpl = XpandParseFacade.file (new StringReader(XpandTokens.LT + "DEFINE test FOR test" + XpandTokens.RT + XpandTokens.LT + "EXPAND " + _expand + XpandTokens.RT + XpandTokens.LT + "ENDDEFINE" + XpandTokens.RT), null); ExpandStatement es = null; try { es = (ExpandStatement) ((Definition) tpl.getDefinitions()[0]).getBody()[1]; } catch (final Exception e) { log.error(e); } return es; } @Override public void checkConfigurationInternal (final Issues issues) { super.checkConfigurationInternal(issues); if (_genPath == null && getInitializedOutlets().isEmpty()) issues.addError(this, "You need to configure at least one outlet!"); if ((_genPath != null || _srcPath != null) && !_outlets.isEmpty()) issues.addWarning(this, "'genPath' is ignored since you have specified outlets!"); int defaultOutlets = 0; for (final Iterator<Outlet> iter = getInitializedOutlets().iterator(); iter.hasNext();) { final Outlet o = iter.next(); if (o.getName() == null) defaultOutlets++; } if (defaultOutlets > 1) issues.addError(this, "Only one outlet can be the default outlet. Please specifiy a name for the other outlets!"); else if (defaultOutlets == 0) issues.addWarning(this, "No default outlet configured!"); if (_expand == null) issues.addError(this, "property 'expand' not configured!"); else { try { final ExpandStatement es = getStatement(); if (es == null) { issues.addError(this, "property 'expand' has wrong syntax!"); } } catch (ParseException e) { issues.addError(this, "property 'expand' has wrong syntax : "+e.getMessage()); } } } public Map<String, Object> getGlobalVarsFromContext (Map<String, Variable> globalVars) { Map <String, Object> vars = new HashMap <String, Object> (); if (globalVars != null) { for (String varName : globalVars.keySet()) { vars.put(varName, globalVars.get(varName).getValue()); } } return vars; } }