FileManager.java
/*
* Copyright (C) 2002-2003,2017-2023 Dipl.-Inform. Kai Hofmann. All rights reserved!
*/
package de.powerstat.phplib.templateengine.intern;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Template file manager.
*/
public final class FileManager
{
/**
* Logger.
*/
private static final Logger LOGGER = LogManager.getLogger(FileManager.class);
/**
* Maximum template size.
*/
private static final int MAX_TEMPLATE_SIZE = 1048576;
/**
* File path separator.
*/
private static final String FILEPATH_SEPARATOR = "/"; //$NON-NLS-1$
/**
* Variable manager reference.
*/
private final VariableManager variableManager;
/**
* File name map.
*/
private final Map<String, File> files = new ConcurrentHashMap<>();
/**
* Copy constructor.
*
* @param vManager Variable manager
* @param fManager File manager to copy from
* @throws NullPointerException If vManager or fManager is null
*/
@SuppressFBWarnings("EI_EXPOSE_REP2")
public FileManager(final VariableManager vManager, final FileManager fManager)
{
super();
Objects.requireNonNull(vManager, "vManager"); //$NON-NLS-1$
Objects.requireNonNull(fManager, "fManager"); //$NON-NLS-1$
this.variableManager = vManager;
for (final Map.Entry<String, File> entry : fManager.files.entrySet())
{
this.files.put(entry.getKey(), entry.getValue());
}
}
/**
* Constructor.
*
* @param vManager Variable manager
*/
@SuppressFBWarnings("EI_EXPOSE_REP2")
public FileManager(final VariableManager vManager)
{
super();
this.variableManager = vManager;
}
/**
* Add template file for variable.
*
* @param newVarname Variable that should hold the template
* @param newFile Template file UTF-8 encoded
* @return true when successful (file exists) otherwise false
* @throws NullPointerException If newVarname or newFile is null
* @throws IllegalArgumentException If newVarname is empty
*/
@SuppressWarnings({"PMD.LinguisticNaming", "java:S3457"})
public boolean addFile(final String newVarname, final File newFile)
{
// asserts
boolean exists = newFile.exists();
if (exists)
{
if (newFile.length() > FileManager.MAX_TEMPLATE_SIZE)
{
throw new IllegalArgumentException("newFile to large"); //$NON-NLS-1$
}
this.files.put(newVarname, newFile);
}
else
{
try (InputStream stream = this.getClass().getResourceAsStream(FileManager.FILEPATH_SEPARATOR + newFile.getName()))
{
if (stream != null)
{
exists = true;
this.files.put(newVarname, newFile);
}
}
catch (final IOException ignored)
{
// exists is already false
FileManager.LOGGER.warn("File does not exist: " + newFile.getAbsolutePath(), ignored); //$NON-NLS-1$
}
}
return exists;
}
/**
* Exists file for varname.
*
* @param varname Variable to read from file
* @return true if file exists, false otherwise
*/
public boolean existsFile(final String varname)
{
final var file = this.files.get(varname);
return (file != null);
}
/**
* Load template file (UTF-8 encoded) if required.
*
* @param varname Variable to read from file
* @return true if successful otherwise false
* @throws FileNotFoundException File not found
* @throws IOException IO exception
*/
@SuppressWarnings("PMD.CloseResource")
public boolean loadFile(final String varname) throws IOException
{
// assert (varname != null) && !varname.isEmpty() && (varname.length() <= TemplateEngine.MAX_VARNAME_SIZE);
if (this.variableManager.existsVar(varname)) // Already loaded?
{
return true;
}
final var file = this.files.get(varname);
if (file == null)
{
return false;
}
InputStream istream = this.getClass().getResourceAsStream(FileManager.FILEPATH_SEPARATOR + file.getName()); // Read from classpath/jar
if (istream == null)
{
istream = Files.newInputStream(this.files.get(varname).toPath(), StandardOpenOption.READ); // Read from filesystem
}
final var fileBuffer = new StringBuilder();
try (var reader = new BufferedReader(new InputStreamReader(istream, StandardCharsets.UTF_8)))
{
String line = reader.readLine();
while (line != null)
{
fileBuffer.append(line);
fileBuffer.append('\n');
line = reader.readLine();
}
}
if (fileBuffer.length() == 0)
{
return false;
}
this.variableManager.setVar(varname, fileBuffer.toString());
return true;
}
/**
* Returns the string representation of this FileManager.
*
* The exact details of this representation are unspecified and subject to change, but the following may be regarded as typical:
*
* "FileManager[files=[name, ...]]"
*
* @return String representation of this FileManager.
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return new StringBuilder().append("FileManager[").append("files=").append(this.files.values().stream().map(File::getName).reduce((s1, s2) -> s1 + ", " + s2)).append(']').toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
/**
* Calculate hash code.
*
* @return Hash
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode()
{
return Objects.hash(this.files);
}
/**
* Is equal with another object.
*
* @param obj Object
* @return true when equal, false otherwise
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj)
{
if (this == obj)
{
return true;
}
if (!(obj instanceof FileManager))
{
return false;
}
final FileManager other = (FileManager)obj;
return this.files.equals(other.files) && this.variableManager.equals(other.variableManager);
}
}