All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.epsilon.egl.EglFileGeneratingTemplate Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * 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.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.stream.Collectors;

import org.eclipse.epsilon.common.util.UriUtil;
import org.eclipse.epsilon.egl.exceptions.EglRuntimeException;
import org.eclipse.epsilon.egl.execute.context.IEglContext;
import org.eclipse.epsilon.egl.formatter.NullFormatter;
import org.eclipse.epsilon.egl.incremental.IncrementalitySettings;
import org.eclipse.epsilon.egl.merge.output.LocatedRegion;
import org.eclipse.epsilon.egl.patch.Line;
import org.eclipse.epsilon.egl.patch.Patch;
import org.eclipse.epsilon.egl.patch.PatchValidationDiagnostic;
import org.eclipse.epsilon.egl.patch.TextBlock;
import org.eclipse.epsilon.egl.spec.EglTemplateSpecification;
import org.eclipse.epsilon.egl.spec.EglTemplateSpecificationFactory;
import org.eclipse.epsilon.egl.status.ProtectedRegionWarning;
import org.eclipse.epsilon.egl.traceability.OutputFile;
import org.eclipse.epsilon.egl.util.FileUtil;
import org.eclipse.epsilon.eol.ImportManager;

public class EglFileGeneratingTemplate extends EglPersistentTemplate {

	private File target;
	private String targetName;
	private OutputFile currentOutputFile;
	private String existingContents;
	private String newContents;
	private String positiveMessage;
	private OutputMode outputMode;

	public static enum OutputMode {
		WRITE, MERGE, APPEND, PATCH;
	}
	
	// For tests
	protected EglFileGeneratingTemplate(URI path, IEglContext context, URI outputRoot) throws Exception {
		this(new EglTemplateSpecificationFactory(new NullFormatter(), new IncrementalitySettings(), new ImportManager()).fromResource(path.toString(), path), context, outputRoot);
	}

	public EglFileGeneratingTemplate(EglTemplateSpecification spec, IEglContext context, URI outputRoot, String outputRootPath) throws Exception {
		super(spec, context, outputRoot, outputRootPath);
	}
	
	/**
	 * 
	 * @param spec
	 * @param context
	 * @param outputRoot
	 * @throws Exception
	 * @since 1.6
	 */
	public EglFileGeneratingTemplate(EglTemplateSpecification spec, IEglContext context, URI outputRoot) throws Exception {
		super(spec, context, outputRoot);
	}
	
	public File append(String path) throws EglRuntimeException {
		return write(path, OutputMode.APPEND);
	}
	
	public File patch(String path) throws EglRuntimeException {
		return write(path, OutputMode.PATCH);
	}
	
	protected File write(String path, OutputMode outputMode) throws EglRuntimeException {
		try {
			final File target = resolveFile(path);

			if (!isProcessed()) {
				process();
			}
			
			this.target = target;
			this.targetName = name(path);			
			this.existingContents = FileUtil.readIfExists(target);
			this.outputMode = outputMode;
			
			prepareNewContents();
			writeNewContentsIfDifferentFromExistingContents();

			return target;
		} catch (URISyntaxException e) {
			throw new EglRuntimeException("Could not resolve path: " + target, e, module);
		} catch (IOException ex) {
			throw new EglRuntimeException("Could not generate to: " + target, ex, module);
		}
	}

	@Override
	protected void doGenerate(File target, String targetName, boolean overwrite, boolean merge) throws EglRuntimeException {
		try {
			this.target = target;
			this.targetName = targetName;			
			this.existingContents = FileUtil.readIfExists(target);
			this.outputMode = (merge && target.exists()) ? OutputMode.MERGE : OutputMode.WRITE;
			
			prepareNewContents();
			writeNewContentsIfDifferentFromExistingContents();
			
		} catch (URISyntaxException e) {
			throw new EglRuntimeException("Could not resolve path: " + target, e, module);
		} catch (IOException ex) {
			throw new EglRuntimeException("Could not generate to: " + target, ex, module);
		}
	}
	
