WorkspaceMechanicConfigParser.java
package de.funfried.netbeans.plugins.external.formatter.eclipse.mechanic;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.validator.routines.UrlValidator;
import org.netbeans.api.annotations.common.NonNull;
import de.funfried.netbeans.plugins.external.formatter.eclipse.xml.EclipseFormatterUtils;
/**
* A parser for Workspace Mechanic configuration files.
*/
public class WorkspaceMechanicConfigParser {
private static final Logger log = Logger.getLogger(WorkspaceMechanicConfigParser.class.getName());
private static final String MULTI_FILE_SETUP_PREFIX = "/instance/com.google.eclipse.mechanic/mechanicSourceDirectories";
/**
* Parses and returns properties of the given {@code path} into a key value {@link Map}. If an optional
* {@code prefix} is specified, only the properties where the key starts with the given {@code prefix}
* are returned and the {@code prefix} will be removed from the keys in the returned {@link Map}.
*
* @param path a configuration file path or URL
* @param prefix an optional key prefix
*
* @return properties of the given {@code path} as a key value {@link Map}
*
* @throws IOException if there is an issue accessing the given configuration file
*/
@NonNull
public static Map<String, String> readPropertiesFromConfiguration(String path, String prefix) throws IOException {
Properties properties = createPropertiesFromPath(path);
if (properties.containsKey(MULTI_FILE_SETUP_PREFIX)) {
parseAdditionalFiles((String) properties.get(MULTI_FILE_SETUP_PREFIX)).stream().forEach(p -> properties.putAll(p));
properties.remove(MULTI_FILE_SETUP_PREFIX);
}
return EclipseFormatterUtils.toMap(properties, prefix);
}
@NonNull
private static List<Properties> parseAdditionalFiles(String pathStruct) throws IOException {
// the pathStruct looks as follows:
// ["/path/to/additional/mechanic/files","/path/to/origin/mechanic/file"]
pathStruct = StringUtils.trimToEmpty(pathStruct);
pathStruct = StringUtils.removeStart(pathStruct, "[");
pathStruct = StringUtils.removeEnd(pathStruct, "]");
List<Properties> result = new ArrayList<>();
String[] additionalFilesPaths = StringUtils.split(pathStruct, ",");
for (String additionalFilesPath : additionalFilesPaths) {
additionalFilesPath = StringUtils.removeStart(additionalFilesPath, "\"");
additionalFilesPath = StringUtils.removeEnd(additionalFilesPath, "\"");
Properties additionalProperties = createPropertiesFromPath(additionalFilesPath);
result.add(additionalProperties);
}
return result;
}
@NonNull
private static Properties createPropertiesFromPath(String path) throws IOException {
if (StringUtils.isBlank(path)) {
return new Properties();
}
if (UrlValidator.getInstance().isValid(path)) {
try {
URL url = new URL(path);
Properties properties = new Properties();
properties.load(url.openStream());
return properties;
} catch (IOException ex) {
log.log(Level.WARNING, "Could not read given path as URL, fallback to local file reading", ex);
}
}
return createPropertiesFromFile(new File(path));
}
@NonNull
private static Properties createPropertiesFromFile(File file) throws IOException {
Properties properties = new Properties();
if (file != null && file.exists()) {
if (file.isFile()) {
try (FileInputStream is = new FileInputStream(file)) {
properties.load(is);
}
} else if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
if (file.isDirectory() || (file.isFile() && StringUtils.endsWith(file.getName(), EclipseFormatterUtils.EPF_FILE_EXTENSION))) {
Properties additionalProperties = createPropertiesFromFile(f);
properties.putAll(additionalProperties);
}
}
}
}
return properties;
}
}