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

Last change on this file since 1498 was 1498, checked in by bnemhaus, 4 years ago

Refactored variable name for clarity.

Comments explaining why an exception is being suppressed.

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