blob: 465135c02b22e0245c4b52668b099a88d84dad21 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2020 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.acceleo.aql.evaluation.writer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.eclipse.acceleo.OpenModeKind;
import org.eclipse.acceleo.ProtectedArea;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.URIConverter;
/**
* This generation strategy can be used to generate files on-the-fly.
* <p>
* It will create {@link java.io.BufferedWriter}s so that files are just written to the disk as needed. This
* is the least memory-expensive strategy; however, it is not aware of the workspace and the VCSs in use for
* these files and does not check for write permission before writing the files. As such, it is not to be used
* with a pessimistic locking VCS such as clearcase for example.
* </p>
*
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
*/
public class DefaultGenerationStrategy implements IAcceleoGenerationStrategy {
/** Used to call URIConverter methods with no options. */
private static final Map<String, Object> EMPTY_OPTION_MAP = new HashMap<>();
/**
* Keeps track of the contents of all protected areas from the files we've created writers for.
* <p>
* This will only contain contents about the writers created in {@link OpenModeKind#OVERWRITE} mode.
* </p>
*/
protected final Map<URI, Map<String, String>> protectedAreaContents;
/**
* We'll use this uri converter to create our streams towards files to be opened in
* {@link OpenModeKind#OVERWRITE} or {@link OpenModeKind#CREATE} mode.
*/
protected final URIConverter uriConverter;
/**
* Constructor.
*/
public DefaultGenerationStrategy() {
protectedAreaContents = new LinkedHashMap<URI, Map<String, String>>();
uriConverter = URIConverter.INSTANCE; // FIXME pass the instance ?
}
@Override
public void closeWriter(IAcceleoWriter writer) throws IOException {
writer.close();
}
@Override
public String getProtectedAreaContent(URI uri, String protectedAreaID) {
// TODO Auto-generated method stub
return null;
}
@Override
public IAcceleoWriter createWriterFor(URI uri, OpenModeKind openMode, Charset charset,
String lineDelimiter) throws IOException {
final IAcceleoWriter writer;
final boolean exists = uriConverter.exists(uri, EMPTY_OPTION_MAP);
switch (openMode) {
case CREATE:
if (exists) {
writer = new NullWriter(uri);
break;
}
// fall through: same behavior as "OVERWRITE" if the file doesn't exist
case OVERWRITE:
if (exists) {
try (InputStream input = uriConverter.createInputStream(uri);) {
Map<String, String> protectedAreas = readProtectedAreaContent(new InputStreamReader(
input), lineDelimiter);
if (protectedAreas != null && !protectedAreas.isEmpty()) {
protectedAreaContents.put(uri, protectedAreas);
}
}
}
writer = new AcceleoFileWriter(uri, uriConverter, charset);
break;
case APPEND:
// FIXME we can't create a stream to "append" to a file with the URIConverter. We probably
// need to fall back to a regular FileWriter here. For now, we'll fall through to the
// "default" case and use a null writer.
default:
// TODO shouldn't happen, fall back to a null writer and log
writer = new NullWriter(uri);
break;
}
return writer;
}
@Override
public void terminate() {
// TODO Auto-generated method stub
}
/**
* Gets the mapping from {@link ProtectedArea}'s {@link ProtectedArea#getId() ID} to its content.
*
* @param reader
* the {@link Reader}
* @param lineDelimiter
* the line delimiter to use to create content
* @return the mapping from {@link ProtectedArea}'s {@link ProtectedArea#getId() ID} to its content
* @throws IOException
* if the {@link Reader} can't be read
*/
protected Map<String, String> readProtectedAreaContent(Reader reader, String lineDelimiter)
throws IOException {
final Map<String, String> protectedAreas = new LinkedHashMap<>();
final BufferedReader localReader = new BufferedReader(reader);
String line = localReader.readLine();
while (line != null) {
final int start = line.indexOf(USER_CODE_START);
if (start >= 0) {
final String marker = line.substring(start + USER_CODE_START.length()).trim();
final StringBuffer areaContent = new StringBuffer(1024);
areaContent.append(line.substring(start));
line = localReader.readLine();
while (line != null) {
final int end = line.indexOf(USER_CODE_END);
if (end >= 0) {
final int endOffset = end + USER_CODE_END.length();
areaContent.append(line.substring(0, endOffset));
break;
} else {
areaContent.append(line);
areaContent.append(lineDelimiter);
}
}
protectedAreas.put(marker, areaContent.toString());
}
line = localReader.readLine();
}
return protectedAreas;
}
}