/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.annotation;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.xwiki.annotation.maintainer.AnnotationState;
/**
* Factory to create test documents from corpus files.
*
* @version $Id: f329818ab8fd66fb52e66d61d0acd250d2e0810a $
* @since 2.3M1
*/
public class TestDocumentFactory
{
/**
* Loaded documents map.
*/
protected Map<String, MockDocument> docs = new HashMap<String, MockDocument>();
/**
* Default constructor.
*/
public TestDocumentFactory()
{
}
/**
* @param docName name of test document to get, as loaded from the corpus file with the same name. Note that a
* document will be loaded and cached until the {@link #reset()} method is called.
* @return the test document loaded from the corpus file
* @throws IOException if something goes wrong parsing the document file
*/
public MockDocument getDocument(String docName) throws IOException
{
MockDocument loadedDoc = docs.get(docName);
if (loadedDoc == null) {
loadedDoc = new MockDocument();
loadDocument(loadedDoc, docName);
docs.put(docName, loadedDoc);
}
return loadedDoc;
}
/**
* Helper method to load a document from the corpus file with the same name.
*
* @param doc the document to load the file in
* @param docName the name of the document to load from the corpus file
* @throws IOException if something goes wrong parsing the file
*/
protected void loadDocument(MockDocument doc, String docName) throws IOException
{
// FIXME: this is pretty dirty, but it should work
doc.set("annotations", new ArrayList<Annotation>());
// get the file
BufferedReader reader =
new BufferedReader(new InputStreamReader(TestDocumentFactory.class.getResourceAsStream("/" + docName)));
// read line by line and
String line = null;
String currentKey = null;
StringBuffer currentValue = new StringBuffer();
while ((line = reader.readLine()) != null) {
if (line.startsWith("#")) {
// comment, ignore
continue;
}
if (line.startsWith(".")) {
// it's a key, parse its value
// if there exists a previous key, put its value in the document
if (currentKey != null) {
saveKeyToDoc(currentKey, currentValue.toString(), doc, docName);
currentValue.delete(0, currentValue.length());
}
currentKey = line.substring(1);
} else {
if (currentValue.length() > 0) {
currentValue.append("\n");
}
currentValue.append(line);
}
}
// process last key + value as well
saveKeyToDoc(currentKey, currentValue.toString(), doc, docName);
}
/**
* Helper function to save a parsed key in the configuration file to the mock document.
*
* @param currentKey the read key
* @param currentValue the value for the read key
* @param doc the mock document read from corpus
* @param docName the name of the document where the annotation is contained
* @throws IOException if there is any problem reading the annotation representation
*/
protected void saveKeyToDoc(String currentKey, String currentValue, MockDocument doc, String docName)
throws IOException
{
if (currentKey.equals("annotation")) {
// parse the annotation value
Annotation ann = parseAnnotation(currentValue, docName);
doc.getAnnotations().add(ann);
} else if (currentKey.indexOf(':') > 0) {
// the key contains a key and a syntax, parse the syntax and set it
int separatorIndex = currentKey.indexOf(':');
String key = currentKey.substring(0, separatorIndex);
String syntax = currentKey.substring(separatorIndex + 1);
doc.set(key, currentValue);
doc.set(key + "Syntax", syntax);
} else {
doc.set(currentKey, currentValue.toString());
}
}
/**
* Parses an annotation from its string representation, as read from the corpus file.
*
* @param annotation the string representation of the annotation, as in the corpus file
* @param docName the name of the document where the annotation is created
* @return an {@link Annotation} object corresponding to the data in the {@code annotation} string
* @throws IOException if there is any problem reading the annotation representation
*/
protected Annotation parseAnnotation(String annotation, String docName) throws IOException
{
BufferedReader stringReader = new BufferedReader(new StringReader(annotation));
// FIXME: pretty dirty to parse by lines
String line = null;
String[] properties = new String[7];
int propIndex = 0;
while ((line = stringReader.readLine()) != null) {
properties[propIndex] = line;
propIndex++;
}
AnnotationState state = AnnotationState.SAFE;
try {
state = AnnotationState.valueOf(properties[6] != null ? properties[6] : "");
} catch (IllegalArgumentException e) {
// nothing, leave it to SAFE
}
Annotation ann = new Annotation(properties[0]);
// allow left context and right context properties to miss
String leftContext = properties[4] == null ? "" : properties[4];
String rightContext = properties[5] == null ? "" : properties[5];
ann.setSelection(properties[3], leftContext, rightContext);
ann.setAuthor(properties[1]);
ann.setState(state);
ann.set("annotation", properties[2]);
return ann;
}
}