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

Last change on this file since 6935 was 6935, checked in by Oliver Schonefeld, 8 years ago
  • update/add copyright
  • fix typo in class name
  • minor changes
  • Property svn:eol-style set to native
File size: 9.8 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     * @param highlight
145     *            the span's alternate value or <code>null</code> if none
146     * @param highlight
147     *            the highlight group
148     * @throws IllegalArgumentException
149     *             if any argument is invalid
150     */
151    public void addSpan(URI layerId, long start, long end, String value,
152            String altValue, int highlight) {
153        if (layerId == null) {
154            throw new NullPointerException("layerId == null");
155        }
156        if (start < 0) {
157            throw new IllegalArgumentException("start < 0");
158        }
159        if (end < start) {
160            throw new IllegalArgumentException("end < start");
161        }
162        if (highlight <= 0) {
163            highlight = NO_HIGHLIGHT;
164        }
165
166        // find segment or create a new one
167        Segment segment = null;
168        for (Segment seg : segments) {
169            if ((seg.start == start) && (seg.end == end)) {
170                segment = seg;
171                break;
172            }
173        }
174        if (segment == null) {
175            segment = new Segment(nextSegmentId++, start, end);
176            segments.add(segment);
177        }
178
179        // find layer or create a new one
180        List<Span> layer = layers.get(layerId);
181        if (layer == null) {
182            layer = new ArrayList<Span>();
183            layers.put(layerId, layer);
184        }
185
186        // sanity check (better overlap check?)
187        for (Span span : layer) {
188            if (segment.equals(span.segment)) {
189                // FIXME: better exception!
190                throw new IllegalArgumentException(
191                        "segment already exists in layer");
192            }
193        }
194        layer.add(new Span(segment, value, altValue, highlight));
195    }
196
197
198    /**
199     * Write the Advanced data view to the output stream.
200     *
201     * @param writer
202     *            the writer to write to
203     * @throws XMLStreamException
204     *             if an error occurs
205     */
206    public void writeAdvancedDataView(XMLStreamWriter writer)
207            throws XMLStreamException {
208        if (writer == null) {
209            throw new NullPointerException("writer == null");
210        }
211
212        XMLStreamWriterHelper.writeStartDataView(writer, ADV_MIME_TYPE);
213        writer.setPrefix(ADV_PREFIX, ADV_NS);
214        writer.writeStartElement(ADV_NS, "Advanced");
215        writer.writeNamespace(ADV_PREFIX, ADV_NS);
216        if (unit == Unit.ITEM) {
217            writer.writeAttribute("unit", "item");
218        } else if (unit == Unit.TIMESTAMP) {
219            writer.writeAttribute("unit", "timestamp");
220        }
221
222        // segments
223        writer.writeStartElement(ADV_NS, "Segments");
224        for (Segment segment : segments) {
225            // FIXME: unit translation (long -> time)
226            writer.writeEmptyElement(ADV_NS, "Segment");
227            writer.writeAttribute("id", segment.id);
228            writer.writeAttribute("start", Long.toString(segment.start));
229            writer.writeAttribute("end", Long.toString(segment.end));
230            if (segment.ref != null) {
231                writer.writeAttribute("ref", segment.ref.toString());
232            }
233        }
234        writer.writeEndElement(); // "Segments" element
235
236        // layers
237        writer.writeStartElement(ADV_NS, "Layers");
238        for (Map.Entry<URI, List<Span>> layer : layers.entrySet()) {
239            writer.writeStartElement(ADV_NS, "Layer");
240            writer.writeAttribute("id", layer.getKey().toString());
241            for (Span span : layer.getValue()) {
242                if ((span.value != null) && !span.value.isEmpty()) {
243                    writer.writeStartElement(ADV_NS, "Span");
244                    writer.writeAttribute("ref", span.segment.id);
245                    if (span.highlight != null) {
246                        writer.writeAttribute("highlight", span.highlight);
247                    }
248                    if (span.altValue != null) {
249                        writer.writeAttribute("alt-value", span.altValue);
250                    }
251                    writer.writeCharacters(span.value);
252                    writer.writeEndElement(); // "Span" element
253                } else {
254                    writer.writeEmptyElement(ADV_NS, "Span");
255                    writer.writeAttribute("ref", span.segment.id);
256                    if (span.highlight != null) {
257                        writer.writeAttribute("highlight", span.highlight);
258                    }
259                    if (span.altValue != null) {
260                        writer.writeAttribute("alt-value", span.altValue);
261                    }
262                }
263            }
264            writer.writeEndElement(); // "Layer" element
265        }
266        writer.writeEndElement(); // "Layers" element
267
268        writer.writeEndElement(); // "Advanced" element
269        XMLStreamWriterHelper.writeEndDataView(writer);
270    }
271
272    private static final class Segment {
273        private final String id;
274        private final long start;
275        private final long end;
276        private final URI ref;
277
278
279        private Segment(long id, long start, long end) {
280            this.id = "s" + Long.toHexString(id);
281            this.start = start;
282            this.end = end;
283            this.ref = null;
284        }
285    }
286
287    private static final class Span {
288        private final Segment segment;
289        private final String value;
290        private final String altValue;
291        private final String highlight;
292
293
294        private Span(Segment segment, String value, String altValue,
295                int highlight) {
296            this.segment = segment;
297            this.value = value;
298            this.altValue = altValue;
299            if (highlight != NO_HIGHLIGHT) {
300                this.highlight = "h" + Integer.toHexString(highlight);
301            } else {
302                this.highlight = null;
303            }
304        }
305    }
306
307} // class AdvancedDataViewHelper
Note: See TracBrowser for help on using the repository browser.