ContextSerializerText.java
package org.thegalactic.context.io;
/*
* ContextSerializerText.java
*
* Copyright: 2010-2015 Karell Bertet, France
* Copyright: 2015-2016 The Galactic Organization, France
*
* License: http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html CeCILL-B license
*
* This file is part of java-lattices.
* You can redistribute it and/or modify it under the terms of the CeCILL-B license.
*/
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.thegalactic.context.Context;
import org.thegalactic.io.Reader;
import org.thegalactic.io.Writer;
/**
* This class defines the way for reading a context from a text file.
*
* ![ContextSerializerText](ContextSerializerText.png)
*
* @uml TextSerializer.png
* !include resources/org/thegalactic/context/io/TextSerializer.iuml
* !include resources/org/thegalactic/io/Reader.iuml
* !include resources/org/thegalactic/io/Writer.iuml
* hide members
* show TextSerializer members
* class TextSerializer #LightCyan
* title TextSerializer UML graph
*/
public final class ContextSerializerText implements Reader<Context>, Writer<Context> {
/**
* String extension.
*/
private static final String EXTENSION = "txt";
/**
* The singleton instance.
*/
private static final ContextSerializerText INSTANCE = new ContextSerializerText();
/**
* Return the singleton instance of this class.
*
* @return the singleton instance
*/
public static ContextSerializerText getInstance() {
return INSTANCE;
}
/**
* Register this class for reading and writing .txt files.
*/
public static void register() {
ContextIOFactory.getInstance().registerReader(ContextSerializerText.getInstance(), EXTENSION);
ContextIOFactory.getInstance().registerWriter(ContextSerializerText.getInstance(), EXTENSION);
}
/**
* This class is not designed to be publicly instantiated.
*/
private ContextSerializerText() {
super();
}
/**
* Read a context from a file.
*
* The following format is respected:
*
* The list of observations separated by a space on the first line ; the
* list of attrbutes separated by a space on the second line ; then, for
* each observations o, the list of its intent on a line, written like o a1
* a2 ...
*
* ~~~
* Observations: 1 2 3
* Attributes: a b c d e
* 1: a c
* 2: a b
* 3: b d e
* 4: c e
* ~~~
*
* @param context a context to read
* @param file a file
*
* @throws IOException When an IOException occurs
*/
public void read(final Context context, final BufferedReader file) throws IOException {
this.readObservations(context, file);
this.readAttributes(context, file);
this.readExtentIntent(context, file);
context.setBitSets();
}
/**
* Read observations from a file.
*
* The following format is respected:
*
* ~~~
* Observations: 1 2 3
* ~~~
*
* @param context a context to read
* @param file a file
*
* @throws IOException When an IOException occurs
*/
private void readObservations(final Context context, final BufferedReader file) throws IOException {
final List<String> list = this.analyzeString(file.readLine());
if ("Observations".equals(list.get(0))) {
for (int i = 1; i < list.size(); i++) {
if (!context.addToObservations(list.get(i))) {
throw new IOException("Duplicated observation");
}
}
} else {
throw new IOException("Invalid declaration of observations");
}
}
/**
* Read attributes from a file.
*
* The following format is respected:
*
* ~~~
* Attributes: a b c d e
* ~~~
*
* @param context a context to read
* @param file a file
*
* @throws IOException When an IOException occurs
*/
private void readAttributes(final Context context, final BufferedReader file) throws IOException {
final List<String> list = this.analyzeString(file.readLine());
if ("Attributes".equals(list.get(0))) {
for (int i = 1; i < list.size(); i++) {
if (!context.addToAttributes(list.get(i))) {
throw new IOException("Duplicated attribute");
}
}
} else {
throw new IOException("Invalid declaration of attributes");
}
}
/**
* Read extension and intension from a file.
*
* The following format is respected:
*
* ~~~
* 1: a c
* 2: a b
* 3: b d e
* 4: c e
* ~~~
*
* @param context a context to read
* @param file a file
*
* @throws IOException When an IOException occurs
*/
private void readExtentIntent(final Context context, final BufferedReader file) throws IOException {
String line;
List<String> list;
line = file.readLine();
while (line != null && !line.isEmpty()) {
list = this.analyzeString(line);
if (!context.containsObservation(list.get(0))) {
throw new IOException("Unexisting observation");
}
for (int i = 1; i < list.size(); i++) {
if (!context.containsAttribute(list.get(i))) {
throw new IOException("Unexisting attribute");
}
// Add the extent/intent for the current observation and current attribute
context.addExtentIntent(list.get(0), list.get(i));
}
line = file.readLine();
}
}
/**
* Analyze a string.
*
* @param string line to analyze
*
* @return a list of string
*/
private List<String> analyzeString(final String string) {
final Pattern definition = Pattern.compile("(?:(?:\"(?<quoted>(?:[^\"]|\\\")+)\")|(?<simple>[^ :\"]+)):(?<elements>.*)");
final Pattern elements = Pattern.compile("(?:\"(?<quoted>(?:[^\"]|\\\")+)\")|(?<simple>[^ :\"]+)");
final List<String> list = new ArrayList<String>();
Matcher matcher;
matcher = definition.matcher(string);
if (matcher.find()) {
// Get the first name (before the colon)
list.add(this.getElement(matcher));
matcher = elements.matcher(matcher.group("elements"));
while (matcher.find()) {
list.add(this.getElement(matcher));
}
}
return list;
}
/**
* Get the element using the matcher.
*
* @param matcher the matcher
*
* @return the string
*/
private String getElement(final Matcher matcher) {
String element;
if (matcher.group("quoted") == null) {
element = matcher.group("simple");
} else {
element = matcher.group("quoted").replace("\\\"", "\"").replace("\\n", "\n").replace("\\t", "\t");
}
return element;
}
/**
* Write a context to a file.
*
* The following format is respected:
*
* The list of observations separated by a space on the first line ; the
* list of attrbutes separated by a space on the second line ; then, for
* each observations o, the list of its intent on a line, written like o a1
* a2 ...
*
* ~~~
* Observations: 1 2 3
* Attributes: a b c d e
* 1: a c
* 2: a b
* 3: b d e
* 4: c e
* ~~~
*
* @param context a context to write
* @param file a file
*
* @throws IOException When an IOException occurs
*/
public void write(final Context context, final BufferedWriter file) throws IOException {
file.write(context.toString());
}
}