blob: 448a41ad688e9f79ae7a244e0fe6ead184d1aaf7 [file] [log] [blame]
/*******************************************************************************
* 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.io.IOException;
import java.net.URL;
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.Properties;
import java.util.TreeMap;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.osgi.framework.Bundle;
import org.eclipse.sirius.query.legacy.ecore.factories.FactoryException;
import org.eclipse.sirius.query.legacy.ecore.tools.ETools;
import org.eclipse.sirius.query.legacy.gen.AcceleoGenMessages;
import org.eclipse.sirius.query.legacy.gen.template.Template;
import org.eclipse.sirius.query.legacy.gen.template.TemplateConstants;
import org.eclipse.sirius.query.legacy.gen.template.TemplateSyntaxException;
import org.eclipse.sirius.query.legacy.gen.template.TemplateSyntaxExceptions;
import org.eclipse.sirius.query.legacy.gen.template.TemplateText;
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.LaunchManager;
import org.eclipse.sirius.query.legacy.gen.template.expressions.TemplateCallExpression;
import org.eclipse.sirius.query.legacy.gen.template.expressions.TemplateCallSetExpression;
import org.eclipse.sirius.query.legacy.gen.template.expressions.TemplateExpression;
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.JavaServiceNotFoundException;
import org.eclipse.sirius.query.legacy.gen.template.statements.TemplateFeatureStatement;
import org.eclipse.sirius.query.legacy.tools.plugins.AcceleoMetamodelProvider;
import org.eclipse.sirius.query.legacy.tools.plugins.AcceleoModuleProvider;
import org.eclipse.sirius.query.legacy.tools.resources.Resources;
import org.eclipse.sirius.query.legacy.tools.strings.Int2;
import org.eclipse.sirius.query.legacy.tools.strings.TextSearch;
/**
* Model specific generator configuration. A script file contains this
* configuration. <li>isDefault() == false</li> <li>isSpecific() == true</li>
* <li>hasFileTemplate() == true if more than one file template is defined in
* the configuration</li> <li>isGenerated(EObject) == true if one file template
* is defined for the object</li> <li>hasError(EObject) == false</li>
*
*
*/
public class SpecificScript extends AbstractScript {
/**
* Generator file extension.
*/
public static final String GENERATORS_EXTENSION = "mt"; //$NON-NLS-1$
/**
* Should we profile the initialization of the script.
*/
private boolean initProfiling = false;
/**
* Map of text templates.
*/
protected Map textTemplates = new TreeMap(new Comparator() {
public int compare(Object arg0, Object arg1) {
if (arg0.equals(arg1)) {
return 0;
} else {
ScriptDescriptor a0 = (ScriptDescriptor) arg0;
ScriptDescriptor a1 = (ScriptDescriptor) arg1;
int result = a0.type.compareTo(a1.type);
if (result != 0) {
return result;
} else {
return a0.name.compareTo(a1.name);
}
}
}
});
/**
* The name of the templates.
*/
protected List textTemplateNames = new ArrayList();
/**
* Map of file templates.
*/
protected Map fileTemplates = new HashMap();
/**
* Script file that contains the specific configuration.
*/
protected File file;
/**
* Root element of the metamodel.
*/
protected EPackage metamodel = null;
/**
* Gets the text template that corresponds to a file template.
*/
protected Map file2TextTemplate = new HashMap();
/**
* Gets the file template that corresponds to a text template.
*/
protected Map text2FileTemplate = new HashMap();
/**
* The chain file.
*/
protected File chainFile = null;
/**
* The context of the script.
*/
protected ISpecificScriptContext scriptContext = null;
/**
* Constructor.
*/
public SpecificScript() {
super();
this.file = null;
try {
init(new ArrayList(), "", false); //$NON-NLS-1$
} catch (final TemplateSyntaxExceptions e) {
// Never catch
}
}
/**
* Constructor.
*
* @param file
* is the script file that contains the specific configuration
*/
public SpecificScript(File file) {
this(file, null);
}
/**
* Constructor.
*
* @param file
* is the script file that contains the specific configuration
* @param chainFile
* is the optional chain file
*/
public SpecificScript(File file, File chainFile) {
this();
this.file = file;
this.chainFile = chainFile;
this.scriptContext = null;
}
/**
* Constructor.
*
* @param file
* is the script file that contains the specific configuration
* @param chainFile
* is the optional chain file
* @param scriptContext
* is the context of the script
*/
public SpecificScript(File file, File chainFile, ISpecificScriptContext scriptContext) {
this();
this.file = file;
this.chainFile = chainFile;
this.scriptContext = scriptContext;
if (scriptContext != null) {
scriptContext.setScript(file, this);
}
}
/**
* @return the root element of the metamodel or null
*/
public EPackage getMetamodel() {
return metamodel;
}
/**
* @return the map of text templates
*/
public Map getTextTemplates() {
return textTemplates;
}
/* (non-Javadoc) */
@Override
public File getFile() {
return file;
}
/**
* @return the chain file
*/
public File getChainFile() {
return chainFile;
}
/**
* @param chainFile
* is the chain file
*/
public void setChainFile(File chainFile) {
this.chainFile = chainFile;
}
/* (non-Javadoc) */
public boolean isDefault() {
return false;
}
/* (non-Javadoc) */
public boolean isSpecific() {
return true;
}
/* (non-Javadoc) */
public void reset() throws TemplateSyntaxExceptions {
reset(new ArrayList());
}
private void reset(List fileHierarchy) throws TemplateSyntaxExceptions {
if (file != null) {
final String content = Resources.getFileContent(file).toString();
reset(fileHierarchy, content);
}
}
/**
* Reset the generator.
*
* @param content
* is the new content to be parsed
* @throws TemplateSyntaxExceptions
*/
public void reset(String content) throws TemplateSyntaxExceptions {
reset(new ArrayList(), content);
}
/**
* Reset the generator.
*
* @param fileHierarchy
* is the imported scripts hierarchy
* @param content
* is the new content to be parsed
* @throws TemplateSyntaxExceptions
*/
private synchronized void reset(List fileHierarchy, String content) throws TemplateSyntaxExceptions {
if (file != null) {
if (fileHierarchy.contains(file.getAbsolutePath())) {
final List problems = new ArrayList();
problems.add(new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.RecursiveDependency"), this, 0)); //$NON-NLS-1$
throw new TemplateSyntaxExceptions(problems);
} else {
fileHierarchy.add(file.getAbsolutePath());
}
}
boolean checkOnly;
if (oldContent == null || !oldContent.equals(content)) {
oldContent = content;
checkOnly = false;
textTemplates.clear();
textTemplateNames.clear();
fileTemplates.clear();
id2TextTemplate.clear();
id2FileTemplate.clear();
file2TextTemplate.clear();
text2FileTemplate.clear();
quickTemplates.clear();
} else {
checkOnly = true;
}
clearFoundProperties();
current = null;
init(fileHierarchy, content, checkOnly);
}
private String oldContent = null;
/**
* Gets the file template for the given text template.
*
* @param textTemplate
* is a text template
* @return the file template
*/
public Template getFileTemplate(Template textTemplate) {
return (Template) text2FileTemplate.get(textTemplate);
}
/**
* Gets the text template for the given file template.
*
* @param fileTemplate
* is a file template
* @return the text template
*/
public Template getTextTemplate(Template fileTemplate) {
return (Template) file2TextTemplate.get(fileTemplate);
}
/* (non-Javadoc) */
public Template getTextTemplateForEObject(EObject object, String name) throws FactoryException, ENodeException {
return getTextTemplateForEClass(object.eClass(), name);
}
private Template getTextTemplateForEClass(EClass eClass, String name) throws FactoryException, ENodeException {
Template template = getTextTemplateForEClassifier(eClass, name);
if (template == null) {
if (eClass.getESuperTypes().isEmpty() && eClass != EcorePackage.eINSTANCE.getEObject()) {
/*
* We want to add an "artificial" specialization on EObject
*/
template = getTextTemplateForEClass(EcorePackage.eINSTANCE.getEObject(), name);
}
final Iterator superTypes = eClass.getESuperTypes().iterator();
while (template == null && superTypes.hasNext()) {
final EClassifier superType = (EClassifier) superTypes.next();
if (superType instanceof EClass) {
template = getTextTemplateForEClass((EClass) superType, name);
} else {
template = getTextTemplateForEClassifier(superType, name);
}
}
}
return template;
}
private Template getTextTemplateForEClassifier(EClassifier eClass, String name) throws FactoryException, ENodeException {
final ScriptDescriptor key = new ScriptDescriptor(ETools.getEClassifierPath(eClass), name);
Template template = (Template) id2TextTemplate.get(key);
if (template == null) {
template = (Template) textTemplates.get(key);
if (template == null) {
final Iterator it = textTemplates.entrySet().iterator();
while (template == null && it.hasNext()) {
final Map.Entry entry = (Map.Entry) it.next();
if (name.equals(((ScriptDescriptor) entry.getKey()).name) && ('.' + key.type).endsWith('.' + ((ScriptDescriptor) entry.getKey()).type)) {
template = (Template) entry.getValue();
}
}
}
if (template != null) {
id2TextTemplate.put(key, template);
}
}
return template;
}
/* (non-Javadoc) */
public Template getRootTemplate(EObject object, boolean recursive) throws FactoryException, ENodeException {
Template textTemplate = null;
final Template fileTemplate = getFileTemplateForEObject(object);
if (fileTemplate != null) {
textTemplate = (Template) file2TextTemplate.get(fileTemplate);
}
if (recursive && !hasFileTemplate()) {
if (textTemplate == null) {
final Iterator imports = this.imports.iterator();
while (textTemplate == null && imports.hasNext()) {
final IEvalSettings anImport = (IEvalSettings) imports.next();
if (anImport instanceof IScript) {
try {
textTemplate = ((IScript) anImport).getRootTemplate(object, false);
} catch (final ENodeException e) {
textTemplate = null;
}
}
}
}
}
if (textTemplate != null) {
return textTemplate;
} else {
throw new ENodeException(AcceleoGenMessages.getString("ENodeError.UnresolvedRoot"), new Int2(0, 0), this, object, true); //$NON-NLS-1$
}
}
/**
* Gets the text template that corresponds to an identifiant.
*/
protected Map id2TextTemplate = new HashMap();
/**
* Creates a new empty text template.
*
* @param descriptor
* is the descriptor of the template
* @return the new text template
* @throws TemplateSyntaxException
*/
public Template createTextTemplate(ScriptDescriptor descriptor) throws TemplateSyntaxException {
return createTextTemplate(descriptor, "", new Int2(0, 0)); //$NON-NLS-1$
}
/**
* Creates a new text template.
*
* @param descriptor
* is the descriptor of the template
* @param text
* is the content of the file
* @param pos
* is the position of the template in the file
* @return the new text template
* @throws TemplateSyntaxException
* if the text has syntax errors
*/
public Template createTextTemplate(ScriptDescriptor descriptor, String text, Int2 pos) throws TemplateSyntaxException {
TemplateSyntaxException failure = null;
Template template = (Template) textTemplates.get(descriptor);
if (template == null) {
// Template has been created before?
final String quickEntry = descriptor.getType() + '\n' + descriptor.getName() + '\n' + text.substring(pos.b(), pos.e());
template = (Template) quickTemplates.get(quickEntry);
if (template == null) {
// Create template
try {
template = newTextTemplate(descriptor, text, pos);
} catch (final TemplateSyntaxException e) {
template = newTextTemplate(descriptor, null, pos);
failure = e;
}
quickTemplates.put(quickEntry, template);
}
// Update the position of this template in the script file
template.setPos(pos);
textTemplates.put(descriptor, template);
if (!textTemplateNames.contains(descriptor.getName())) {
textTemplateNames.add(descriptor.getName());
}
current = template;
} else {
failure = new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.DuplicateEntry.Text", new Object[] { descriptor.toString(), }), this, pos); //$NON-NLS-1$
}
if (failure != null) {
throw failure;
}
return template;
}
private final Map quickTemplates = new HashMap();
/**
* It checks the syntax and creates a template for the given part of the
* text. The part of the text to be parsed is delimited by the given limits.
*
* @param descriptor
* is the descriptor of the template
* @param text
* is the textual representation of the script that contains
* templates
* @param pos
* delimits the part of the text to be parsed for this template
* @return the new template
* @throws TemplateSyntaxException
*/
protected Template newTextTemplate(ScriptDescriptor descriptor, String text, Int2 pos) throws TemplateSyntaxException {
final Template template = Template.read(text, pos, this);
template.setDescriptor(descriptor);
return template;
}
/**
* Last template created.
*/
protected Template current = null;
/**
* @return last template created
*/
public Template getCurrent() {
return current;
}
/**
* @param current
* is the last template created
*/
public void setCurrent(Template current) {
this.current = current;
}
/* (non-Javadoc) */
public boolean hasFileTemplate() {
return fileTemplates.size() > 0;
}
/* (non-Javadoc) */
public boolean isGenerated(EObject object) {
try {
return getFilePath(object, true) != null;
} catch (final FactoryException e) {
return false;
}
}
/* (non-Javadoc) */
public IPath getFilePath(EObject object, boolean recursive) throws FactoryException {
if (hasFileTemplate()) {
try {
final Template fileTemplate = getFileTemplateForEObject(object);
if (fileTemplate != null) {
final String path = fileTemplate.evaluateAsString(object, LaunchManager.create("run", false)).trim(); //$NON-NLS-1$
if (path.length() > 0) {
return new Path(path);
}
}
} catch (final ENodeException e) {
}
} else if (recursive) {
final Iterator imports = this.imports.iterator();
while (imports.hasNext()) {
final IEvalSettings anImport = (IEvalSettings) imports.next();
if (anImport instanceof IScript) {
final IPath path = ((IScript) anImport).getFilePath(object, false);
if (path != null) {
return path;
}
}
}
}
return null;
}
/**
* Gets the file template for the given object of the model.
*
* @param object
* is an object of the model
* @return the file template
*/
public Template getFileTemplateForEObject(EObject object) {
Template res = getFileTemplateForEClass(object.eClass());
// try the default EObject type
if (res == null) {
res = getFileTemplateForEClass(EcorePackage.eINSTANCE.getEObject());
}
return res;
}
private Template getFileTemplateForEClass(EClass eClass) {
Template template = getFileTemplateForEClassifier(eClass);
if (template == null) {
final Iterator superTypes = eClass.getESuperTypes().iterator();
while (template == null && superTypes.hasNext()) {
final EClassifier superType = (EClassifier) superTypes.next();
if (superType instanceof EClass) {
template = getFileTemplateForEClass((EClass) superType);
} else {
template = getFileTemplateForEClassifier(superType);
}
}
}
return template;
}
private Template getFileTemplateForEClassifier(EClassifier eClass) {
final String typeID = ETools.getEClassifierPath(eClass);
Template template = (Template) id2FileTemplate.get(typeID);
if (template == null) {
template = (Template) fileTemplates.get(typeID);
if (template == null) {
final Iterator it = fileTemplates.entrySet().iterator();
while (template == null && it.hasNext()) {
final Map.Entry entry = (Map.Entry) it.next();
if (('.' + typeID).endsWith("." + entry.getKey())) { //$NON-NLS-1$
template = (Template) entry.getValue();
}
}
}
if (template != null) {
id2FileTemplate.put(typeID, template);
}
}
return template;
}
/**
* Gets the file template that corresponds to an identifiant.
*/
protected Map id2FileTemplate = new HashMap();
/**
* Creates a new file template.
*
* @param typeID
* is the identifiant
* @param text
* is the content of the template
* @param textTemplate
* is the text template that corresponds to the file template to
* be created
* @throws TemplateSyntaxException
*/
public void createFileTemplate(String typeID, String text, Template textTemplate) throws TemplateSyntaxException {
createFileTemplate(typeID, text, new Int2(0, text.length()), textTemplate);
}
/**
* Creates a new file template.
*
* @param typeID
* is the identifiant
* @param text
* is the content of the file
* @param pos
* is the position of the template in the file
* @param textTemplate
* is the text template that corresponds to the file template to
* be created
* @throws TemplateSyntaxException
*/
public void createFileTemplate(String typeID, String text, Int2 pos, Template textTemplate) throws TemplateSyntaxException {
TemplateSyntaxException failure = null;
Template template = (Template) fileTemplates.get(typeID);
if (template == null) {
try {
template = Template.read(text, pos, this);
} catch (final TemplateSyntaxException e) {
template = new Template(this);
failure = e;
}
fileTemplates.put(typeID, template);
file2TextTemplate.put(template, textTemplate);
text2FileTemplate.put(textTemplate, template);
} else {
failure = new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.DuplicateEntry.File", new Object[] { typeID, }), this, pos); //$NON-NLS-1$
}
if (failure != null) {
throw failure;
}
}
/* (non-Javadoc) */
@Override
public String toString() {
final StringBuffer buffer = new StringBuffer(super.toString());
final Iterator it = textTemplates.entrySet().iterator();
while (it.hasNext()) {
final Map.Entry entry = (Map.Entry) it.next();
final ScriptDescriptor key = (ScriptDescriptor) entry.getKey();
buffer.append(TemplateConstants.SCRIPT_BEGIN); // TemplateConstants.
// SCRIPT_BEGIN
// ends with " "
buffer.append(key.toString());
// File template?
final Template fileTemplate = (Template) fileTemplates.get(key.type);
if (fileTemplate != null) {
buffer.append(' ');
buffer.append(TemplateConstants.SCRIPT_FILE);
buffer.append(TemplateConstants.SCRIPT_PROPERTY_ASSIGN);
buffer.append(TemplateConstants.LITERAL[0]);
buffer.append(fileTemplate.toString());
buffer.append(TemplateConstants.LITERAL[1]);
}
buffer.append(TemplateConstants.SCRIPT_END);
buffer.append('\n');
final String text = ((Template) entry.getValue()).toString();
buffer.append(text);
buffer.append("\n\n"); //$NON-NLS-1$
}
return buffer.toString();
}
/**
* It checks the syntax and creates templates for the given text.
*
* @param fileHierarchy
* is the imported scripts hierarchy
* @param text
* is the text to be parsed
* @param checkOnly
* indicates if it checks the syntax only
* @throws TemplateSyntaxExceptions
*/
protected void init(List fileHierarchy, String text, boolean checkOnly) throws TemplateSyntaxExceptions {
final boolean isRoot = fileHierarchy.size() <= 1;
if (AbstractScript.getScriptLoader() != null) {
text = AbstractScript.getScriptLoader().load(text);
if (text != null) {
final List problems = new ArrayList();
TemplateConstants.initConstants(text);
oldImports = new ArrayList(imports);
clearImports();
if (text != null && text.length() > 0) {
// Get imports
if (file != null) {
try {
addImport(new EvalJavaService(file));
} catch (final JavaServiceNotFoundException e) {
}
}
parseImports(fileHierarchy, text, problems);
getSystemServicesFactory().addImports(this, isRoot);
// Parse scripts
if (!checkOnly) {
syntaxErrors.clear();
parseScripts(text, syntaxErrors);
}
problems.addAll(syntaxErrors);
}
// Check all expressions of the generator
if (file != null) {
final IFile workspaceFile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(new Path(file.getAbsolutePath()));
if (workspaceFile != null && workspaceFile.exists()) {
if (isRoot) {
checkAllExpressions(problems);
}
}
}
// check only if the compilation result is not for runtime use
if (scriptContext != null && scriptContext.getMaxLevel() != -1) {
checkOverride(problems);
}
// Throw TemplateSyntaxExceptions if problems are detected
if (problems.size() > 0) {
throw new TemplateSyntaxExceptions(problems);
}
}
}
}
/**
* Check for masked overrides.
*
* @param problems
* the problem list
*/
private void checkOverride(List problems) {
Map overrides = new HashMap();
Iterator it = getImports().iterator();
while (it.hasNext()) {
Map localOverrides = new HashMap();
IEvalSettings imp = (IEvalSettings) it.next();
if (imp instanceof SpecificScript) {
SpecificScript script = (SpecificScript) imp;
final Iterator entries = script.textTemplates.entrySet().iterator();
while (entries.hasNext()) {
final Map.Entry entry = (Map.Entry) entries.next();
final EClassifier type = ETools.getEClassifier(script.getMetamodel(), ((ScriptDescriptor) entry.getKey()).getType());
if (type instanceof EClass) {
final Template template = (Template) entry.getValue();
final String name = template.getDescriptor().getName();
List typeList = (List) overrides.get(name);
if (typeList == null) {
typeList = new ArrayList();
localOverrides.put(name, typeList);
} else {
if (isMaskedOverride((EClass) type, typeList)) {
TemplateSyntaxException problem = new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.BadOverride",
new Object[] { fileScriptToImportString(script.getFile()), }), this, 1);
problem.setSeverity(IMarker.SEVERITY_WARNING);
problems.add(problem);
}
}
typeList.add(type);
}
}
}
// merge localOverrides and overrides
Iterator localIt = localOverrides.entrySet().iterator();
while (localIt.hasNext()) {
final Map.Entry entry = (Map.Entry) localIt.next();
String name = (String) entry.getKey();
List types = (List) overrides.get(name);
if (types == null) {
overrides.put(name, entry.getValue());
} else {
types.addAll((List) entry.getValue());
}
}
}
}
private boolean isMaskedOverride(EClass type, List typeList) {
boolean res = false;
List supertypes = type.getEAllSuperTypes();
Iterator it = typeList.iterator();
while (!res && it.hasNext()) {
res = supertypes.contains(it.next());
}
return res;
}
private final List syntaxErrors = new ArrayList();
/**
* It checks the syntax and creates the scripts for the given text.
*
* @param text
* is the text to be parsed
* @param problems
* are the syntax problems detected during this parsing
*/
private void parseScripts(String text, List problems) {
TemplateConstants.initConstants(text);
ScriptDescriptor descriptor = null;
Int2 end = new Int2(0, 0);
while (end.e() > -1 && end.e() < text.length()) {
final Int2 begin = TextSearch.getDefaultSearch().indexOf(text, TemplateConstants.SCRIPT_BEGIN, end.e(), null, TemplateConstants.INHIBS_SCRIPT_CONTENT);
if (begin.b() > -1) {
// Create a new script
try {
newScript(descriptor, text, new Int2(end.e(), begin.b()));
} catch (final TemplateSyntaxException e) {
problems.add(e);
}
// Clear informations
descriptor = null;
// Prepare new script
end = TextSearch.getDefaultSearch().blockIndexEndOf(text, TemplateConstants.SCRIPT_BEGIN, TemplateConstants.SCRIPT_END, begin.b(), false, TemplateConstants.SPEC,
TemplateConstants.INHIBS_SCRIPT_DECLA);
if (end.e() == -1) {
problems.add(new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.MissingScriptEndTag"), this, begin.b())); //$NON-NLS-1$
} else {
try {
descriptor = getDescriptorFactory().createScriptDescriptor(text, this, new Int2(begin.e(), end.b()));
} catch (final TemplateSyntaxException e) {
problems.add(e);
descriptor = null;
}
}
} else { // -1
// Create a new script
try {
newScript(descriptor, text, new Int2(end.e(), text.length()));
} catch (final TemplateSyntaxException e) {
problems.add(e);
}
end = new Int2(text.length(), text.length());
}
}
}
/**
* Creates an instance of the descriptor factory. This new factory will be
* used to create template's descriptors.
*
* @return the new factory
*/
protected ScriptDescriptorFactory createDescriptorFactory() {
return new ScriptDescriptorFactory();
}
/**
* Gets the instance of the descriptor factory. This factory is used to
* create template's descriptors.
*
* @return the descriptor factory
*/
private ScriptDescriptorFactory getDescriptorFactory() {
if (descriptorFactory == null) {
descriptorFactory = createDescriptorFactory();
}
return descriptorFactory;
}
private ScriptDescriptorFactory descriptorFactory = null;
/**
* It checks the syntax and creates the imports for the given text.
*
* @param fileHierarchy
* is the imported scripts hierarchy
* @param text
* is the text to be parsed
* @param problems
* are the syntax problems detected during this parsing
*/
protected void parseImports(List fileHierarchy, String text, List problems) {
metamodel = null;
final List importValues = new ArrayList();
int end = TextSearch.getDefaultSearch().indexOf(text, TemplateConstants.SCRIPT_BEGIN, 0, null, TemplateConstants.INHIBS_SCRIPT_CONTENT).b();
if (end == -1) {
end = text.length();
}
int pos = 0;
while (pos > -1 && pos < end) {
final Int2 bComment = TextSearch.getDefaultSearch().indexIn(text, TemplateConstants.COMMENT_BEGIN, pos, end);
final Int2 bImports = TextSearch.getDefaultSearch().indexIn(text, TemplateConstants.IMPORT_BEGIN, pos, end);
if (bComment.b() > -1 && (bImports.b() == -1 || bComment.b() <= bImports.b())) {
final Int2 eComment = TextSearch.getDefaultSearch().blockIndexEndIn(text, TemplateConstants.COMMENT_BEGIN, TemplateConstants.COMMENT_END, bComment.b(), end, false);
if (eComment.b() > -1) {
pos = eComment.e();
} else {
problems.add(new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.MissingCommentEndTag"), this, bComment.b())); //$NON-NLS-1$
pos = end;
}
} else if (bImports.b() > -1) {
final Int2 eImports = TextSearch.getDefaultSearch().indexIn(text, TemplateConstants.IMPORT_END, bImports.e(), end);
if (eImports.b() > -1) {
final Int2[] imports = TextSearch.getDefaultSearch().splitPositionsIn(text, bImports.e(), eImports.b(), new String[] { "\n" }, false); //$NON-NLS-1$
for (Int2 import1 : imports) {
Int2 importPos = import1;
importPos = TextSearch.getDefaultSearch().trim(text, importPos.b(), importPos.e());
if (importPos.b() > -1) {
if (importPos.e() > importPos.b()) {
if (TextSearch.getDefaultSearch().indexIn(text, TemplateConstants.IMPORT_WORD, importPos.b(), importPos.e()).b() == importPos.b()) {
final Int2 valuePos = TextSearch.getDefaultSearch().trim(text, importPos.b() + TemplateConstants.IMPORT_WORD.length(), importPos.e());
if (valuePos.b() > -1) {
final String value = text.substring(valuePos.b(), valuePos.e()).trim();
if (importValues.contains(value)) {
problems.add(new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.DuplicateValue", new Object[] { "import", }), this, valuePos)); //$NON-NLS-1$ //$NON-NLS-2$
} else {
importValues.add(value);
try {
newImport(fileHierarchy, value, valuePos, importValues.size());
} catch (final TemplateSyntaxException e) {
problems.add(e);
}
}
} else {
problems.add(new TemplateSyntaxException(
AcceleoGenMessages.getString("TemplateSyntaxError.EmptyImport"), this, importPos.b() + TemplateConstants.IMPORT_WORD.length())); //$NON-NLS-1$
}
} else if (TextSearch.getDefaultSearch().indexIn(text, TemplateConstants.MODELTYPE_WORD, importPos.b(), importPos.e()).b() == importPos.b()) {
final Int2 valuePos = TextSearch.getDefaultSearch().trim(text, importPos.b() + TemplateConstants.MODELTYPE_WORD.length(), importPos.e());
if (valuePos.b() > -1) {
final String value = text.substring(valuePos.b(), valuePos.e()).trim();
if (importValues.contains(value)) {
problems.add(new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.DuplicateValue", new Object[] { "metamodel", }), this, valuePos)); //$NON-NLS-1$ //$NON-NLS-2$
} else {
importValues.add(value);
try {
newImport(fileHierarchy, value, valuePos, importValues.size());
} catch (final TemplateSyntaxException e) {
problems.add(e);
}
}
} else {
problems.add(new TemplateSyntaxException(
AcceleoGenMessages.getString("TemplateSyntaxError.EmptyValue", new Object[] { "metamodel", }), this, importPos.b() + TemplateConstants.MODELTYPE_WORD.length())); //$NON-NLS-1$ //$NON-NLS-2$
}
} else {
problems.add(new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.MissingKeyWord", new Object[] { "import", }), this, importPos.b())); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
}
pos = eImports.e();
} else {
problems.add(new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.InvalidImportSequence"), this, bImports.b())); //$NON-NLS-1$
pos = end;
}
} else {
pos = end;
}
}
}
/**
* Creates an import.
*
* @param fileHierarchy
* is the imported scripts hierarchy
* @param value
* is the import value
* @param valuePos
* is the position of the value in the script
* @param num
* is the number of the import
* @throws TemplateSyntaxException
*/
private void newImport(List fileHierarchy, String value, Int2 valuePos, int num) throws TemplateSyntaxException {
boolean isMetamodelImport = parseMetamodelImport(value, valuePos, num);
if (scriptContext == null || scriptContext.getMaxLevel() == -1 || fileHierarchy.size() < scriptContext.getMaxLevel()) {
if (!isMetamodelImport) {
if (file != null) {
boolean service = false;
boolean specificExists = false;
// Specific script file
final String[] specificExtensions = getSpecificImportExtensions();
for (String specificExtension : specificExtensions) {
final File specificFile = resolveScriptFile(file, value, specificExtension);
if (specificFile != null && specificFile.exists()) {
// Is recursive import?
IScript genSpecific = this;
do {
if (genSpecific.getFile() != null && genSpecific.getFile().equals(specificFile)) {
throw new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.RecursiveImport"), this, valuePos); //$NON-NLS-1$
}
genSpecific = genSpecific.getSpecific();
} while (genSpecific != null);
// Add import
try {
if (!tryOptimizedImport(fileHierarchy, specificFile)) {
final SpecificScript newImport = createSpecificImport(specificFile);
newImport.setInitProfiling(initProfiling);
newImport.reset(new ArrayList(fileHierarchy));
newImport.setSpecific(this);
addImport(newImport);
}
} catch (final TemplateSyntaxExceptions e) {
String message = AcceleoGenMessages.getString("SpecificScript.ErroneousTemplate"); //$NON-NLS-1$
if (e.getProblems().size() == 1) {
message += " : " + ((TemplateSyntaxException) e.getProblems().get(0)).getMessage(); //$NON-NLS-1$
}
throw new TemplateSyntaxException(message, this, valuePos);
}
specificExists = true;
}
}
// Java service
try {
addImportForJavaService(file, value);
service = true;
} catch (final JavaServiceNotFoundException e) {
// throw new
// TemplateSyntaxException(e.getMessage(),this,valuePos);
}
if (!service && !specificExists) {
throw new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.UnresolvedImport", new Object[] { value, }), this, valuePos); //$NON-NLS-1$
}
}
}
}
}
/**
* Add a java service to import list.
*
* @param file
* the current script file
* @param value
* the class name
* @throws JavaServiceNotFoundException
* if the class designed by value doesn't exists
*/
protected void addImportForJavaService(final File file, final String value) throws JavaServiceNotFoundException {
addImport(new EvalJavaService(file, value));
}
protected File resolveScriptFile(File script, String importValue, String extension) {
File res = null;
final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(new Path(script.getAbsolutePath()));
if (file != null && file.isAccessible()) {
final IPath importPath = new Path(importValue.replaceAll("\\.", "/")).addFileExtension(extension); //$NON-NLS-1$ //$NON-NLS-2$
res = getScriptFileInProject(file.getProject(), importPath);
} else {
final String pluginId = AcceleoModuleProvider.getDefault().getPluginId(script);
if (pluginId != null) {
final Bundle bundle = Platform.getBundle(pluginId);
if (bundle != null) {
res = AcceleoModuleProvider.getDefault().getFile(bundle.getSymbolicName(), importValue, extension);
}
}
}
return res;
}
private String fileScriptToImportString(File script) {
String res = "";
final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(new Path(script.getAbsolutePath()));
String[] segments = file.getProjectRelativePath().segments();
for (int i = 1; i < segments.length; ++i) {
res += segments[i];
if (i < segments.length - 1) {
res += "."; //$NON-NLS-1$
}
}
return res;
}
private File getScriptFileInProject(IProject project, IPath importPath) {
File result = null;
if (project.exists()) {
try {
final IJavaProject javaProject = JavaCore.create(project);
final IClasspathEntry[] entries = javaProject.getResolvedClasspath(true);
for (int i = 0; i < entries.length && result == null; i++) {
final IClasspathEntry entry = entries[i];
if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE && entry.getPath().segmentCount() > 1) {
final IFile test = ResourcesPlugin.getWorkspace().getRoot().getFile(entry.getPath().append(importPath));
if (test.exists()) {
result = test.getLocation().toFile();
}
}
}
for (int i = 0; i < entries.length && result == null; i++) {
final IClasspathEntry entry = entries[i];
if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT && entry.getPath().segmentCount() == 1) {
final IProject entryProject = ResourcesPlugin.getWorkspace().getRoot().getProject(entry.getPath().segment(0));
if (entryProject != null && entryProject.exists()) {
result = getScriptFileInProject(entryProject, importPath);
}
}
}
} catch (final JavaModelException e) {
result = null;
}
if (result == null) {
final String[] requiredPluginIDs = Resources.getRequiredPluginIDs(project);
for (int i = 0; i < requiredPluginIDs.length && result == null; i++) {
final IProject bundleProject = ResourcesPlugin.getWorkspace().getRoot().getProject(requiredPluginIDs[i]);
if (bundleProject != null && bundleProject.exists()) {
result = getScriptFileInProject(bundleProject, importPath);
} else if (Platform.getBundle(requiredPluginIDs[i]) != null) {
result = AcceleoModuleProvider.getDefault().getFile(requiredPluginIDs[i], importPath);
}
}
}
}
return result;
}
/**
* Tries to parse the import value and creates a metamodel import.
*
* @param value
* is the import value
* @param valuePos
* is the position of the value in the script
* @param num
* is the number of the import
* @return true if a metamodel import has been created
* @throws TemplateSyntaxException
*/
protected boolean parseMetamodelImport(String value, Int2 valuePos, int num) throws TemplateSyntaxException {
if (num == 1) {
value = value.trim();
final EPackage regValue = EPackage.Registry.INSTANCE.getEPackage(value);
if (regValue != null) {
final EvalModel anImport = new EvalModel(value);
if (anImport.getMetamodel() == null) {
throw new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.UnresolvedMetamodel"), this, valuePos); //$NON-NLS-1$
}
metamodel = anImport.getMetamodel();
addImport(anImport);
return true;
} else {
IPath ecorePath = new Path(value);
if (ecorePath.segmentCount() >= 2) {
ecorePath = ecorePath.removeFileExtension().addFileExtension("ecore"); //$NON-NLS-1$
}
final File ecoreFile = AcceleoMetamodelProvider.getDefault().getFile(ecorePath);
if (ecoreFile != null && ecoreFile.exists()) {
final EvalModel anImport = new EvalModel(value);
if (anImport.getMetamodel() == null) {
throw new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.UnresolvedMetamodel"), this, valuePos); //$NON-NLS-1$
}
metamodel = anImport.getMetamodel();
addImport(anImport);
return true;
} else {
throw new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.UnresolvedMetamodel"), this, valuePos); //$NON-NLS-1$
}
}
} else {
return false;
}
}
/**
* Gets all the file extensions that are accepted in the imports.
*
* @return a table of extensions
*/
protected String[] getSpecificImportExtensions() {
return new String[] { SpecificScript.GENERATORS_EXTENSION };
}
/**
* Creates a specific import for the given file.
*
* @param specificFile
* is the file to import
* @return the new specific import
*/
protected SpecificScript createSpecificImport(File specificFile) {
if (scriptContext != null) {
final SpecificScript result = scriptContext.getScript(specificFile, chainFile);
if (result != null) {
return result;
}
}
final SpecificScript result = new SpecificScript(specificFile, chainFile, scriptContext);
return result;
}
/**
* Tries a quick import with the file modification stamp.
*
* @param fileHierarchy
* is the imported scripts hierarchy
* @param file
* is the file to import
* @return true if the quick import is done
* @throws TemplateSyntaxExceptions
*/
private boolean tryOptimizedImport(List fileHierarchy, File file) throws TemplateSyntaxExceptions {
boolean tryOptimizedImport;
final IFile workspaceFile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(new Path(file.getAbsolutePath()));
if (workspaceFile != null && workspaceFile.isAccessible()) {
final Double newModificationStamp = new Double(workspaceFile.getModificationStamp());
final Double oldModificationStamp = (Double) mt2OldModificationStamp.get(workspaceFile);
if (oldModificationStamp != null && oldModificationStamp.doubleValue() == newModificationStamp.doubleValue()) {
tryOptimizedImport = true;
} else {
tryOptimizedImport = false;
}
mt2OldModificationStamp.put(workspaceFile, newModificationStamp);
} else {
tryOptimizedImport = true;
}
if (tryOptimizedImport) {
final Iterator it = oldImports.iterator();
while (it.hasNext()) {
final Object oldImportObject = it.next();
if (oldImportObject instanceof SpecificScript) {
final SpecificScript oldImport = (SpecificScript) oldImportObject;
if (oldImport.getFile().equals(file)) {
oldImport.clearFoundProperties();
oldImport.reset(new ArrayList(fileHierarchy));
addImport(oldImport);
oldImport.setSpecific(this);
return true;
}
}
}
}
return false;
}
/* (non-Javadoc) */
@Override
public void addImport(IEvalSettings element) {
super.addImport(element);
}
/**
* Quick imports : old script modification stamp.
*/
private final Map mt2OldModificationStamp = new HashMap();
/**
* Quick imports : old imports.
*/
private List oldImports = new ArrayList();
/**
* It checks the semantic of the links.
*
* @param problems
* are the semantic problems detected during this checking.
*/
protected void checkAllExpressions(List problems) {
if (metamodel == null) {
problems.add(new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.InvalidImportSequence"), this, 0)); //$NON-NLS-1$
} else {
final Iterator textTemplates = this.textTemplates.entrySet().iterator();
while (textTemplates.hasNext()) {
final Map.Entry entry = (Map.Entry) textTemplates.next();
final String type = ((ScriptDescriptor) entry.getKey()).type;
final Template template = (Template) entry.getValue();
checkAllExpressions(problems, type, template);
}
final Iterator fileTemplates = this.fileTemplates.entrySet().iterator();
while (fileTemplates.hasNext()) {
final Map.Entry entry = (Map.Entry) fileTemplates.next();
final String type = (String) entry.getKey();
final Template template = (Template) entry.getValue();
checkAllExpressions(problems, type, template);
}
}
}
private void checkAllExpressions(List problems, String type, Template template) {
// Get the EClassifier for the identifier
final EClassifier classifier = ETools.getEClassifier(metamodel, type);
if (classifier == null) {
problems.add(new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.UnresolvedClassifier", new Object[] { type, }), this, template.getPos())); //$NON-NLS-1$
} else {
// Check the elements of the template
final List allElements = template.getAllElements(TemplateCallSetExpression.class);
if (template.getPostExpression() != null) {
allElements.addAll(template.getPostExpression().getAllElements(TemplateCallSetExpression.class));
}
final Iterator elements = allElements.iterator();
while (elements.hasNext()) {
final TemplateCallSetExpression callSet = (TemplateCallSetExpression) elements.next();
if (callSet != null) {
if (!callSet.isPredefined()) {
// Check not predefined links
Object resolvedType = callSet.getRootResolver(classifier, this);
final Iterator calls = callSet.iterator();
TemplateCallExpression call = null;
while (resolvedType != null && calls.hasNext()) {
// Remark : resolvedType == GENERIC_TYPE
// => resolvedType != null
call = (TemplateCallExpression) calls.next();
if (resolvedType == IEvalSettings.GENERIC_TYPE && call.getLink().length() > 0) {
final char[] array = call.getLink().toCharArray();
for (int i = 0; i < array.length; i++) {
if (!Character.isJavaIdentifierPart(array[i])) {
problems.add(new TemplateSyntaxException(
AcceleoGenMessages.getString("TemplateSyntaxError.InvalidCharacter", new Object[] { Character.toString(array[i]), }), this, new Int2(call.getPos().b() + i, call.getPos().b() + i + 1))); //$NON-NLS-1$
}
}
}
resolvedType = resolveType(resolvedType, call);
}
if (call != null) {
if (resolvedType == null) {
problems.add(new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.UnresolvedCall", new Object[] { call, }), this, call.getPos())); //$NON-NLS-1$
}
}
} else {
// Check the user tags
if (callSet.getFirst().getLink().equals(TemplateConstants.USER_BEGIN_NAME) && callSet.getFirst().countArguments() == 0) {
// Remark : isPredefined() &&
// USER_BEGIN_NAME => getParent() is
// instance of TemplateFeatureStatement
final TemplateFeatureStatement feature = (TemplateFeatureStatement) callSet.getParent();
boolean valid = false;
if (feature.getNext() != null && feature.getNext() instanceof TemplateText) {
final String nextString = ((TemplateText) feature.getNext()).toString();
final int iNewLine = nextString.indexOf("\n"); //$NON-NLS-1$
if (iNewLine == -1 || nextString.substring(0, iNewLine).trim().length() > 0) {
valid = true;
}
}
if (!valid && feature.getPrevious() != null && feature.getPrevious() instanceof TemplateText) {
final String previousString = ((TemplateText) feature.getPrevious()).toString();
final int iNewLine = previousString.lastIndexOf("\n"); //$NON-NLS-1$
if (iNewLine == -1 || previousString.substring(iNewLine).trim().length() > 0) {
valid = true;
}
}
if (!valid) {
problems.add(new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.EmptyUserTag"), this, callSet.getPos())); //$NON-NLS-1$
}
}
}
}
}
}
}
private void newScript(ScriptDescriptor descriptor, String text, Int2 limitsTextTemplate) throws TemplateSyntaxException {
if (descriptor != null && text != null) {
limitsTextTemplate = Template.formatTemplate(text, limitsTextTemplate, 2);
final Template textTemplate = createTextTemplate(descriptor, text, limitsTextTemplate);
if (descriptor.getFileTemplate() != null) {
createFileTemplate(descriptor.getType(), text, descriptor.getFileTemplate(), textTemplate);
}
if (descriptor.getPostExpression() != null) {
final TemplateExpression postExpression = TemplateExpression.fromString(text, descriptor.getPostExpression(), this);
textTemplate.setPostExpression(postExpression);
}
}
}
/* (non-Javadoc) */
public boolean hasError(EObject object) {
return false;
}
/* (non-Javadoc) */
@Override
public ENode eGetTemplate(ENode node, String name, ENode[] args, LaunchManager mode) throws ENodeException, FactoryException {
return eGetTemplateSub(node, name, args, mode);
}
public ENode eGetTemplateSub(ENode node, String name, ENode[] args, LaunchManager mode) throws ENodeException, FactoryException {
if (textTemplateNames.contains(name)) {
if (node.isEObject()) {
try {
final EObject object = node.getEObject();
final Template template = getTextTemplateForEObject(object, name);
if (template != null) {
contextPush(IScript.TEMPLATE_ARGS, args);
ENode result;
try {
final boolean withComment = !hasFileTemplate() && name.equals("write"); //$NON-NLS-1$
if (withComment) {
result = template.evaluateWithComment(object, mode);
} else {
result = template.evaluate(object, mode);
}
if (result.isNull()) {
final List children = template.getSignificantStatements();
if (children.size() > 1 || children.size() == 1 && !(children.get(0) instanceof TemplateFeatureStatement)) {
// isNull() => ""
result.asString();
}
}
if (withComment && name.equals("write") && template.isEmptyEvaluation()) { //$NON-NLS-1$
return null;
}
} finally {
contextPop(IScript.TEMPLATE_ARGS);
}
return result;
}
} catch (final ENodeCastException e) {
// Never catch
}
}
}
return null;
}
/* (non-Javadoc) */
@Override
public Object resolveType(Object type, TemplateCallExpression call, int depth) {
if ("".equals(call.getPrefix()) || TemplateConstants.LINK_PREFIX_SCRIPT.equals(call.getPrefix())) { //$NON-NLS-1$
if (call.getLink().length() == 0) {
return IEvalSettings.GENERIC_TYPE;
}
if (type instanceof EClassifier) {
final Iterator textTemplates = this.textTemplates.entrySet().iterator();
while (textTemplates.hasNext()) {
final Map.Entry entry = (Map.Entry) textTemplates.next();
final ScriptDescriptor key = (ScriptDescriptor) entry.getKey();
if (ETools.ofType((EClassifier) type, key.type) && key.name.equals(call.getLink())) {
return IEvalSettings.GENERIC_TYPE;
}
}
} else if (type == IEvalSettings.GENERIC_TYPE) {
final Iterator textTemplates = this.textTemplates.entrySet().iterator();
while (textTemplates.hasNext()) {
final Map.Entry entry = (Map.Entry) textTemplates.next();
final ScriptDescriptor key = (ScriptDescriptor) entry.getKey();
if (key.name.equals(call.getLink())) {
return IEvalSettings.GENERIC_TYPE;
}
}
}
}
return super.resolveType(type, call, depth);
}
/* (non-Javadoc) */
@Override
public Object[] getCompletionProposals(Object type, int depth) {
final List result = new ArrayList();
// Templates proposals
if (type instanceof EClassifier) {
final Iterator textTemplates = this.textTemplates.entrySet().iterator();
while (textTemplates.hasNext()) {
final Map.Entry entry = (Map.Entry) textTemplates.next();
if (ETools.ofType((EClassifier) type, ((ScriptDescriptor) entry.getKey()).type)) {
result.add(entry);
}
}
}
// Other proposals
result.addAll(Arrays.asList(super.getCompletionProposals(type, depth)));
return result.toArray();
}
/**
* Clears the found properties.
*/
private void clearFoundProperties() {
name2Properties.clear();
allProperties = null;
}
/**
* Gets the property for the key and the property file (without extension).
*
* @param name
* is the name of the property file (without ".properties"
* extension)
* @param key
* is the key
* @return the value for the given key
* @throws CoreException
* @throws IOException
*/
public String getProperty(String name, String key) throws CoreException, IOException {
final Properties properties = getOrCreateProperties(name);
if (properties != null) {
return properties.getProperty(key);
} else {
return null;
}
}
private Properties getOrCreateProperties(String name) throws CoreException, IOException {
Properties properties = (Properties) name2Properties.get(name);
if (properties == null) {
boolean found = false;
final List containers = getPropertyContainers();
final Iterator it = containers.iterator();
while (it.hasNext() && !found) {
final File container = (File) it.next();
if (container.exists() && container.isDirectory()) {
final File[] members = container.listFiles();
for (int i = 0; i < members.length && !found; i++) {
if (members[i].isFile() && (name + ".properties").equals(members[i].getName())) { //$NON-NLS-1$
properties = new Properties();
properties.load(members[i].toURL().openStream());
name2Properties.put(name, properties);
found = true;
}
}
}
}
}
return properties;
}
private final Map name2Properties = new HashMap();
/**
* Gets the value for the key in all the properties files.
*
* @param key
* is the key
* @return the value for the given key
* @throws CoreException
* @throws IOException
*/
public String getProperty(String key) throws CoreException, IOException {
final Properties[] properties = getOrCreateProperties();
for (Properties propertie : properties) {
if (propertie != null) {
final String value = propertie.getProperty(key);
if (value != null) {
return value;
}
}
}
return null;
}
private Properties[] getOrCreateProperties() throws CoreException, IOException {
if (allProperties == null) {
final List allPropertiesList = new ArrayList();
final List containers = getPropertyContainers();
final Iterator it = containers.iterator();
while (it.hasNext()) {
final File container = (File) it.next();
if (container.exists() && container.isDirectory()) {
final File[] members = container.listFiles();
for (File member : members) {
if (member.isFile() && member.getName() != null && member.getName().endsWith(".properties")) { //$NON-NLS-1$
final Properties properties = new Properties();
properties.load(member.toURL().openStream());
name2Properties.put(new Path(member.getName()).removeFileExtension().lastSegment(), properties);
allPropertiesList.add(properties);
}
}
}
}
allProperties = (Properties[]) allPropertiesList.toArray(new Properties[allPropertiesList.size()]);
}
return allProperties;
}
private Properties[] allProperties = null;
/**
* Gets the properties files containers.
*
* @return the properties files containers
*/
protected List getPropertyContainers() {
final List result = new ArrayList();
if (chainFile != null && chainFile.getParentFile() != null) {
result.add(chainFile.getParentFile());
}
if (file != null && file.getParentFile() != null) {
result.add(file.getParentFile());
File project = null;
final IFile workspaceFile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(new Path(file.getAbsolutePath()));
if (workspaceFile != null && workspaceFile.isAccessible()) {
project = workspaceFile.getProject().getLocation().toFile();
}
final String pluginId = AcceleoModuleProvider.getDefault().getPluginId(file);
if (pluginId != null) {
final Bundle bundle = Platform.getBundle(pluginId);
if (bundle != null) {
final URL url = bundle.getEntry("/"); //$NON-NLS-1$
if (url != null) {
final File file = new File(Resources.transformToAbsolutePath(url));
if (file.exists()) {
project = file;
}
}
}
}
if (project != null && project.exists()) {
File parent = file.getParentFile().getParentFile();
while (parent != null && parent.exists()) {
result.add(parent);
if (parent.equals(project)) {
break;
} else {
parent = parent.getParentFile();
}
}
}
}
return result;
}
/* (non-Javadoc) */
public boolean validateCall(TemplateCallExpression call) {
return "".equals(call.getPrefix()) || TemplateConstants.LINK_PREFIX_SCRIPT.equals(call.getPrefix()); //$NON-NLS-1$
}
/**
* Sets initProfiling value.
*
* @param initProfiling
*/
public void setInitProfiling(boolean initProfiling) {
this.initProfiling = initProfiling;
}
}