	protected void prepareNewContents() throws EglRuntimeException {
		switch (outputMode) {
			case APPEND: {
				newContents = getExistingContents() != null ?
					getExistingContents() + FileUtil.NEWLINE + getContents() :
					getContents();
				positiveMessage = "Successfully appended to ";
				break;
			}
			case MERGE: {
				newContents = merge(getExistingContents());
				positiveMessage = "Protected regions preserved in ";
				break;
			}
			case WRITE: {
				newContents = getContents();
				positiveMessage = "Successfully wrote to ";
				break;
			}
			case PATCH: {
				positiveMessage = "Successfully patched ";
				
				TextBlock existingContentsBlock = new TextBlock(getExistingContents().split(System.lineSeparator()));
				Patch patch = new Patch(getContents().split(System.lineSeparator()));
				List patchValidationDiagnostics = patch.validate();
				if (!patchValidationDiagnostics.isEmpty()) {
					PatchValidationDiagnostic patchValidationDiagnostic = patchValidationDiagnostics.get(0);
					throw new EglRuntimeException("Invalid patch. Line " + 
							patchValidationDiagnostic.getLine().getNumber() + ": " + 
							patchValidationDiagnostic.getReason(), new IllegalStateException());
				}
				
				TextBlock newContentsBlock = patch.apply(existingContentsBlock);
				
				newContents = newContentsBlock.getLines().stream()
					.map(Line::getText)
					.collect(Collectors.joining(System.lineSeparator()));
				
				break;
			}
			default:
				throw new EglRuntimeException("Unsupported output mode " + outputMode, new IllegalStateException());
		}
	}
	
	protected void writeNewContentsIfDifferentFromExistingContents() throws URISyntaxException, IOException {
		if (isOverwriteUnchangedFiles() || !newContents.equals(existingContents)) {
			write();
			addMessage(getPositiveMessage() + getTargetName());
		} else {
			addMessage("Content unchanged for " + getTargetName());			
		}
	}
	
	protected boolean isOverwriteUnchangedFiles() {
		return getIncrementalitySettings().isOverwriteUnchangedFiles();
	}

	protected void write() throws IOException, URISyntaxException {
		if (getTarget() != null) {
			FileUtil.write(getTarget(), getNewContents());
		}
		
		currentOutputFile = getTemplate().addOutputFile(getTargetName(), UriUtil.fileToUri(getTarget()));
		
		if (getOutputMode() == OutputMode.MERGE) {
			for (LocatedRegion pr : module.getContext().getPartitioner().partition(getNewContents()).getLocatedRegions()) {
				getCurrentOutputFile().addProtectedRegion(pr.getId(), pr.isEnabled(), pr.getOffset());
			}
		}
	}

	@Override
	protected void addProtectedRegionWarning(ProtectedRegionWarning warning) {
		super.addProtectedRegionWarning(new ProtectedRegionWarning(warning.getId(), target.getAbsolutePath()));
	}

	public File getTarget() {
		return target;
	}

	public void setTarget(File target) {
		this.target = target;
	}

	public String getTargetName() {
		return targetName;
	}

	public void setTargetName(String targetName) {
		this.targetName = targetName;
	}

	public OutputFile getCurrentOutputFile() {
		return currentOutputFile;
	}

	public void setCurrentOutputFile(OutputFile currentOutputFile) {
		this.currentOutputFile = currentOutputFile;
	}

	public String getExistingContents() {
		return existingContents;
	}

	public void setExistingContents(String existingContents) {
		this.existingContents = existingContents;
	}

	public String getNewContents() {
		return newContents;
	}

	public void setNewContents(String newContents) {
		this.newContents = newContents;
	}

	public String getPositiveMessage() {
		return positiveMessage;
	}

	public void setPositiveMessage(String positiveMessage) {
		this.positiveMessage = positiveMessage;
	}

	public OutputMode getOutputMode() {
		return outputMode;
	}

	public void setOutputMode(OutputMode outputMode) {
		this.outputMode = outputMode;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy