blob: d5e90fe61afd5988986d202996db84ece840dea8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 The University of York.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Louis Rose - initial API and implementation
******************************************************************************/
package org.eclipse.epsilon.egl;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import org.eclipse.epsilon.common.util.UriUtil;
import org.eclipse.epsilon.egl.exceptions.EglRuntimeException;
import org.eclipse.epsilon.egl.execute.context.EglContext;
import org.eclipse.epsilon.egl.execute.context.IEglContext;
import org.eclipse.epsilon.egl.execute.control.ITemplateExecutionListener;
import org.eclipse.epsilon.egl.formatter.CompositeFormatter;
import org.eclipse.epsilon.egl.formatter.Formatter;
import org.eclipse.epsilon.egl.formatter.NullFormatter;
import org.eclipse.epsilon.egl.incremental.IncrementalitySettings;
import org.eclipse.epsilon.egl.spec.EglTemplateSpecification;
import org.eclipse.epsilon.egl.spec.EglTemplateSpecificationFactory;
import org.eclipse.epsilon.egl.util.FileUtil;
public class EglTemplateFactory {
protected IEglContext context;
protected URI root;
private URI templateRoot;
private String templateRootPath;
private Formatter defaultFormatter = new NullFormatter();
private IncrementalitySettings defaultIncrementalitySettings = new IncrementalitySettings();
private final Collection<ITemplateExecutionListener> listeners = new LinkedList<>();
public EglTemplateFactory() {
this.context = new EglContext(this);
}
public EglTemplateFactory(IEglContext context) {
this.context = context;
}
public EglTemplateFactory(EglTemplateFactory other) {
this.context = other.context;
this.root = other.root;
this.templateRoot = other.templateRoot;
this.templateRootPath = other.templateRootPath;
}
public Collection<ITemplateExecutionListener> getTemplateExecutionListeners() {
return this.listeners;
}
public IncrementalitySettings getDefaultIncrementalitySettings() {
return this.defaultIncrementalitySettings;
}
public void setDefaultFormatter(Formatter defaultFormatter) {
this.defaultFormatter = defaultFormatter;
}
public void setDefaultFormatters(Formatter... defaultFormatters) {
setDefaultFormatters(Arrays.asList(defaultFormatters));
}
public void setDefaultFormatters(Collection<Formatter> defaultFormatters) {
setDefaultFormatter(new CompositeFormatter(defaultFormatters));
}
public IEglContext getContext() {
return context;
}
public void setContext(IEglContext context) {
this.context = context;
}
/**
* Sets the root of this template factory, unless it has already been set.
*/
public void initialiseRoot(URI root) {
if (this.root == null)
setRoot(root);
}
public void setRoot(URI root) {
this.root = root;
}
public String getTemplateRoot() {
return templateRootPath;
}
public void setTemplateRoot(String path) throws EglRuntimeException {
templateRootPath = path;
templateRoot = resolveRoot(path);
}
protected URI resolveRoot(String path) throws EglRuntimeException {
try {
path = UriUtil.encode(path, true);
return UriUtil.resolve(path, root);
} catch (URISyntaxException e) {
throw new EglRuntimeException("Could not resolve path: "+path, e, context.getModule());
}
}
public URI resolveTemplate(String path) throws EglRuntimeException {
try {
path = UriUtil.encode(path, false);
return UriUtil.resolve(path, templateRoot, root);
} catch (URISyntaxException e) {
throw new EglRuntimeException("Could not resolve path: "+path, e, context.getModule());
}
}
protected String name(String path) {
String name = path;
if (templateRootPath != null)
name = new File(templateRootPath).getPath() + FileUtil.FILE_SEP + name;
return name;
}
/**
* Loads an EglTemplate for the EGL code stored in the indicated file.
*
* Subclasses should override {@link #createTemplate(String, URI)}, rather
* than this method, unless they wish to alter the way in which a file is
* transformed into an EglTemplateSpecification
*/
public EglTemplate load(File file) throws EglRuntimeException {
final String name = name(file.getAbsolutePath());
try {
return load(createTemplateSpecificationFactory().fromResource(name, UriUtil.fileToUri(file)));
} catch (URISyntaxException e) {
return handleFailedLoad(name, e);
}
}
/**
* Loads an EglTemplate for the given EGL code as though it were
* contained in the given File. Used for parsing "dirty" code (which
* has not yet been saved to disk).
*
* Subclasses should override {@link #createTemplate(String, URI)}, rather
* than this method, unless they wish to alter the way in which a dirty
* resource is transformed into an EglTemplateSpecification
*/
protected EglTemplate load(String code, File file) throws EglRuntimeException {
final String name = name(file.getAbsolutePath());
try {
return load(createTemplateSpecificationFactory().fromDirtyResource(name, code, UriUtil.fileToUri(file)));
} catch (URISyntaxException e) {
return handleFailedLoad(name, e);
}
}
/**
* Loads an EglTemplate for the EGL code stored in the file at path.
*
* Subclasses should override {@link #createTemplate(String, URI)}, rather
* than this method, unless they wish to alter the way in which a path is
* transformed into an EglTemplateSpecification
*/
public EglTemplate load(String path) throws EglRuntimeException {
return load(createTemplateSpecificationFactory().fromResource(name(path), resolveTemplate(path)));
}
/**
* Loads an EglTemplate for the EGL code stored in the given resource.
*
* Subclasses should override {@link #createTemplate(String, URI)}, rather
* than this method, unless they wish to alter the way in which a resource is
* transformed into an EglTemplateSpecification
*/
public EglTemplate load(URI resource) throws EglRuntimeException {
final String name = resource.toString(); // FIXME better name for URIs
return load(createTemplateSpecificationFactory().fromResource(name, resource));
}
/**
* Loads an EglTemplate for the given EGL code as though it were
* contained in the given URI. Used for parsing "dirty" code (which
* has not yet been saved to disk).
*
* Subclasses should override {@link #createTemplate(String, URI)}, rather
* than this method, unless they wish to alter the way in which a dirty
* resource is transformed into an EglTemplateSpecification
*/
protected EglTemplate load(String code, URI resource) throws EglRuntimeException {
final String name = resource.toString(); // FIXME better name for URIs
return load(createTemplateSpecificationFactory().fromDirtyResource(name, code, resource));
}
/**
* Loads an EglTemplate from the given EglTemplateSpecification.
*
* Subclasses should override {@link #createTemplate(String, URI)}, rather
* than this method, unless they wish to alter the way in which IOExceptions
* are handled, in which case they should override {@link #handleFailedLoad(String, Exception)}.
*/
protected final EglTemplate load(EglTemplateSpecification spec) throws EglRuntimeException {
try {
initialiseRoot(spec.getURI());
return createTemplate(spec);
} catch (Exception e) {
return handleFailedLoad(spec.getName(), e);
}
}
protected EglTemplate handleFailedLoad(final String name, Exception e) throws EglRuntimeException {
final String reason = e instanceof FileNotFoundException ? "Template not found" : "Could not process";
throw new EglRuntimeException(reason + " '" + name + "'", e, context.getModule());
}
/**
* Prepares an EGL template that will execute the given
* EGL source code. Subclasses should override
* {@link #createTemplate(String)}, rather than this method,
* as this method may, in the future, acquire additional
* responsibilities, such as exception handling.
*/
public final EglTemplate prepare(String code) throws Exception {
return createTemplate(createTemplateSpecificationFactory().fromCode(code));
}
/**
* Creates a template from the given specification.
* Subclasses may override to create different types of template.
*/
protected EglTemplate createTemplate(EglTemplateSpecification spec) throws Exception {
return new EglTemplate(spec, context);
}
private EglTemplateSpecificationFactory createTemplateSpecificationFactory() {
return new EglTemplateSpecificationFactory(defaultFormatter, defaultIncrementalitySettings, listeners.toArray(new ITemplateExecutionListener[]{}));
}
@Override
public String toString() {
final String root = templateRoot == null ? "" : templateRoot.toString();
return "TemplateFactory: root='" + root + "'";
}
}