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

Last change on this file since 1499 was 1499, checked in by bnemhaus, 4 years ago
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.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 protected BufferedReader _reader = null;
51
52 protected 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 List<DelayedAction> delayedActions = new LinkedList<DelayedAction>();
131
132 // First read all the header lines
133 next = readTheHeader(newFrame);
134
135 // Now read all the items
136 next = readTheItems(newFrame, delayedActions);
137
138 // Read the lines
139 next = readTheLines(newFrame);
140
141 // Read the constraints
142 next = readTheConstraints();
143
144 for(DelayedAction action: delayedActions) {
145 action.exec();
146 }
147
148 // Read the stats
149 next = readTheStats(newFrame);
150
151 } catch (Exception e) {
152 e.printStackTrace();
153 System.out.println("Error reading frame file line: " + next + " "
154 + e.getMessage());
155 }
156
157 //newFrame.refreshItemPermissions();
158 _reader.close();
159 FrameIO.setSavedProperties(newFrame);
160 newFrame.setChanged(false);
161
162 return newFrame;
163 }
164
165 protected String readTheStats(Frame newFrame) throws IOException {
166 String next = null;
167 while (_reader.ready() && ((next = _reader.readLine()) != null)) {
168 if (next.startsWith(SessionStats.ACTIVE_TIME_ATTRIBUTE)) {
169 try {
170 String value = next.substring(SessionStats.ACTIVE_TIME_ATTRIBUTE.length()).trim();
171 newFrame.setActiveTime(value);
172 } catch (Exception e) {
173 }
174
175 } else if (next.startsWith(SessionStats.DARK_TIME_ATTRIBUTE)) {
176 try {
177 String value = next.substring(SessionStats.DARK_TIME_ATTRIBUTE.length()).trim();
178 newFrame.setDarkTime(value);
179 } catch (Exception e) {
180 }
181
182 }
183 }
184 return next;
185 }
186
187 protected String readTheConstraints() throws IOException, Exception {
188 String next = null;
189 while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {
190 if (isValidLine(next)) {
191 Point idtype = separateValues(next.substring(2));
192 // The next line must be the endpoints
193 if (!_reader.ready()) {
194 throw new Exception("Unexpected end of file");
195 }
196 next = _reader.readLine();
197 Point startend = separateValues(next.substring(2));
198
199 Item a = _linePoints.get(startend.getX());
200 Item b = _linePoints.get(startend.getY());
201
202 new Constraint(a, b, idtype.getX(), idtype.getY());
203 }
204 }
205 return next;
206 }
207
208 protected String readTheLines(Frame newFrame) throws IOException, Exception {
209 String next = null;
210 while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {
211 if (isValidLine(next)) {
212 Point idtype = separateValues(next.substring(2));
213 // The next line must be the endpoints
214 if (!_reader.ready()) {
215 throw new Exception("Unexpected end of file");
216 }
217 next = _reader.readLine();
218 Point startend = separateValues(next.substring(2));
219 int start = startend.getX();
220 int end = startend.getY();
221
222 if (_linePoints.get(start) != null
223 && _linePoints.get(end) != null) {
224 newFrame.addItem(new Line(_linePoints.get(start),
225 _linePoints.get(end), idtype.getX()));
226 } else {
227 System.out
228 .println("Error reading line with unknown end points");
229 }
230 }
231 }
232 return next;
233 }
234
235 protected String readTheItems(Frame newFrame, final List<DelayedAction> delayedActions) throws IOException {
236 String next = null;
237 Item currentItem = null;
238 while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {
239 // if this is the start of a new item add a new item
240 if (isValidLine(next)) {
241 if (getTag(next) == 'S') {
242 currentItem = newItem(next);
243 _linePoints.put(currentItem.getID(), currentItem);
244 newFrame.addItem(currentItem);
245 } else if (currentItem != null && actionShouldBeDelayed(getTag(next))) {
246 delayedActions.add(new DelayedAction(currentItem, next));
247 } else if (currentItem != null) {
248 processBodyLine(currentItem, next);
249 } else {
250 System.err.println("Error while reading in frame (ExpReader): Found body line but no current item to apply it to.");
251 }
252 }
253 }
254 return next;
255 }
256
257 protected Item newItem(String line) {
258 Item currentItem;
259 String value = getValue(line);
260 int id = Integer.parseInt(value.substring(2));
261
262 switch (value.charAt(0)) {
263 case 'P': // check if its a point
264 currentItem = new Dot(id);
265 break;
266 default:
267 currentItem = new Text(id);
268 break;
269 }
270 return currentItem;
271 }
272
273 protected String readTheHeader(Frame newFrame) throws IOException {
274 String next = null;
275 while (_reader.ready() && !(next = _reader.readLine()).equals("Z")) {
276 if (isValidLine(next)) {
277 processHeaderLine(newFrame, next);
278 }
279 }
280 return next;
281 }
282
283 public class DelayedAction {
284 private Item theItem;
285 private String theLine;
286
287 public DelayedAction(final Item theItem, final String theLine) {
288 this.theItem = theItem;
289 this.theLine = theLine;
290 }
291
292 public void exec() {
293 processBodyLine(theItem, theLine);
294 }
295 }
296
297 // Stores points used when constructing lines
298 protected HashMap<Integer, Item> _linePoints = new HashMap<Integer, Item>();
299
300 /**
301 * Processes the body section of the Exp file, which contains all Items
302 *
303 * @param frame
304 * The Frame to add any created Items to.
305 * @param line
306 * The line of text read in from the file to process.
307 */
308 protected void processBodyLine(Item item, String line) {
309 Method toRun = null;
310
311 // separate the tag from the value
312 String tag = getTag(line).toString();
313 String value = null;
314 if (tag.charAt(0) != '_') {
315 value = getValue(line);
316 toRun = _ItemTags.get(tag.charAt(0));
317 } else {
318 tag = getTagExt(line);
319 value = getValueExt(line);
320 toRun = _ItemTagsExt.get(tag);
321 }
322
323
324 if (toRun == null) {
325 System.out.println("Error accessing tag method: " + tag);
326 }
327
328 Object[] vals = Conversion.Convert(toRun, value);
329 try {
330 if (vals != null) {
331 toRun.invoke(item, vals);
332 }
333 } catch (Exception e) {
334 System.out.println("Error running tag method: " + tag);
335 e.printStackTrace();
336 }
337 }
338
339 protected static Character getTag(String line) {
340 assert (line.length() > 0);
341 return line.charAt(0);
342 }
343
344 protected static String getTagExt(String line) {
345 assert(line.length() >= 2 && line.contains(" "));
346 String[] parts = line.split(" ");
347 assert(parts.length >= 2);
348 return parts[0];
349 }
350
351 protected static String getValue(String line) {
352 if (line.length() > 2) {
353 return line.substring(2);
354 } else {
355 return "";
356 }
357 }
358
359 protected static String getValueExt(String line) {
360 assert(line.length() >= 2 && line.contains(" "));
361 return line.substring(line.indexOf(" ") + 1);
362 }
363
364 protected static boolean actionShouldBeDelayed(Character c) {
365 return _DelayedItemTags.contains(c);
366 }
367
368 /**
369 * Reads the header section of the file, which contains information about
370 * the Frame.
371 *
372 * @param frame
373 * The Frame to assign the read values to.
374 * @param line
375 * The line from the file to process.
376 * @return False if the end of the header has been reached, True otherwise.
377 */
378 private void processHeaderLine(Frame frame, String line) throws IOException {
379 // first separate the tag from the text
380 Character tag = getTag(line);
381 String value = getValue(line);
382 Method toRun = _FrameTags.get(tag);
383
384 if (toRun == null) {
385 if (tag != 'v') {
386 System.out.println("Tag '" + tag + "' in '" + line
387 + "' is not supported.");
388 }
389 return;
390 }
391
392 Object[] vals = Conversion.Convert(toRun, value);
393 try {
394 toRun.invoke(frame, vals);
395 } catch (Exception e) {
396 System.out.println("Error running method: "
397 + toRun.toGenericString());
398 e.printStackTrace();
399 }
400 }
401
402 // Returns a point from a String containing two ints separated by a space
403 protected Point separateValues(String line) {
404 int x = Integer.parseInt(line.substring(0, line.indexOf(" ")));
405 int y = Integer.parseInt(line.substring(line.indexOf(" ") + 1));
406
407 return new Point(x, y);
408 }
409
410 public static int getVersion(String fullpath) {
411 if (fullpath == null) return -1;
412 try {
413 BufferedReader reader = new BufferedReader(new FileReader(fullpath));
414 String next = "";
415 // First read the header lines until we get the version number
416 while (reader.ready() && !(next = reader.readLine()).equals("Z")) {
417 if (isValidLine(next)) {
418 Character tag = getTag(next);
419 String value = getValue(next);
420 if (tag.equals('V')) {
421 reader.close();
422 return Integer.parseInt(value);
423 }
424 }
425 }
426 reader.close();
427 } catch (Exception e) {
428 //e.printStackTrace();
429 // When this exception goes off, it is because it is trying to check if a frame that has yet to be saved
430 // to the filesystem has a version number greater than in memory one. This only happens for new frames,
431 // so is not a problem.
432 }
433 return -1;
434 }
435
436 public static String redirectTo(String fullPath) {
437 if (fullPath == null) return null;
438 try {
439 BufferedReader reader = new BufferedReader(new FileReader(fullPath));
440 String next = "";
441 while (reader.ready() && !(next = reader.readLine()).equals("Z")) {
442 if (next.startsWith("REDIRECT:")) {
443 String redirectTo = next.replace("REDIRECT:", "");
444 reader.close();
445 return redirectTo;
446 }
447 }
448 reader.close();
449 } catch (IOException e) {
450 //e.printStackTrace();
451 // When this exception goes off, it is because it is trying to check if a frame that has yet to be saved
452 // to the filesystem has a redirect. This comes out in teh wash later on when a redirect is next checked.
453 }
454 return null;
455 }
456}
Note: See TracBrowser for help on using the repository browser.