source: trunk/src/org/expeditee/io/ExpReader.java@ 1321

Last change on this file since 1321 was 1321, checked in by bln4, 5 years ago

Added the ability to use strings as item tags in .exp files. In order to maintain back compatibility and to maximise efficiency, these strings must start with a underscore character.

File size: 12.3 KB
Line 
1/**
2 * ExpReader.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.io;
20
21import java.io.BufferedReader;
22import java.io.FileReader;
23import java.io.IOException;
24import java.lang.reflect.Method;
25import java.util.HashMap;
26import java.util.LinkedList;
27import java.util.List;
28
29import org.expeditee.core.Point;
30import org.expeditee.gui.Frame;
31import org.expeditee.gui.FrameIO;
32import org.expeditee.items.Constraint;
33import org.expeditee.items.Dot;
34import org.expeditee.items.Item;
35import org.expeditee.items.Line;
36import org.expeditee.items.Text;
37import org.expeditee.stats.SessionStats;
38
39/**
40 * Reads in Exp format files and constructs the Frame and Item objects they
41 * contain.
42 *
43 * @author mrww1
44 *
45 */
46public class ExpReader extends DefaultFrameReader {
47
48 public static final String EXTENTION = ".exp";
49
50 private BufferedReader _reader = null;
51
52 private String _frameName;
53
54 /**
55 * Does nothing, location must be set before use
56 */
57 public ExpReader(String frameName) {
58 super();
59
60 _frameName = frameName;
61 }
62
63 /**
64 * Determines whether a string begins with tag.
65 *
66 * @param s
67 * a line of text
68 * @return true if s begins with a tag
69 */
70 protected static boolean isValidLine(String s) {
71 // Previously lines in a .exp file had to start with a letter (A-Z, a-z). This allowed for an efficient check for valid lines.
72 // As we started to run out of spare letters to use for properties, we wished to use the full range of characters. But we did not
73 // wish to loose the efficiency of the Character.isLetter check. In order to maintain as much of this efficiency as possible, but
74 // allow for all characters, we take advantage of how || is evaluated:
75 // if the check for Character.isLetter passes, then the more complex map lookup operation does not take place.
76
77 if (s.length() < 2) {
78 return false;
79 }
80 char charZero = s.charAt(0);
81
82 if (charZero == '_') {
83 // If the character at the start is a underscore then we are dealing with the extended collection and must extract a string.
84 // This requires that the line contains a space character to split on and that the resulting split has at least two parts.
85 String[] parts = s.split(" ");
86 if (parts.length < 2) {
87 return false;
88 }
89 boolean isStringTag = _ItemTagsExt.keySet().contains(parts[0]);
90 if (isStringTag) {
91 return true;
92 }
93 } else {
94 // If we are looking at a letter then we can save ourselves from the less efficient general character check.
95 boolean isLetter = Character.isLetter(charZero);
96 if (isLetter) {
97 return true;
98 }
99
100 // If we are not looking at a letter but we are looking at a character that is not _ then it must be in the existing collection to be valid
101 boolean isCharacterTag = _ItemTags.keySet().contains(charZero);
102 if (isCharacterTag) {
103 return true;
104 }
105 }
106
107 // If we have somehow found a entry which does not pass any of the above tests then the line is invalid.
108 return false;
109 }
110
111 /**
112 * Reads a file with the given name from disk.
113 *
114 * @param frameName
115 * the name of the Frame to read in from a file.
116 * @return A new Frame object that contains any Items described in the file.
117 * @throws IOException
118 * Any exceptions occured by the BufferedReader.
119 */
120 @Override
121 public Frame readFrame(BufferedReader reader) throws IOException {
122 _reader = reader;
123 String next = "";
124 Frame newFrame = new Frame();
125
126 try {
127 // Framename must be set before setting the frame number
128 newFrame.setName(_frameName);
129
130 final List<DelayedAction> delayedActions = new LinkedList<DelayedAction>();
131
132 // First read all the header lines
133 while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {
134 if (isValidLine(next)) {
135 processHeaderLine(newFrame, next);
136 }
137 }
138
139 // Now read all the items
140 Item currentItem = null;
141 while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {
142 // if this is the start of a new item add a new item
143 if (isValidLine(next)) {
144 if (getTag(next) == 'S') {
145 String value = getValue(next);
146 int id = Integer.parseInt(value.substring(2));
147
148 switch (value.charAt(0)) {
149 case 'P': // check if its a point
150 currentItem = new Dot(id);
151 break;
152 default:
153 currentItem = new Text(id);
154 break;
155 }
156 _linePoints.put(currentItem.getID(), currentItem);
157 newFrame.addItem(currentItem);
158 } else if (currentItem != null && actionShouldBeDelayed(getTag(next))) {
159 delayedActions.add(new DelayedAction(currentItem, next));
160 } else if (currentItem != null) {
161 processBodyLine(currentItem, next);
162// final boolean hasSpecifiedPermission = currentItem.getPermission() != null;
163// final boolean hasSpecifiedOwner = currentItem.getOwner() != null;
164// if (hasSpecifiedPermission && hasSpecifiedOwner && currentItem.getPermission().getPermission(currentItem.getOwner()) == UserAppliedPermission.denied) {
165// newFrame.removeItem(currentItem);
166// newFrame.addItemHidden(currentItem);
167// continue;
168// }
169 } else {
170 System.err.println("Error while reading in frame (ExpReader): Found body line but no current item to apply it to.");
171 }
172 }
173 }
174
175 // Read the lines
176 while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {
177 if (isValidLine(next)) {
178 Point idtype = separateValues(next.substring(2));
179 // The next line must be the endpoints
180 if (!_reader.ready()) {
181 throw new Exception("Unexpected end of file");
182 }
183 next = _reader.readLine();
184 Point startend = separateValues(next.substring(2));
185 int start = startend.getX();
186 int end = startend.getY();
187
188 if (_linePoints.get(start) != null
189 && _linePoints.get(end) != null) {
190 newFrame.addItem(new Line(_linePoints.get(start),
191 _linePoints.get(end), idtype.getX()));
192 } else {
193 System.out
194 .println("Error reading line with unknown end points");
195 }
196 }
197 }
198
199 // Read the constraints
200 while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {
201 if (isValidLine(next)) {
202 Point idtype = separateValues(next.substring(2));
203 // The next line must be the endpoints
204 if (!_reader.ready()) {
205 throw new Exception("Unexpected end of file");
206 }
207 next = _reader.readLine();
208 Point startend = separateValues(next.substring(2));
209
210 Item a = _linePoints.get(startend.getX());
211 Item b = _linePoints.get(startend.getY());
212
213 new Constraint(a, b, idtype.getX(), idtype.getY());
214 }
215 }
216
217 for(DelayedAction action: delayedActions) {
218 action.exec();
219 }
220
221 // Read the stats
222 while (_reader.ready() && ((next = _reader.readLine()) != null)) {
223 if (next.startsWith(SessionStats.ACTIVE_TIME_ATTRIBUTE)) {
224 try {
225 String value = next.substring(SessionStats.ACTIVE_TIME_ATTRIBUTE.length()).trim();
226 newFrame.setActiveTime(value);
227 } catch (Exception e) {
228 }
229
230 } else if (next.startsWith(SessionStats.DARK_TIME_ATTRIBUTE)) {
231 try {
232 String value = next.substring(SessionStats.DARK_TIME_ATTRIBUTE.length()).trim();
233 newFrame.setDarkTime(value);
234 } catch (Exception e) {
235 }
236
237 }
238 }
239
240 } catch (Exception e) {
241 e.printStackTrace();
242 System.out.println("Error reading frame file line: " + next + " "
243 + e.getMessage());
244 }
245
246 //newFrame.refreshItemPermissions();
247 _reader.close();
248 FrameIO.setSavedProperties(newFrame);
249 newFrame.setChanged(false);
250
251 return newFrame;
252 }
253
254 private class DelayedAction {
255 private Item theItem;
256 private String theLine;
257
258 DelayedAction(final Item theItem, final String theLine) {
259 this.theItem = theItem;
260 this.theLine = theLine;
261 }
262
263 void exec() {
264 processBodyLine(theItem, theLine);
265 }
266 }
267
268 // Stores points used when constructing lines
269 private HashMap<Integer, Item> _linePoints = new HashMap<Integer, Item>();
270
271 /**
272 * Processes the body section of the Exp file, which contains all Items
273 *
274 * @param frame
275 * The Frame to add any created Items to.
276 * @param line
277 * The line of text read in from the file to process.
278 */
279 protected void processBodyLine(Item item, String line) {
280 Method toRun = null;
281
282 // separate the tag from the value
283 String tag = getTag(line).toString();
284 String value = null;
285 if (tag.charAt(0) != '_') {
286 value = getValue(line);
287 toRun = _ItemTags.get(tag.charAt(0));
288 } else {
289 tag = getTagExt(line);
290 value = getValueExt(line);
291 toRun = _ItemTagsExt.get(tag);
292 }
293
294
295 if (toRun == null) {
296 System.out.println("Error accessing tag method: " + tag);
297 }
298
299 Object[] vals = Conversion.Convert(toRun, value);
300 try {
301 if (vals != null) {
302 toRun.invoke(item, vals);
303 }
304 } catch (Exception e) {
305 System.out.println("Error running tag method: " + tag);
306 e.printStackTrace();
307 }
308 }
309
310 protected static Character getTag(String line) {
311 assert (line.length() > 0);
312 return line.charAt(0);
313 }
314
315 protected static String getTagExt(String line) {
316 assert(line.length() >= 2 && line.contains(" "));
317 String[] parts = line.split(" ");
318 assert(parts.length >= 2);
319 return parts[0];
320 }
321
322 protected static String getValue(String line) {
323 if (line.length() > 2) {
324 return line.substring(2);
325 } else {
326 return "";
327 }
328 }
329
330 protected static String getValueExt(String line) {
331 assert(line.length() >= 2 && line.contains(" "));
332 return line.substring(line.indexOf(" ") + 1);
333 }
334
335 protected static boolean actionShouldBeDelayed(Character c) {
336 return _DelayedItemTags.contains(c);
337 }
338
339 /**
340 * Reads the header section of the file, which contains information about
341 * the Frame.
342 *
343 * @param frame
344 * The Frame to assign the read values to.
345 * @param line
346 * The line from the file to process.
347 * @return False if the end of the header has been reached, True otherwise.
348 */
349 private void processHeaderLine(Frame frame, String line) throws IOException {
350 // first separate the tag from the text
351 Character tag = getTag(line);
352 String value = getValue(line);
353 Method toRun = _FrameTags.get(tag);
354
355 if (toRun == null) {
356 if (tag != 'v') {
357 System.out.println("Tag '" + tag + "' in '" + line
358 + "' is not supported.");
359 }
360 return;
361 }
362
363 Object[] vals = Conversion.Convert(toRun, value);
364 try {
365 toRun.invoke(frame, vals);
366 } catch (Exception e) {
367 System.out.println("Error running method: "
368 + toRun.toGenericString());
369 e.printStackTrace();
370 }
371 }
372
373 // Returns a point from a String containing two ints separated by a space
374 protected Point separateValues(String line) {
375 int x = Integer.parseInt(line.substring(0, line.indexOf(" ")));
376 int y = Integer.parseInt(line.substring(line.indexOf(" ") + 1));
377
378 return new Point(x, y);
379 }
380
381 public static int getVersion(String fullpath) {
382 try {
383 BufferedReader reader = new BufferedReader(new FileReader(fullpath));
384 String next = "";
385 // First read the header lines until we get the version number
386 while (reader.ready() && !(next = reader.readLine()).equals("Z")) {
387 if (isValidLine(next)) {
388 Character tag = getTag(next);
389 String value = getValue(next);
390 if (tag.equals('V')) {
391 reader.close();
392 return Integer.parseInt(value);
393 }
394 }
395 }
396 reader.close();
397 } catch (Exception e) {
398 }
399 return -1;
400 }
401
402 public static String redirectTo(String fullPath) {
403 try {
404 BufferedReader reader = new BufferedReader(new FileReader(fullPath));
405 String next = "";
406 while (reader.ready() && !(next = reader.readLine()).equals("Z")) {
407 if (next.startsWith("REDIRECT:")) {
408 String redirectTo = next.replace("REDIRECT:", "");
409 reader.close();
410 return redirectTo;
411 }
412 }
413 reader.close();
414 } catch (Exception e) {
415 }
416 return null;
417 }
418}
Note: See TracBrowser for help on using the repository browser.