source: FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/AdvancedDataViewWriter.java @ 6937

Last change on this file since 6937 was 6937, checked in by Oliver Schonefeld, 8 years ago
  • Property svn:eol-style set to native
File size: 9.9 KB
Line 
1/**
2 * This software is copyright (c) 2013-2016 by
3 *  - Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
4 * This is free software. You can redistribute it
5 * and/or modify it under the terms described in
6 * the GNU General Public License v3 of which you
7 * should have received a copy. Otherwise you can download
8 * it from
9 *
10 *   http://www.gnu.org/licenses/gpl-3.0.txt
11 *
12 * @copyright Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
13 *
14 * @license http://www.gnu.org/licenses/gpl-3.0.txt
15 *  GNU General Public License v3
16 */
17package eu.clarin.sru.server.fcs;
18
19import java.net.URI;
20import java.util.ArrayList;
21import java.util.HashMap;
22import java.util.List;
23import java.util.Map;
24
25import javax.xml.stream.XMLStreamException;
26import javax.xml.stream.XMLStreamWriter;
27
28
29/**
30 * Helper class for serializing Advanced data views. It can be used for writing
31 * more than one, but it is <em>not thread-save</em>.
32 */
33public class AdvancedDataViewWriter {
34    public enum Unit {
35        ITEM, TIMESTAMP
36    }
37    private static final long INITIAL_SEGMENT_ID = 1;
38    public static final int NO_HIGHLIGHT = -1;
39    private static final String ADV_PREFIX = "adv";
40    private static final String ADV_NS = "http://clarin.eu/fcs/dataview/advanced";
41    private static final String ADV_MIME_TYPE = "application/x-clarin-fcs-adv+xml";
42    private final Unit unit;
43    private final List<Segment> segments = new ArrayList<Segment>();
44    private final Map<URI, List<Span>> layers = new HashMap<URI, List<Span>>();
45    private long nextSegmentId = INITIAL_SEGMENT_ID;
46
47
48    /**
49     * Constructor.
50     *
51     * @param unit
52     *            the unit to be used for span offsets
53     * @see Unit
54     */
55    public AdvancedDataViewWriter(Unit unit) {
56        if (unit == null) {
57            throw new NullPointerException("unit == null");
58        }
59        this.unit = unit;
60    }
61
62
63    /**
64     * Reset the writer for writing a new data view (instance).
65     */
66    public void reset() {
67        nextSegmentId = INITIAL_SEGMENT_ID;
68    }
69
70
71    /**
72     * Add a span.
73     *
74     * @param layerId
75     *            the span's layer id
76     * @param start
77     *            the span's start offset
78     * @param end
79     *            the span's end offset
80     * @param value
81     *            the span's content value or <code>null</code> if none
82     * @throws IllegalArgumentException
83     *             if any argument is invalid
84     */
85    public void addSpan(URI layerId, long start, long end, String value) {
86        addSpan(layerId, start, end, value, null, NO_HIGHLIGHT);
87    }
88
89
90    /**
91     * Add a span.
92     *
93     * @param layerId
94     *            the span's layer id
95     * @param start
96     *            the span's start offset
97     * @param end
98     *            the span's end offset
99     * @param value
100     *            the span's content value or <code>null</code> if none
101     * @param highlight
102     *            the highlight group
103     * @throws IllegalArgumentException
104     *             if any argument is invalid
105     */
106    public void addSpan(URI layerId, long start, long end, String value,
107            int highlight) {
108        addSpan(layerId, start, end, value, null, highlight);
109    }
110
111
112    /**
113     * Add a span.
114     *
115     * @param layerId
116     *            the span's layer id
117     * @param start
118     *            the span's start offset
119     * @param end
120     *            the span's end offset
121     * @param value
122     *            the span's content value or <code>null</code> if none
123     * @param altValue
124     *            the span's alternate value or <code>null</code> if none
125     */
126    public void addSpan(URI layerId, long start, long end, String value,
127            String altValue) {
128        addSpan(layerId, start, end, value, altValue, NO_HIGHLIGHT);
129    }
130
131
132    /**
133     * Add a span.
134     *
135     * @param layerId
136     *            the span's layer id
137     * @param start
138     *            the span's start offset
139     * @param end
140     *            the span's end offset
141     * @param value
142     *            the span's content value or <code>null</code> if none
143     * @param altValue
144     *            the span's alternate value or <code>null</code> if none
145     * @param highlight
146     *            the span's alternate value or <code>null</code> if none
147     * @param highlight
148     *            the highlight group
149     * @throws IllegalArgumentException
150     *             if any argument is invalid
151     */
152    public void addSpan(URI layerId, long start, long end, String value,
153            String altValue, int highlight) {
154        if (layerId == null) {
155            throw new NullPointerException("layerId == null");
156        }
157        if (start < 0) {
158            throw new IllegalArgumentException("start < 0");
159        }
160        if (end < start) {
161            throw new IllegalArgumentException("end < start");
162        }
163        if (highlight <= 0) {
164            highlight = NO_HIGHLIGHT;
165        }
166
167        // find segment or create a new one
168        Segment segment = null;
169        for (Segment seg : segments) {
170            if ((seg.start == start) && (seg.end == end)) {
171                segment = seg;
172                break;
173            }
174        }
175        if (segment == null) {
176            segment = new Segment(nextSegmentId++, start, end);
177            segments.add(segment);
178        }
179
180        // find layer or create a new one
181        List<Span> layer = layers.get(layerId);
182        if (layer == null) {
183            layer = new ArrayList<Span>();
184            layers.put(layerId, layer);
185        }
186
187        // sanity check (better overlap check?)
188        for (Span span : layer) {
189            if (segment.equals(span.segment)) {
190                // FIXME: better exception!
191                throw new IllegalArgumentException(
192                        "segment already exists in layer");
193            }
194        }
195        layer.add(new Span(segment, value, altValue, highlight));
196    }
197
198
199    /**
200     * Write the Advanced data view to the output stream.
201     *
202     * @param writer
203     *            the writer to write to
204     * @throws XMLStreamException
205     *             if an error occurs
206     */
207    public void writeAdvancedDataView(XMLStreamWriter writer)
208            throws XMLStreamException {
209        if (writer == null) {
210            throw new NullPointerException("writer == null");
211        }
212
213        XMLStreamWriterHelper.writeStartDataView(writer, ADV_MIME_TYPE);
214        writer.setPrefix(ADV_PREFIX, ADV_NS);
215        writer.writeStartElement(ADV_NS, "Advanced");
216        writer.writeNamespace(ADV_PREFIX, ADV_NS);
217        if (unit == Unit.ITEM) {
218            writer.writeAttribute("unit", "item");
219        } else if (unit == Unit.TIMESTAMP) {
220            writer.writeAttribute("unit", "timestamp");
221        }
222
223        // segments
224        writer.writeStartElement(ADV_NS, "Segments");
225        for (Segment segment : segments) {
226            // FIXME: unit translation (long -> time)
227            writer.writeEmptyElement(ADV_NS, "Segment");
228            writer.writeAttribute("id", segment.id);
229            writer.writeAttribute("start", Long.toString(segment.start));
230            writer.writeAttribute("end", Long.toString(segment.end));
231            if (segment.ref != null) {
232                writer.writeAttribute("ref", segment.ref.toString());
233            }
234        }
235        writer.writeEndElement(); // "Segments" element
236
237        // layers
238        writer.writeStartElement(ADV_NS, "Layers");
239        for (Map.Entry<URI, List<Span>> layer : layers.entrySet()) {
240            writer.writeStartElement(ADV_NS, "Layer");
241            writer.writeAttribute("id", layer.getKey().toString());
242            for (Span span : layer.getValue()) {
243                if ((span.value != null) && !span.value.isEmpty()) {
244                    writer.writeStartElement(ADV_NS, "Span");
245                    writer.writeAttribute("ref", span.segment.id);
246                    if (span.highlight != null) {
247                        writer.writeAttribute("highlight", span.highlight);
248                    }
249                    if (span.altValue != null) {
250                        writer.writeAttribute("alt-value", span.altValue);
251                    }
252                    writer.writeCharacters(span.value);
253                    writer.writeEndElement(); // "Span" element
254                } else {
255                    writer.writeEmptyElement(ADV_NS, "Span");
256                    writer.writeAttribute("ref", span.segment.id);
257                    if (span.highlight != null) {
258                        writer.writeAttribute("highlight", span.highlight);
259                    }
260                    if (span.altValue != null) {
261                        writer.writeAttribute("alt-value", span.altValue);
262                    }
263                }
264            }
265            writer.writeEndElement(); // "Layer" element
266        }
267        writer.writeEndElement(); // "Layers" element
268
269        writer.writeEndElement(); // "Advanced" element
270        XMLStreamWriterHelper.writeEndDataView(writer);
271    }
272
273    private static final class Segment {
274        private final String id;
275        private final long start;
276        private final long end;
277        private final URI ref;
278
279
280        private Segment(long id, long start, long end) {
281            this.id = "s" + Long.toHexString(id);
282            this.start = start;
283            this.end = end;
284            this.ref = null;
285        }
286    }
287
288    private static final class Span {
289        private final Segment segment;
290        private final String value;
291        private final String altValue;
292        private final String highlight;
293
294
295        private Span(Segment segment, String value, String altValue,
296                int highlight) {
297            this.segment = segment;
298            this.value = value;
299            this.altValue = altValue;
300            if (highlight != NO_HIGHLIGHT) {
301                this.highlight = "h" + Integer.toHexString(highlight);
302            } else {
303                this.highlight = null;
304            }
305        }
306    }
307
308} // class AdvancedDataViewHelper
Note: See TracBrowser for help on using the repository browser.