ContextSerializerSLF.java

package org.thegalactic.context.io;

/*
 * ContextSerializerSLF.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 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.SortedSet;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;

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 slf file.
 *
 */
public final class ContextSerializerSLF implements Reader<Context>, Writer<Context> {

    /**
     * String extension.
     */
    private static final String EXTENSION = "slf";

    /**
     * Header.
     */
    private static final String HEADER = "[Lattice]";

    /**
     * Objects.
     */
    private static final String OBJECTS = "[Objects]";

    /**
     * Attributes.
     */
    private static final String ATTRIBUTES = "[Attributes]";

    /**
     * relation.
     */
    private static final String RELATION = "[relation]";

    /**
     * Misformed exception.
     */
    private static final String MISFORMED = "Misformated SLF file.";

    /**
     * The singleton INSTANCE.
     */
    private static final ContextSerializerSLF INSTANCE = new ContextSerializerSLF();

    /**
     * Return the singleton INSTANCE of this class.
     *
     * @return the singleton INSTANCE
     */
    public static ContextSerializerSLF getINSTANCE() {
        return INSTANCE;
    }

    /**
     * Register this class for reading and writing .slf files.
     */
    public static void register() {
        ContextIOFactory.getInstance().registerReader(ContextSerializerSLF.getINSTANCE(), EXTENSION);
        ContextIOFactory.getInstance().registerWriter(ContextSerializerSLF.getINSTANCE(), EXTENSION);
    }

    /**
     * This class is not designed to be publicly instantiated.
     */
    private ContextSerializerSLF() {
    }

    /**
     * Read a context from a file.
     *
     * The following format is respected:
     *
     * The number of objects and observation on two separated lines The list of
     * objects on seprated lines The list of attributes on separated lines
     *
     * then, for each observations, the list of its intent on a line, written
     * like 0 1 0
     *
     * ~~~
     * [Lattice]
     * 2
     * 3
     * [Objects]
     * 1 2
     * [Attributes]
     * a b c
     * [relation]
     * 0 1 0
     * 1 1 0
     * ~~~
     *
     * @param context a context to read
     * @param file    a file
     *
     * @throws IOException When an IOException occurs
     *
     * @todo use StreamTokenizer
     */
    public void read(final Context context, final BufferedReader file) throws IOException {

        if (!file.readLine().equals(HEADER)) {
            throw new IOException(MISFORMED);
        }

        final int countObservations = Integer.parseInt(file.readLine());
        final int countAttributes = Integer.parseInt(file.readLine());

        if (!file.readLine().equals(OBJECTS)) {
            throw new IOException(MISFORMED);
        }

        final List<Comparable> observations = new ArrayList(countObservations);
        final List<Comparable> attributes = new ArrayList(countAttributes);
        final TreeMap<Comparable, TreeSet<Comparable>> intent = new TreeMap();
        final TreeMap<Comparable, TreeSet<Comparable>> extent = new TreeMap();

        String line = file.readLine();
        while (!ATTRIBUTES.equals(line)) {
            observations.add(line);
            intent.put(line, new TreeSet());
            line = file.readLine();
        }
        line = file.readLine();
        while (!RELATION.equals(line)) {
            attributes.add(line);
            extent.put(line, new TreeSet());
            line = file.readLine();
        }

        context.addAllToAttributes(new TreeSet(attributes));
        context.addAllToObservations(new TreeSet(observations));

        for (int i = 0; i < countObservations; i++) {
            line = file.readLine();
            final StringTokenizer tokenizer = new StringTokenizer(line);
            int count = 0;
            while (tokenizer.hasMoreTokens()) {
                final String next = tokenizer.nextToken();
                if ("1".equals(next)) {
                    context.addExtentIntent(observations.get(i), attributes.get(count));
                }
                count++;
            }
            if (count != countAttributes) {
                throw new IOException(MISFORMED);
            }
        }
        context.setBitSets();
    }

    /**
     * Write a context to a file.
     *
     * The Standard Lattice Format SLF format file is respected :
     *
     * The following format is respected:
     *
     * The number of objects and observation on two separated lines The list of
     * objects on seprated lines The list of attributes on separated lines
     *
     * then, for each observations, the list of its intent on a line, written
     * like 0 1 0
     *
     * ~~~
     * [Lattice]
     * 2
     * 3
     * [Objects]
     * 1
     * 2
     * [Attributes]
     * a
     * b
     * c
     * [relation]
     * 0 1 0
     * 1 1 0
     * ~~~
     *
     * @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(HEADER);
        file.newLine();
        file.write(String.valueOf(context.getObservations().size()));
        file.newLine();
        file.write(String.valueOf(context.getAttributes().size()));
        file.newLine();
        file.write(OBJECTS);
        file.newLine();
        for (final Comparable observation : context.getObservations()) {
            file.write(observation.toString());
            file.newLine();
        }
        file.write(ATTRIBUTES);
        file.newLine();
        for (final Comparable attribute : context.getAttributes()) {
            file.write(attribute.toString());
            file.newLine();
        }
        file.write(RELATION);
        file.newLine();
        for (final Comparable observation : context.getObservations()) {
            final SortedSet<Comparable> intent = context.getIntent(observation);
            for (final Comparable attribute : context.getAttributes()) {
                if (intent.contains(attribute)) {
                    file.write("1 ");
                } else {
                    file.write("0 ");
                }
            }
            file.newLine();
        }
    }
}