View Javadoc

1   package gov.nasa.pds.ltdt.gui;
2    
3   import gov.nasa.pds.ltdt.gui.configuration.LTDTKeys;
4   import gov.nasa.pds.ltdt.gui.util.DictionaryUtility;
5   import gov.nasa.pds.ltdt.gui.util.ProcessWaitGlassPane;
6   import gov.nasa.pds.ltdt.gui.util.Utility;
7   import gov.nasa.pds.tools.dict.Definition;
8   import gov.nasa.pds.tools.dict.parser.DictionaryParser;
9   import gov.nasa.pds.tools.label.parser.ParseException;
10  
11  import java.awt.Color;
12  import java.awt.Cursor;
13  import java.io.BufferedReader;
14  import java.io.FileNotFoundException;
15  import java.io.FileReader;
16  import java.io.IOException;
17  import java.io.InputStream;
18  import java.io.InputStreamReader;
19  import java.net.MalformedURLException;
20  import java.net.URL;
21  import java.net.URLConnection;
22  import java.util.ArrayList;
23  import java.util.Enumeration;
24  import java.util.HashMap;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Properties;
29  import java.util.Set;
30  
31  import javax.swing.BorderFactory;
32  import javax.swing.JOptionPane;
33  
34  /***
35   * Open a project. 
36   * 
37   * @author jwang
38   *
39   */
40  public class ProjectOpen {
41  	
42  	private static String logfile_name = null;
43  	
44  	/***
45  	 * Open a project.
46  	 * @param props         properties
47  	 * @param window        main window
48  	 * @param project_name  name of the project
49  	 * @param fromCommandline  a flag indicating whether this is a commandline or menu triggered open
50  	 *                      dictionaries entered at command line will be attached to the dictionary list for
51  	 *                      a project.
52  	 * @return              SUCCESS, PROJECTDIR_NOT_FOUND, FOUND_PROJECTDIR_NO_PROPERTY
53  	 */
54  
55  	public static int open
56  		(final Properties props, final MainWindow window, final String project_name, final boolean fromCommandline) {
57  
58  		//  read in configuration and examine if project directory is provided
59  		//  populate dictionary list including wdd if any
60  		//  if template exist, populate it and set templateexists=true
61  		//  pull out other information
62  		//  record to log file
63  		//  
64  			
65  
66  	
67  		
68  		Utility.initializeEmptyProject(props, window);
69  		
70  
71  		int pstatus = 0;
72  		pstatus = retrieveProjectProperties(props, window, project_name);
73  		if (pstatus!=LTDTKeys.SUCCESS) return pstatus;
74  		
75  		// handle loading project on a separate thread
76  		// and display a wait message
77  		final ProcessWaitGlassPane pw = new ProcessWaitGlassPane();
78  		window.setGlassPane(pw);
79  		pw.setBackground( new Color(255, 255, 255, 255) ); // white glass pane
80  		pw.setForeground( Color.LIGHT_GRAY); // message in dark gray
81  
82  		pw.activate("Opening project. Please wait ...");	
83  		Thread thread = new Thread() 
84  		{
85  			public void run() 
86  			{	
87  				// Gather all the dictionary specification from both existing property file
88  				// and command line. Store the result into props.dictionaries
89  				// All  condition is handled inside this method, and non of the issue cause project open
90  				// failure, so we don't check return status at this time. And status is kept as Success
91  				combineDictionaires(props,window, fromCommandline);
92  		
93  				// populate the keyword window
94  				populateProjectData (props, window);
95  				
96  				//reportOpenStatus(props, window);
97  		
98  				// Change the project altered status to false
99  				// Can't do this earlier because populating editing window set it to true
100 				// which is wrong.
101 				props.setProperty(LTDTKeys.PROJECTALTERED, "false");
102 				
103 				// If there was additional dictionaries combined at the project open time, likely because
104 				// of the command line interface, then the project should be marked as altered
105 				if ("true".equals(props.getProperty(LTDTKeys.COMMANDLINEDICTIONARYADDED))) {
106 					props.setProperty(LTDTKeys.PROJECTALTERED, "true");
107 				}
108 		
109 				// on the gui, set keyword listing 	
110 				DictionaryListPane.displaySingleTypeList(window, LTDTKeys.ELEMENTONLY);	
111 				
112 				window.dictDefPane.setBorder(BorderFactory.createTitledBorder(LTDTKeys.GENERICDEFINITIONTITLE));
113 				pw.deactivate();
114 			}
115 		};
116 		thread.start();
117 				
118 		return LTDTKeys.SUCCESS; // see note above about this status
119 		
120 
121 	}
122 	
123 
124 	/***
125 	 * Retrieve property information from the previous run of a project
126 	 * @param props
127 	 * @param window
128 	 * @param project_name
129 	 * @return SUCCESS, PROJECTDIR_NOT_FOUND, FOUND_PROJECTDIR_NO_PROPERTY
130 	 */
131 	private static int retrieveProjectProperties 
132 		(Properties props, MainWindow window, String project_name) {
133 
134 		
135 		BufferedReader reader= null;
136 		String projectDir=null;
137 		String invalidDict = "";
138 		List dictList=null;
139 		
140 		try {
141 				
142 	
143 			if (project_name != null) {
144 				projectDir = Utility.getProjectLocation(project_name);
145 			}
146 			else
147 				projectDir = props.getProperty(LTDTKeys.PROJECTDIR);
148 			
149 			reader = new BufferedReader(
150 						new FileReader(projectDir+System.getProperty("file.separator")+LTDTKeys.PROPERTYFILENAME));
151 			
152 			// update the properties with the project that's about to be opened
153 			for (String line=reader.readLine(); line!=null; line=reader.readLine()){
154 					// skip the comment lines and only retrive the the records with K=V pairs
155 					if (!line.trim().startsWith("#")) {
156 						String [] str = line.split("=");
157 						if (str.length==2 ) {
158 							if (str[0].trim().length()>0 && str[1].trim().length()>0) {
159 								props.setProperty(str[0].trim(), str[1].trim());
160 							}
161 						}
162 					}
163 					// skip the ones not in K=V format for now	
164 			}
165 			
166 			
167 			try {
168 				if (reader != null) 
169 				reader.close();	
170 			} catch (IOException ie2) { }
171 		}		
172 		catch (FileNotFoundException fe){
173 			return LTDTKeys.FOUND_PROJECTDIR_NO_PROPERTY;				
174 		}		
175 		catch (IOException ex){
176 			// TODO: got IO exception after confirming dir is valid and file exists
177 			//JOptionPane.showConfirmDialog (window, "Can not locate project path")	
178 			return LTDTKeys.PROJECTDIR_NOT_FOUND;
179 		}		
180 		finally {
181 			try {
182 				if (reader!=null) reader.close();					
183 			} catch (IOException ie){ }
184 		}
185 	
186 		return LTDTKeys.SUCCESS;
187 	
188 	}
189 	
190 	/***
191 	 * Gather dictionary specification for this project from existing project property. If this
192 	 * project is open at the tool start up time with other dictionary specifictions, also includ 
193 	 * those dictionaries 
194 	 * 
195 	 * Note: if dictionary names passed in from the command line are different dictionary
196 	 * names to the ones store in project property,  they are appended to the list of dictionaries 
197 	 * under this project.  
198 	 * ** At this point, only allow add, but no removal of dictionaries.
199 	 * @param props
200 	 * @param fromCommandline
201 	 * @return
202 	 */
203 	private static int  combineDictionaires (Properties props, MainWindow window, boolean fromCommandline) {
204 		
205 		List dictList=null;
206 		String new_dictionaries = "";
207 		String invalidDict = "";
208 		String filteredDList = "";
209 		
210 		if (fromCommandline == true) {
211 
212 			dictList =  DictionaryUtility.getDictionaryNameList(props.getProperty(LTDTKeys.DICTIONARIESFROMCOMMAND));
213 			
214 			List oldList=new ArrayList();	
215 			
216 			// dictionaries will be a concatenated list of old and new dictionaries
217 			// read the "old" list from previous run first
218 			String old_dictionaries = props.getProperty(LTDTKeys.DICTIONARIES);
219 			
220 			
221 			// if there was dictionaries defined from previous session
222 			if (old_dictionaries!=null) {
223 
224 				// examine old dictionaries definition, filter out "null", and convert them into an array, 
225 				String [] oldDictDef = DictionaryUtility.getDictionaryNameArray(old_dictionaries);
226 				
227 				//	If old dictionary list becomes empty after conversion, just add the ones from command line
228 				if (oldDictDef==null ) {
229 					for (int i=0; i<dictList.size(); i++) {
230 						if (!"null".equals(dictList.get(i))) {
231 							new_dictionaries = new_dictionaries+(String)dictList.get(i)+LTDTKeys.DICTIONARY_DELIMITER;
232 							props.setProperty(LTDTKeys.COMMANDLINEDICTIONARYADDED, "true");			
233 						}
234 					}
235 
236 				}	
237 				
238 				// if there's existing project dictionaries, and user specifies additional dictionary on command line, 
239 				// combine the ones that's not redundant into one definition entry.
240 				// Note: We don't remove dictionary at this point.
241 				else {	
242 					for (int i=0; i<oldDictDef.length;i++) {						
243 							oldList.add(oldDictDef[i]);
244 							new_dictionaries = new_dictionaries+oldDictDef[i]+LTDTKeys.DICTIONARY_DELIMITER;
245 					}
246 					
247 					// only combine the one that's not already in the old dictionary list
248 					for (int t=0; t<dictList.size(); t++) {
249 					
250 						if (!oldList.contains(dictList.get(t))) {
251 							new_dictionaries = new_dictionaries+(String)dictList.get(t)+LTDTKeys.DICTIONARY_DELIMITER;
252 							props.setProperty(LTDTKeys.COMMANDLINEDICTIONARYADDED, "true");
253 						}
254 					}
255 					
256 				}			
257 				
258 			}
259 			else {
260 				// No old dictionary info from project property, then add whatever entered by the user into it
261 				for (int i=0; i<dictList.size(); i++) {
262 						new_dictionaries = new_dictionaries + (String)dictList.get(i)+LTDTKeys.DICTIONARY_DELIMITER;
263 				}
264 				props.setProperty(LTDTKeys.COMMANDLINEDICTIONARYADDED, "true");
265 			}
266 
267 			
268 		} // if project open called at the tool starting time 
269 		
270 		// if project open was a result from menu selection, only the dictionary names from previous run is retrieved
271 		else {
272 			new_dictionaries = props.getProperty(LTDTKeys.DICTIONARIES);
273 		}
274 		
275 		
276 
277 	
278 		// finally, check if any of the dictionary path gathered at this point
279 		// is not valid (for example, invalid location). If any, inform the user to import it from the menu
280 		// Only the valid one will be opened
281 			
282 		String [] st = DictionaryUtility.getDictionaryNameArray (new_dictionaries);
283 
284 		URLConnection conn;
285 		URL url;
286 		
287 		
288 		 if (st!=null) {
289 			for (int k=0; k<st.length; k++) {
290 	
291   
292 				if ((st[k]!=null)) {
293 					try {
294 						url = Utility.toURL(st[k]);
295 						conn = url.openConnection(); 
296 						conn.connect();
297 			
298 						filteredDList = filteredDList+st[k]+LTDTKeys.DICTIONARY_DELIMITER;
299 			
300 					}
301 					catch (Exception e) {
302 						invalidDict = "  "+invalidDict+st[k]+"\n";
303 					}
304 							
305 				}
306 			}
307 
308 			if (filteredDList.length() > 0) {
309 				props.setProperty(LTDTKeys.DICTIONARIES, filteredDList);
310 			}
311 					
312 			if (invalidDict.length() >0) {
313 				JOptionPane.showMessageDialog(window, "The following dictionaries can not be located: \n\n"+invalidDict+
314 						"\nPlease import them using File->Import menu option", 
315 						"Data Dictionary Loading Waring", JOptionPane.WARNING_MESSAGE);
316 			}
317 			
318 
319 		}
320 
321 		return LTDTKeys.SUCCESS;
322 
323 	}
324 	
325 	/***
326 	 * Populate dictionary data into keyword tree.  Add in WDD data if any.
327 	 * @param props
328 	 * @param window
329 	 * @return
330 	 */
331 	private static int populateProjectData (Properties props, MainWindow window )  {
332 		
333 		BufferedReader reader= null;
334 		
335 		// update window title to include name of the project
336 		String projectName=props.getProperty(LTDTKeys.PROJECTNAME);
337 		
338 		window.setTitle("LTDTool (Project Name: "+projectName+")");
339 				
340 		// if there's a working template, read it in
341 		if ("true".equals(props.getProperty(LTDTKeys.TEMPLATEEXISTS))) {
342 			try {
343 				URL url2 = Utility.toURL(props.getProperty(LTDTKeys.PROJECTDIR)+System.getProperty("file.separator")+LTDTKeys.TEMPLATEFILENAME);
344 				InputStream in = url2.openStream();
345 				reader = new BufferedReader (new InputStreamReader(in));
346 				window.editorPane.jta.setText("");
347 				String line=null;
348 	
349 				while ((line=reader.readLine())!=null) {	
350 					window.editorPane.jta.append(line+System.getProperty("line.separator"));
351 				}
352 				in.close();
353 				reader.close();
354 				
355 				window.menu.purgeUndos(); // clear undo cache
356 				window.editorPane.jta.setCaretPosition(0);
357 				window.editorPane.jta.grabFocus();
358 			}
359 			catch (IOException e) {
360 				// display warning message so user know the condition
361 				// but continue the other loadings to make this project available 
362 				JOptionPane.showMessageDialog(
363 						window,
364 						"IOException while opening work  template for "+projectName,
365 						"Template Open Error", JOptionPane.WARNING_MESSAGE);
366 				
367 				window.editorPane.jta.setCaretPosition(0);
368 				window.editorPane.jta.grabFocus();
369 			}
370 			finally {
371 				try {
372 					if (reader!=null)  reader.close();
373 				}
374 				catch (IOException e) { }// do nothing 
375 			}
376 		}
377 		else {
378 			window.editorPane.jta.setCaretPosition(0);
379 			window.editorPane.jta.grabFocus();
380 		}
381 				
382 		// populate the dictionary list, if any, otherwise provide some hints
383 
384 		// read in WDD if available, Don't put it in the property DICTIONARIES value though,
385 		// it's for display only
386 		String displayDictionaries = props.getProperty(LTDTKeys.DICTIONARIES).trim();
387 		try {
388 			if ("true".equals(props.getProperty(LTDTKeys.WDDEXISTS))) {
389 	
390 				//dispalyDictionaries = dispalyDictionaries + props.getProperty(LTDTKeys.PROJECTDIR)+System.getProperty("file.separator")+LTDTKeys.WDDFILENAME+LTDTKeys.DICTIONARY_DELIMITER;
391 				displayDictionaries = displayDictionaries + LTDTKeys.DICTIONARY_DELIMITER + Utility.getProjectWDDFileName(props)+ LTDTKeys.DICTIONARY_DELIMITER;
392 			
393 				window.WDD = DictionaryParser.parse(Utility.toURL(Utility.getProjectWDDFileName(props)) );
394 				
395 				// set status type to WDDSTATUSTYPE while a project is open.
396 				// this is only set in the cache, it does not affect how it's physically stored in a dictionary file
397 				DictionaryUtility.setStatusType (window.WDD, LTDTKeys.WDDSTATUSTYPE);
398 			}
399 
400 		} 
401 		catch ( MalformedURLException me) {
402 			JOptionPane.showMessageDialog(window, "Error when reading WDD during project opening. "+me.getMessage());
403 		}
404 		catch (ParseException pe) {
405 			JOptionPane.showMessageDialog(window,"Error when reading WDD during project opening. "+pe.getMessage());				
406 		}
407 		catch (IOException ie) {
408 			JOptionPane.showMessageDialog(window, "Error when reading WDD during project opening. "+ie.getMessage());
409 		}
410 
411 		
412 		//merge all specified dictionaries, plus WDD, into a dictionary cache
413 		if (displayDictionaries.length()>0) {
414 			try {
415 				if ("true".equals(props.getProperty("debug")))
416 					System.err.println ("displayDictionaries="+displayDictionaries);			
417 
418 				window.mDictionary = DictionaryUtility.MergeDictionaryList(window.mDictionary, Utility.rowstring2urllist(displayDictionaries)  );
419 				
420 			}
421 			catch ( MalformedURLException me) {
422 				JOptionPane.showMessageDialog(window, "Error when construction runtime merged dictionary. "+me.getMessage());
423 			}
424 			catch (ParseException pe) {
425 				JOptionPane.showMessageDialog(window,"Error when construction runtime merged dictionary. "+pe.getMessage());				
426 			}
427 			catch (IOException ie) {
428 				JOptionPane.showMessageDialog(window, "Error when construction runtime merged dictionary. "+ie.getMessage());
429 			}
430 		}
431 		
432 		
433 		if (displayDictionaries.length()>0) {
434 
435 			populateKeywords(props, window, displayDictionaries);
436 			
437 			DictionaryUtility.populateDictionaryFullListingPane(window);
438 			
439 			window.setTitle("LTDTool (Project Name: "+projectName+")");			
440 		}
441 		
442 		else {
443 			window.setTitle("LTDTool (Project Name: "+projectName+")");
444 						
445 		}
446 		
447 		return LTDTKeys.SUCCESS;
448 		
449 	}
450 
451 	
452 	
453 	/***
454 	 * Populate dictionary keyword map
455 	 * @param dictStr  The combined string of props.dictionaries and wdd names
456 	 */
457 	public static void populateKeywords (Properties props, MainWindow window, String dictStr)  {
458 		
459 		ArrayList dictArray = DictionaryUtility.getDictionaryNameList(dictStr);
460 		// clear dictionary map from 
461 		window.dictionaryMap.clear();
462 		window.dictionaryMap.addDictionaries (props, window, dictStr);
463 
464 
465 	}
466 	
467 	
468 	private static int reportOpenStatus(Properties props, MainWindow window) {
469 		
470 		String log_message= null;
471 		String debug_log_message = null;
472 		
473 		
474 		String projectName=props.getProperty(LTDTKeys.PROJECTNAME);			
475 		String projDir = props.getProperty(LTDTKeys.PROJECTDIR);
476 			
477 		
478 		try {
479 			logfile_name=Utility.getProjectLogFileName(props);
480 			//logfile_name=props.getProperty(LTDTKeys.PROJECTDIR)+LTDTKeys.PROJECTLOGFILESUFFIX;				
481 			log_message = "Project "+projectName+" opened";
482 			if ("true".equals(props.getProperty("debug"))) {
483 				debug_log_message = log_message+ " with configuration setting \n";
484 						
485 				for (Enumeration e= props.propertyNames(); e.hasMoreElements();) {
486 					String key = e.nextElement().toString();
487 					debug_log_message = debug_log_message + key+"="+props.getProperty(key)+"\n";
488 				}
489 						
490 				Utility.writeLogEntry(logfile_name, debug_log_message);
491 			}
492 			else 
493 				Utility.writeLogEntry(logfile_name, log_message);
494 					
495 		}
496 		catch (IOException e) {
497 			JOptionPane.showMessageDialog(window, 
498 					"IOExeption. Error writing to project log "+logfile_name, 
499 					"Error", JOptionPane.ERROR_MESSAGE);
500 			return LTDTKeys.ERROR;
501 		}
502 		
503 		return LTDTKeys.SUCCESS;
504 	}
505 }