Skip to content
Snippets Groups Projects
Commit 1991ebda authored by Bernhard Johannes Berger's avatar Bernhard Johannes Berger
Browse files

#7 Created interfaces from existing PropertiesReader and PropertiesWriter....

#7 Created interfaces from existing PropertiesReader and PropertiesWriter. Moved the JSON-based implementation to the main package since they are not part of the actual API. The reader and writer can be instanciated useing the PropertiesIOFactory which chooses an implementation based on the file ending.
parent 3d478af3
No related branches found
No related tags found
No related merge requests found
Pipeline #243130 failed
package de.evoal.core.api.properties.io;
import de.evoal.core.api.cdi.BeanFactory;
import de.evoal.core.api.properties.PropertiesSpecification;
import de.evoal.core.api.utils.EvoalIOException;
import java.io.File;
/**
* Factory class for creating instances of {@code PropertiesReader} and {@code PropertiesWriter}.
*/
public final class PropertiesIOFactory {
private PropertiesIOFactory() {}
public static PropertiesReader reader(final File filename, final PropertiesSpecification specification) throws EvoalIOException {
final String [] parts = filename.toString().split("\\.");
final String extension = parts[parts.length - 1];
final String name = extension + "-reader";
return BeanFactory.create(name, PropertiesReader.class).init(filename, specification);
}
public static PropertiesWriter writer(final File filename, final PropertiesSpecification specification) throws EvoalIOException {
final String [] parts = filename.toString().split("\\.");
final String extension = parts[parts.length - 1];
final String name = extension + "-writer";
return BeanFactory.create(name, PropertiesWriter.class).init(filename, specification);
}
}
package de.evoal.core.api.properties.io; package de.evoal.core.api.properties.io;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.evoal.core.api.properties.Properties; import de.evoal.core.api.properties.Properties;
import de.evoal.core.api.properties.PropertiesSpecification; import de.evoal.core.api.properties.PropertiesSpecification;
import de.evoal.core.api.properties.PropertySpecification; import de.evoal.core.api.utils.EvoalIOException;
import de.evoal.core.api.utils.Requirements;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
@Slf4j /**
public class PropertiesReader implements AutoCloseable, Iterator<Properties> { * Base interface for reading properties from disk.
*/
private final JsonParser jsonParser; public interface PropertiesReader extends AutoCloseable, Iterator<Properties> {
/**
private final Set<String> properties; * The reader's initialisation method. Receives the file to read and the
* specification to use.
private final PropertiesSpecification specification; *
* @param input The input file.
public PropertiesReader(final File inputFile, final PropertiesSpecification specification) throws IOException { * @param specification The input specification.
log.info("Creating properties reader for {}.", specification); *
this.specification = specification; * @return The instance itself.
*/
properties = specification.getProperties() public PropertiesReader init(final File input, final PropertiesSpecification specification) throws EvoalIOException;
.stream()
.map(PropertySpecification::name)
.collect(Collectors.toSet());
final ObjectMapper mapper = new ObjectMapper();
jsonParser = mapper.createParser(inputFile);
jsonParser.nextToken();
assertStartArray();
}
private Properties readProperties() throws IOException {
assertStartArray();
final Map<String, Object> entries = new TreeMap<>();
while(!JsonToken.END_ARRAY.equals(jsonParser.currentToken())) {
Requirements.requireEqual(jsonParser.currentToken(), JsonToken.START_OBJECT);
String name = null;
Object value = null;
while(!JsonToken.END_OBJECT.equals(jsonParser.currentToken())) {
final String fieldName = jsonParser.nextFieldName();
if("name".equals(fieldName)) {
name = jsonParser.nextTextValue();
} else if("value".equals(fieldName)) {
final JsonToken token = jsonParser.nextValue();
if(token == JsonToken.VALUE_NUMBER_FLOAT) {
value = jsonParser.getDoubleValue();
} else if(token == JsonToken.VALUE_STRING) {
value = jsonParser.getValueAsString();
} else if(token == JsonToken.VALUE_FALSE) {
value = false;
} else if(token == JsonToken.VALUE_TRUE) {
value = true;
} else if(token == JsonToken.VALUE_NUMBER_INT) {
value = jsonParser.getValueAsInt();
} else {
throw new RuntimeException("Unsupported token type " + token);
}
}
}
assertEndObject();
entries.put(name, value);
}
assertEndArray();
try {
final PropertiesSpecification spec =
PropertiesSpecification.builder()
.add(entries.keySet()
.stream()
.filter(properties::contains)
.map(specification::find)
.map(PropertySpecification::type)
)
.build();
return new Properties(spec).putAll(entries);
} catch(final NullPointerException e) {
log.error("Failed to read properties file entry {} for specification {}.", entries, specification);
entries.keySet()
.stream()
.filter(k -> !properties.contains(k))
.forEach(n -> System.err.println("There is no properties specification for " + n));
throw e;
}
}
private void assertEndArray() throws IOException {
Requirements.requireEqual(jsonParser.currentToken(), JsonToken.END_ARRAY);
jsonParser.nextToken();
}
private void assertEndObject() throws IOException {
Requirements.requireEqual(jsonParser.currentToken(), JsonToken.END_OBJECT);
jsonParser.nextToken();
}
private void assertStartArray() throws IOException {
Requirements.requireEqual(jsonParser.currentToken(), JsonToken.START_ARRAY);
jsonParser.nextToken();
}
private void assertStartObject() throws IOException {
Requirements.requireEqual(jsonParser.currentToken(), JsonToken.START_OBJECT);
jsonParser.nextToken();
}
@Override
public void close() throws Exception {
jsonParser.close();
}
@Override
public boolean hasNext() {
return !JsonToken.END_ARRAY.equals(jsonParser.currentToken());
}
@Override
@SneakyThrows(IOException.class)
public Properties next() {
return readProperties();
}
} }
package de.evoal.core.api.properties.io; package de.evoal.core.api.properties.io;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.evoal.core.api.properties.Properties; import de.evoal.core.api.properties.Properties;
import de.evoal.core.api.properties.PropertySpecification; import de.evoal.core.api.properties.PropertiesSpecification;
import lombok.SneakyThrows; import de.evoal.core.api.utils.EvoalIOException;
import lombok.NonNull;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class PropertiesWriter implements AutoCloseable { /**
private final FileOutputStream outputStream; * Base interface for properties writers. A properties writer's task is to serialize a sequence of properties.
private final JsonGenerator jsonGenerator; */
public interface PropertiesWriter extends AutoCloseable {
public PropertiesWriter(final File outputFile) throws IOException { /**
outputStream = new FileOutputStream(outputFile); * Writes a new properties instance to the repository.
*
final ObjectMapper mapper = new ObjectMapper(); * @param properties The properties to write.
jsonGenerator = mapper.createGenerator(outputStream); * @throws EvoalIOException An exception to signal some problem while serialising the data.
jsonGenerator.writeStartArray(); */
} public void add(final @NonNull Properties properties) throws EvoalIOException;
@SneakyThrows(IOException.class) /**
public void addProperties(final Properties properties) { * Inits the writer with the specification information.
jsonGenerator.writeStartArray(); *
for(final PropertySpecification spec : properties.getSpecification().getProperties()) { * @param specification The properties specification of the properties to write.
jsonGenerator.writeStartObject(); *
jsonGenerator.writeStringField("name", spec.name()); * @return The instance itself.
*/
final Object value = properties.get(spec); public PropertiesWriter init(final File outputFile, final PropertiesSpecification specification) throws EvoalIOException;
if(value instanceof Double || value instanceof Float) {
jsonGenerator.writeNumberField("value", ((Number)properties.get(spec)).doubleValue());
} else if(value instanceof Integer) {
jsonGenerator.writeNumberField("value", ((Number)properties.get(spec)).longValue());
} else if(value instanceof Boolean) {
jsonGenerator.writeBooleanField("value", (Boolean)properties.get(spec));
} else if(value instanceof String) {
jsonGenerator.writeStringField("value", (String)properties.get(spec));
}
jsonGenerator.writeEndObject();
}
jsonGenerator.writeEndArray();
}
@Override
public void close() throws Exception {
jsonGenerator.writeEndArray();
jsonGenerator.close();
outputStream.close();
}
} }
package de.evoal.core.api.properties.stream; package de.evoal.core.api.properties.stream;
import de.evoal.core.api.properties.PropertiesSpecification; import de.evoal.core.api.properties.PropertiesSpecification;
import de.evoal.core.api.properties.io.PropertiesIOFactory;
import de.evoal.core.api.properties.io.PropertiesReader; import de.evoal.core.api.properties.io.PropertiesReader;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
...@@ -22,7 +23,7 @@ public class FileBasedPropertiesStreamSupplier extends PropertiesBasedProperties ...@@ -22,7 +23,7 @@ public class FileBasedPropertiesStreamSupplier extends PropertiesBasedProperties
super(Collections.emptyList()); super(Collections.emptyList());
log.info("Creating properties stream for {}.", filename); log.info("Creating properties stream for {}.", filename);
try(final PropertiesReader reader = new PropertiesReader(filename, specification)) { try(final PropertiesReader reader = PropertiesIOFactory.reader(filename, specification)) {
while(reader.hasNext()) { while(reader.hasNext()) {
properties.add(reader.next()); properties.add(reader.next());
} }
......
package de.evoal.core.api.utils;
public class EvoalIOException extends EvoalException {
public EvoalIOException(final String message) {
super(message);
}
public EvoalIOException(final String message, final Throwable cause) {
super(message, cause);
}
}
...@@ -95,4 +95,5 @@ module de.evoal.core { ...@@ -95,4 +95,5 @@ module de.evoal.core {
opens de.evoal.core.api.ea.constraints.calculation to weld.core.impl; opens de.evoal.core.api.ea.constraints.calculation to weld.core.impl;
opens de.evoal.core.api.properties.info to weld.core.impl; opens de.evoal.core.api.properties.info to weld.core.impl;
opens de.evoal.core.api.ea.constraints.strategies to weld.core.impl; opens de.evoal.core.api.ea.constraints.strategies to weld.core.impl;
opens de.evoal.core.main.properties to weld.core.impl;
} }
...@@ -2,7 +2,9 @@ package de.evoal.generator.main.internal; ...@@ -2,7 +2,9 @@ package de.evoal.generator.main.internal;
import de.evoal.core.api.properties.Properties; import de.evoal.core.api.properties.Properties;
import de.evoal.core.api.properties.PropertiesSpecification; import de.evoal.core.api.properties.PropertiesSpecification;
import de.evoal.core.api.properties.io.PropertiesIOFactory;
import de.evoal.core.api.properties.io.PropertiesWriter; import de.evoal.core.api.properties.io.PropertiesWriter;
import de.evoal.core.api.utils.EvoalIOException;
import de.evoal.generator.api.GeneratorFunction; import de.evoal.generator.api.GeneratorFunction;
import de.evoal.languages.model.generator.*; import de.evoal.languages.model.generator.*;
import de.evoal.languages.model.generator.util.GeneratorSwitch; import de.evoal.languages.model.generator.util.GeneratorSwitch;
...@@ -156,9 +158,18 @@ public class StatementExecutor extends GeneratorSwitch<Object> { ...@@ -156,9 +158,18 @@ public class StatementExecutor extends GeneratorSwitch<Object> {
new File(filename).getParentFile().mkdirs(); new File(filename).getParentFile().mkdirs();
try(final PropertiesWriter writer = new PropertiesWriter(new File(filename))) { PropertiesSpecification.Builder resultSpec = PropertiesSpecification.builder();
stream.peek(p -> resultSpec.add(p.getSpecification()));
try(final PropertiesWriter writer = PropertiesIOFactory.writer(new File(filename), resultSpec.build())) {
stream.limit(count) stream.limit(count)
.forEach(writer::addProperties); .forEach(p -> {
try {
writer.add(p);
} catch (final EvoalIOException e) {
log.error("Failed to writer properties.", e);
}
});
} catch (final Exception e) { } catch (final Exception e) {
log.error("Failed to write properties to file '{}'.", filename); log.error("Failed to write properties to file '{}'.", filename);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment