1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package ca.uhn.hl7v2.testpanel.controller;
27
28 import static org.apache.commons.lang.StringUtils.*;
29
30 import java.awt.Component;
31 import java.awt.Dimension;
32 import java.awt.EventQueue;
33 import java.awt.Frame;
34 import java.beans.PropertyVetoException;
35 import java.io.BufferedWriter;
36 import java.io.File;
37 import java.io.FileOutputStream;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.io.InputStreamReader;
41 import java.io.OutputStreamWriter;
42 import java.io.Reader;
43 import java.net.MalformedURLException;
44 import java.net.ServerSocket;
45 import java.net.URL;
46 import java.nio.charset.Charset;
47 import java.text.SimpleDateFormat;
48 import java.util.Arrays;
49 import java.util.LinkedList;
50 import java.util.List;
51 import java.util.Properties;
52 import java.util.concurrent.ExecutorService;
53 import java.util.concurrent.Executors;
54
55 import javax.swing.JFileChooser;
56 import javax.swing.JOptionPane;
57 import javax.swing.filechooser.FileFilter;
58
59 import org.apache.commons.lang.StringUtils;
60 import org.apache.commons.lang.Validate;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 import ca.uhn.hl7v2.conf.ProfileException;
65 import ca.uhn.hl7v2.model.Message;
66 import ca.uhn.hl7v2.parser.DefaultModelClassFactory;
67 import ca.uhn.hl7v2.parser.GenericParser;
68 import ca.uhn.hl7v2.testpanel.model.ActivityIncomingMessage;
69 import ca.uhn.hl7v2.testpanel.model.ActivityMessage;
70 import ca.uhn.hl7v2.testpanel.model.MessagesList;
71 import ca.uhn.hl7v2.testpanel.model.conf.ProfileFileList;
72 import ca.uhn.hl7v2.testpanel.model.conf.ProfileGroup;
73 import ca.uhn.hl7v2.testpanel.model.conf.TableFileList;
74 import ca.uhn.hl7v2.testpanel.model.conn.InboundConnection;
75 import ca.uhn.hl7v2.testpanel.model.conn.InboundConnectionList;
76 import ca.uhn.hl7v2.testpanel.model.conn.OutboundConnection;
77 import ca.uhn.hl7v2.testpanel.model.conn.OutboundConnectionList;
78 import ca.uhn.hl7v2.testpanel.model.msg.Comment;
79 import ca.uhn.hl7v2.testpanel.model.msg.Hl7V2MessageBase;
80 import ca.uhn.hl7v2.testpanel.model.msg.Hl7V2MessageCollection;
81 import ca.uhn.hl7v2.testpanel.model.msg.Hl7V2MessageEr7;
82 import ca.uhn.hl7v2.testpanel.model.msg.Hl7V2MessageXml;
83 import ca.uhn.hl7v2.testpanel.ui.AddMessageDialog;
84 import ca.uhn.hl7v2.testpanel.ui.FileChooserOpenAccessory;
85 import ca.uhn.hl7v2.testpanel.ui.FileChooserSaveAccessory;
86 import ca.uhn.hl7v2.testpanel.ui.NothingSelectedPanel;
87 import ca.uhn.hl7v2.testpanel.ui.TestPanelWindow;
88 import ca.uhn.hl7v2.testpanel.ui.conn.CreateOutboundConnectionDialog;
89 import ca.uhn.hl7v2.testpanel.ui.conn.InboundConnectionPanel;
90 import ca.uhn.hl7v2.testpanel.ui.conn.OutboundConnectionPanel;
91 import ca.uhn.hl7v2.testpanel.ui.editor.Hl7V2MessageEditorPanel;
92 import ca.uhn.hl7v2.testpanel.util.AllFileFilter;
93 import ca.uhn.hl7v2.testpanel.util.ExtensionFilter;
94 import ca.uhn.hl7v2.testpanel.util.FileUtils;
95 import ca.uhn.hl7v2.testpanel.util.IOkCancelCallback;
96 import ca.uhn.hl7v2.testpanel.util.ISendProgressCallback;
97 import ca.uhn.hl7v2.testpanel.util.LineEndingsEnum;
98 import ca.uhn.hl7v2.testpanel.util.PortUtil;
99 import ca.uhn.hl7v2.testpanel.xsd.Hl7V2EncodingTypeEnum;
100 import ca.uhn.hl7v2.validation.impl.DefaultValidation;
101
102 public class Controller {
103
104 static final String DIALOG_TITLE = "TestPanel";
105 private static final Logger ourLog = LoggerFactory.getLogger(Controller.class);
106 private String myAppVersionString;
107 private JFileChooser myConformanceProfileFileChooser;
108 private ExecutorService myExecutor;
109 private InboundConnectionList myInboundConnectionList;
110 private Object myLeftSelectedItem;
111 private boolean myMessageEditorInFollowMode = true;
112 private MessagesList myMessagesList;
113 private Object myNothingSelectedMarker = new Object();
114 private JFileChooser myOpenMessagesFileChooser;
115 private FileChooserOpenAccessory myOpenMessagesFileChooserAccessory;
116 private OutboundConnectionList myOutboundConnectionList;
117 private ProfileFileList myProfileFileList;
118 private ConformanceEditorController myProfilesAndTablesController;
119 private LinkedList<Runnable> myQueuedTasks = new LinkedList<Runnable>();
120 private JFileChooser mySaveMessagesFileChooser;
121 private FileChooserSaveAccessory mySaveMessagesFileChooserAccessory;
122 private TableFileList myTableFileList;
123 private TestPanelWindow myView;
124
125 public Controller() {
126 myTableFileList = new TableFileList();
127 myProfileFileList = new ProfileFileList(myTableFileList);
128
129 myMessagesList = new MessagesList(this);
130 try {
131 File workfilesDir = Prefs.getTempWorkfilesDirectory();
132 if (workfilesDir.exists() && workfilesDir.listFiles().length > 0) {
133 ourLog.info("Restoring work files from directory: {}", workfilesDir.getAbsolutePath());
134 myMessagesList.restoreFromWorkDirectory(workfilesDir);
135 }
136 } catch (IOException e1) {
137 ourLog.error("Failed to restore from work direrctory", e1);
138 }
139
140 String savedOutboundList = Prefs.getInstance().getOutboundConnectionList();
141 if (StringUtils.isNotBlank(savedOutboundList)) {
142 try {
143 myOutboundConnectionList = OutboundConnectionList.fromXml(this, savedOutboundList);
144 } catch (Exception e) {
145 ourLog.error("Failed to load outbound connections from storage, going to create default value", e);
146 createDefaultOutboundConnectionList();
147 }
148 }
149
150 if (myOutboundConnectionList == null || myOutboundConnectionList.getConnections().isEmpty()) {
151 ourLog.info("No saved outbound connection list found");
152 createDefaultOutboundConnectionList();
153 }
154
155 String savedInboundList = Prefs.getInstance().getInboundConnectionList();
156 if (StringUtils.isNotBlank(savedInboundList)) {
157 try {
158 myInboundConnectionList = InboundConnectionList.fromXml(this, savedInboundList);
159 } catch (Exception e) {
160 ourLog.error("Failed to load inbound connections from storage, going to create default value", e);
161 createDefaultInboundConnectionList();
162 }
163 }
164
165 if (myInboundConnectionList == null || myInboundConnectionList.getConnections().isEmpty()) {
166 ourLog.info("No saved inbound connection list found");
167 createDefaultInboundConnectionList();
168 }
169
170 }
171
172 public void addInboundConnection() {
173 InboundConnection con = myInboundConnectionList.createDefaultConnection(provideRandomPort());
174
175 setLeftSelectedItem(con);
176 myInboundConnectionList.addConnection(con);
177 }
178
179 public void addMessage() {
180 AddMessageDialog dialog = new AddMessageDialog(this);
181 dialog.setModal(true);
182 dialog.setVisible(true);
183 }
184
185
186
187
188
189 public void addMessage(String theVersion, String theType, String theTrigger, String theStructure, Hl7V2EncodingTypeEnum theEncoding) {
190 DefaultModelClassFactory mcf = new DefaultModelClassFactory();
191 try {
192 Hl7V2MessageCollection col = new Hl7V2MessageCollection();
193 col.setValidationContext(new DefaultValidation());
194
195 Class<? extends Message> messageClass = mcf.getMessageClass(theStructure, theVersion, true);
196 ca.uhn.hl7v2.model.AbstractMessage message = (ca.uhn.hl7v2.model.AbstractMessage) messageClass.newInstance();
197 message.initQuickstart(theType, theTrigger, "T");
198
199 GenericParser p = new GenericParser();
200 Hl7V2MessageBase msg;
201 if (theEncoding == Hl7V2EncodingTypeEnum.ER_7) {
202 p.setPipeParserAsPrimary();
203 col.setEncoding(Hl7V2EncodingTypeEnum.ER_7);
204 msg = new Hl7V2MessageEr7();
205 msg.setSourceMessage(p.encode(message));
206 } else {
207 p.setXMLParserAsPrimary();
208 col.setEncoding(Hl7V2EncodingTypeEnum.XML);
209 msg = new Hl7V2MessageXml();
210 msg.setSourceMessage(p.encode(message));
211 }
212
213 col.addMessage(new Comment(""));
214
215 msg.setIndexWithinCollection(1);
216 col.addMessage(msg);
217
218 setLeftSelectedItem(col);
219 myMessagesList.addMessage(col);
220
221 } catch (Exception e) {
222 handleUnexpectedError(e);
223 }
224 }
225
226 public void addOutboundConnection() {
227 OutboundConnection con = myOutboundConnectionList.createDefaultConnection(provideRandomPort());
228
229 setLeftSelectedItem(con);
230 myOutboundConnectionList.addConnection(con);
231 }
232
233 public void addOutboundConnectionToSendTo(final IOkCancelCallback<OutboundConnection> theHandler) {
234 OutboundConnection connection = myOutboundConnectionList.createDefaultConnection(provideRandomPort());
235
236 final IOkCancelCallback<OutboundConnection> handler = new IOkCancelCallback<OutboundConnection>() {
237 public void cancel(OutboundConnection theArg) {
238 theHandler.cancel(theArg);
239 }
240
241 public void ok(OutboundConnection theArg) {
242 myOutboundConnectionList.addConnection(theArg);
243 theHandler.ok(theArg);
244 }
245 };
246
247 CreateOutboundConnectionDialog dialog = new CreateOutboundConnectionDialog(this, connection, handler);
248 dialog.setVisible(true);
249 }
250
251 public void chooseAndLoadConformanceProfileForMessage(Hl7V2MessageCollection theMessage, IOkCancelCallback<Void> theCallback) {
252 if (myConformanceProfileFileChooser == null) {
253 myConformanceProfileFileChooser = new JFileChooser(Prefs.getInstance().getOpenPathConformanceProfile());
254 myConformanceProfileFileChooser.setDialogTitle("Choose an HL7 Conformance Profile");
255
256 ExtensionFilter type = new ExtensionFilter("XML Files", new String[] { ".xml" });
257 myConformanceProfileFileChooser.addChoosableFileFilter(type);
258 }
259
260 int value = myConformanceProfileFileChooser.showOpenDialog(myView.getFrame());
261 if (value == JFileChooser.APPROVE_OPTION) {
262
263 File file = myConformanceProfileFileChooser.getSelectedFile();
264 Prefs.getInstance().setOpenPathConformanceProfile(file.getPath());
265
266 try {
267 String profileString = FileUtils.readFile(file);
268 theMessage.setRuntimeProfile(ProfileGroup.createFromRuntimeProfile(profileString));
269
270 theCallback.ok(null);
271
272 } catch (IOException e) {
273 ourLog.error("Failed to load profile", e);
274 theCallback.cancel(null);
275 } catch (ProfileException e) {
276 ourLog.error("Failed to load profile", e);
277 theCallback.cancel(null);
278 }
279 } else {
280 theCallback.cancel(null);
281 }
282
283 }
284
285 public void close() {
286
287 if (!saveAllMessagesAndReturnFalseIfCancelIsPressed()) {
288 return;
289 }
290
291 myOutboundConnectionList.removeNonPersistantConnections();
292 ourLog.info("Saving {} outbound connection descriptors", myOutboundConnectionList.getConnections().size());
293 Prefs.getInstance().setOutboundConnectionList(myOutboundConnectionList.exportConfigToXml());
294
295 myInboundConnectionList.removeNonPersistantConnections();
296 ourLog.info("Saving {} inbound connection descriptors", myInboundConnectionList.getConnections().size());
297 Prefs.getInstance().setInboundConnectionList(myInboundConnectionList.exportConfigToXml());
298
299 try {
300
301 ourLog.info("Flusing open messages to work directory");
302 File workfilesDir = Prefs.getTempWorkfilesDirectory();
303 myMessagesList.dumpToWorkDirectory(workfilesDir);
304
305
306
307
308 } catch (IOException e) {
309 ourLog.error("Failed to flush work directory!", e);
310 }
311
312 myView.destroy();
313
314
315
316 myExecutor.shutdown();
317
318 ourLog.info("TestPanel is exiting with status 0");
319 System.exit(0);
320 }
321
322 public void closeMessage(Hl7V2MessageCollection theMsg) {
323 if (theMsg.isSaved() == false) {
324 int save = showPromptToSaveMessageBeforeClosingIt(theMsg, true);
325 switch (save) {
326 case JOptionPane.YES_OPTION:
327 if (!saveMessages(theMsg)) {
328 return;
329 }
330 break;
331 case JOptionPane.NO_OPTION:
332 break;
333 case JOptionPane.CANCEL_OPTION:
334 return;
335 default:
336
337 throw new Error("invalid option:" + save);
338 }
339 }
340
341 updateRecentMessageFiles(theMsg);
342
343 myMessagesList.removeMessage(theMsg);
344 if (myMessagesList.getMessages().size() > 0) {
345 setLeftSelectedItem(myMessagesList.getMessages().get(0));
346 } else {
347 tryToSelectSomething();
348 }
349 }
350
351 private void createDefaultInboundConnectionList() {
352 myInboundConnectionList = new InboundConnectionList();
353
354 }
355
356 private void createDefaultOutboundConnectionList() {
357 myOutboundConnectionList = new OutboundConnectionList();
358
359 }
360
361
362
363
364 private boolean doSave(Hl7V2MessageCollection theSelectedValue) {
365 Validate.notNull(theSelectedValue);
366
367 try {
368
369
370
371
372 File saveFile = new File(theSelectedValue.getSaveFileName());
373 FileOutputStream fos = new FileOutputStream(saveFile);
374
375 Charset saveCharset = theSelectedValue.getSaveCharset();
376 BufferedWriter w;
377 if (saveCharset != null) {
378 w = new BufferedWriter(new OutputStreamWriter(fos, saveCharset));
379 } else {
380 w = new BufferedWriter(new OutputStreamWriter(fos));
381 }
382
383 boolean saveStripComments = theSelectedValue.isSaveStripComments();
384 LineEndingsEnum lineEndings = theSelectedValue.getSaveLineEndings();
385
386 theSelectedValue.writeToFile(w, saveStripComments, lineEndings);
387
388 w.close();
389 fos.close();
390
391 theSelectedValue.setSaveFileTimestamp(saveFile.lastModified());
392
393 ourLog.info("Saved " + theSelectedValue.getMessages().size() + " messages to " + theSelectedValue.getSaveFileName());
394 theSelectedValue.setSaved(true);
395 return true;
396
397 } catch (IOException e) {
398 ourLog.error("Failed to save file", e);
399 showDialogError("Failed to save file: " + e.getMessage());
400 return false;
401 }
402
403 }
404
405 public void editMessages(List<ActivityMessage> theList) {
406 Validate.notEmpty(theList);
407
408 Hl7V2MessageCollection messageCollection = new Hl7V2MessageCollection();
409
410 int index = 0;
411 for (ActivityMessage next : theList) {
412 Hl7V2MessageBase nextModel;
413 if (next.getEncoding() == Hl7V2EncodingTypeEnum.ER_7) {
414 nextModel = new Hl7V2MessageEr7();
415 } else {
416 nextModel = new Hl7V2MessageXml();
417 }
418
419 nextModel.setEncoding(next.getEncoding());
420 try {
421 nextModel.setSourceMessage(next.getRawMessage());
422 } catch (PropertyVetoException e) {
423 ourLog.error("Failed to create message object", e);
424 continue;
425 }
426
427 nextModel.setIndexWithinCollection(index++);
428
429 StringBuilder b = new StringBuilder();
430 if (index > 1) {
431 b.append("\n");
432 }
433
434 if (next instanceof ActivityIncomingMessage) {
435 b.append("Received ");
436 } else {
437 b.append("Sent ");
438 }
439
440 String timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS").format(next.getTimestamp());
441 b.append(timestamp);
442
443 messageCollection.addComment(b.toString());
444
445 messageCollection.addMessage(nextModel);
446
447 }
448
449 setLeftSelectedItem(messageCollection);
450 myMessagesList.addMessage(messageCollection);
451
452 }
453
454 public String getAppVersionString() {
455 if (myAppVersionString == null) {
456
457 Properties prop = new Properties();
458 try {
459 prop.load(Controller.class.getClassLoader().getResourceAsStream("testpanelversion.properties"));
460 myAppVersionString = prop.getProperty("app.version");
461 } catch (IOException e) {
462 ourLog.error("Couldn't load version property", e);
463 myAppVersionString = "v.UNK";
464 }
465 }
466 return myAppVersionString;
467 }
468
469
470
471
472 public InboundConnectionList getInboundConnectionList() {
473 return myInboundConnectionList;
474 }
475
476 public Object getLeftSelectedItem() {
477 return myLeftSelectedItem;
478 }
479
480 public MessagesList getMessagesList() {
481 return myMessagesList;
482 }
483
484 public OutboundConnectionList getOutboundConnectionList() {
485 return myOutboundConnectionList;
486 }
487
488 public ProfileFileList getProfileFileList() {
489 return myProfileFileList;
490 }
491
492
493
494
495 public TableFileList getTableFileList() {
496 return myTableFileList;
497 }
498
499 public Frame getWindow() {
500 return myView.getFrame();
501 }
502
503 private void handleUnexpectedError(Exception theE) {
504 ourLog.error(theE.getMessage(), theE);
505 showDialogError(theE.getMessage());
506 }
507
508 public void invokeInBackground(Runnable theRunnable) {
509 if (myExecutor != null) {
510 myExecutor.execute(theRunnable);
511 } else {
512 myQueuedTasks.add(theRunnable);
513 }
514 }
515
516 public boolean isMessageEditorInFollowMode() {
517 return myMessageEditorInFollowMode;
518 }
519
520 private void openMessageFile(File file, Charset theCharset) {
521 try {
522 String profileString = FileUtils.readFile(file, theCharset);
523 Hl7V2MessageCollection col = new Hl7V2MessageCollection();
524
525 col.setSourceMessage(profileString);
526 col.setSaveFileName(file.getAbsolutePath());
527 col.setSaved(true);
528
529 if (col.getMessages().isEmpty()) {
530 showDialogError("No messages were found in the file");
531 } else {
532
533 setLeftSelectedItem(col);
534 myMessagesList.addMessage(col);
535
536 }
537 } catch (IOException e) {
538 ourLog.error("Failed to load profile", e);
539 }
540 }
541
542 public void openMessages() {
543 if (myOpenMessagesFileChooser == null) {
544 myOpenMessagesFileChooser = new JFileChooser(Prefs.getInstance().getOpenPathMessages());
545 myOpenMessagesFileChooserAccessory = new FileChooserOpenAccessory();
546 myOpenMessagesFileChooser.setAccessory(myOpenMessagesFileChooserAccessory);
547 myOpenMessagesFileChooser.setDialogTitle("Choose a file containing HL7 messages");
548
549 FileFilter type = new ExtensionFilter("HL7 Files", new String[] { ".hl7" });
550 myOpenMessagesFileChooser.addChoosableFileFilter(type);
551
552 type = new ExtensionFilter("XML Files", new String[] { ".xml" });
553 myOpenMessagesFileChooser.addChoosableFileFilter(type);
554
555 type = new AllFileFilter();
556 myOpenMessagesFileChooser.addChoosableFileFilter(type);
557 }
558
559 int value = myOpenMessagesFileChooser.showOpenDialog(myView.getFrame());
560 if (value == JFileChooser.APPROVE_OPTION) {
561
562 File file = myOpenMessagesFileChooser.getSelectedFile();
563 Prefs.getInstance().setOpenPathMessages(file.getPath());
564
565 openMessageFile(file, myOpenMessagesFileChooserAccessory.getSelectedCharset());
566 }
567
568 }
569
570 public void openOrSwitchToMessage(Hl7V2MessageCollection theFile) {
571 for (Hl7V2MessageCollection next : myMessagesList.getMessages()) {
572 if (theFile.equals(next.getSaveFileName())) {
573 setLeftSelectedItem(next);
574 return;
575 }
576 }
577
578 File file = new File(theFile.getSaveFileName());
579 if (file.exists() == false) {
580 ourLog.error("Can't find file: {}", theFile);
581 }
582
583 openMessageFile(file, theFile.getSaveCharset());
584 }
585
586 public void populateWithSampleMessageAndConnections() {
587
588
589
590 Hl7V2MessageCollection col = new Hl7V2MessageCollection();
591 col.setValidationContext(new DefaultValidation());
592
593 String message = "MSH|^~\\&|NES|NINTENDO|TESTSYSTEM|TESTFACILITY|20010101000000||ADT^A04|Q123456789T123456789X123456|P|2.3\r" + "EVN|A04|20010101000000|||^KOOPA^BOWSER^^^^^^^CURRENT\r"
594 + "PID|1||123456789|0123456789^AA^^JP|BROS^MARIO^^^^||19850101000000|M|||123 FAKE STREET^MARIO \\T\\ LUIGI BROS PLACE^TOADSTOOL KINGDOM^NES^A1B2C3^JP^HOME^^1234|1234|(555)555-0123^HOME^JP:1234567|||S|MSH|12345678|||||||0|||||N\r"
595 + "NK1|1|PEACH^PRINCESS^^^^|SO|ANOTHER CASTLE^^TOADSTOOL KINGDOM^NES^^JP|(123)555-1234|(123)555-2345|NOK|||||||||||||\r" + "NK1|2|TOADSTOOL^PRINCESS^^^^|SO|YET ANOTHER CASTLE^^TOADSTOOL KINGDOM^NES^^JP|(123)555-3456|(123)555-4567|EMC|||||||||||||\r"
596 + "PV1|1|O|ABCD^EFGH^|||^^|123456^DINO^YOSHI^^^^^^MSRM^CURRENT^^^NEIGHBOURHOOD DR NBR^|^DOG^DUCKHUNT^^^^^^^CURRENT||CRD|||||||123456^DINO^YOSHI^^^^^^MSRM^CURRENT^^^NEIGHBOURHOOD DR NBR^|AO|0123456789|1|||||||||||||||||||MSH||A|||20010101000000\r"
597 + "IN1|1|PAR^PARENT||||LUIGI\r" + "IN1|2|FRI^FRIEND||||PRINCESS";
598 col.setEncoding(Hl7V2EncodingTypeEnum.ER_7);
599 col.setSourceMessage(message);
600 myMessagesList.addMessage(col);
601
602
603 int port = PortUtil.findFreePort();
604
605
606
607 InboundConnection iCon = myInboundConnectionList.createDefaultConnection(port);
608 iCon.setPersistent(true);
609 myInboundConnectionList.addConnection(iCon);
610
611 OutboundConnection oCon = myOutboundConnectionList.createDefaultConnection(port);
612 oCon.setPersistent(true);
613 myOutboundConnectionList.addConnection(oCon);
614
615
616
617 setLeftSelectedItem(col);
618 }
619
620
621
622
623 private int provideRandomPort() {
624 ServerSocket server;
625 try {
626 server = new ServerSocket(0);
627 int port = server.getLocalPort();
628 server.close();
629 return port;
630 } catch (IOException e) {
631 throw new Error(e);
632 }
633 }
634
635 private Component provideViewFrameIfItExists() {
636 return myView != null ? myView.getFrame() : null;
637 }
638
639 public void removeInboundConnection(InboundConnection theConnection) {
640 myInboundConnectionList.removeConnecion(theConnection);
641 if (myInboundConnectionList.getConnections().size() > 0) {
642 setLeftSelectedItem(myInboundConnectionList.getConnections().get(0));
643 } else {
644 tryToSelectSomething();
645 }
646 }
647
648 public void removeOutboundConnection(OutboundConnection theConnection) {
649 myOutboundConnectionList.removeConnecion(theConnection);
650 if (myOutboundConnectionList.getConnections().size() > 0) {
651 setLeftSelectedItem(myOutboundConnectionList.getConnections().get(0));
652 } else {
653 tryToSelectSomething();
654 }
655 }
656
657 public void revertMessage(Hl7V2MessageCollection theMsg) {
658 if (StringUtils.isBlank(theMsg.getSaveFileName())) {
659 showDialogError("Message has not yet been saved");
660 return;
661 }
662
663 File file = new File(theMsg.getSaveFileName());
664 if (file.exists() == false || file.isDirectory() || !file.canRead()) {
665 showDialogError("File \"" + theMsg.getSaveFileName() + "\" can not be read");
666 return;
667 }
668
669 int revert = showDialogYesNo("Revert file to saved contents? You will lose all changes.");
670 if (revert == JOptionPane.NO_OPTION) {
671 return;
672 }
673
674 Charset charSet = theMsg.getSaveCharset();
675 String contents;
676 try {
677 contents = FileUtils.readFile(file, charSet);
678 } catch (IOException e) {
679 ourLog.error("Failed to read from file " + file.getAbsolutePath(), e);
680 showDialogError("Failed to read from file: " + e.getMessage());
681 return;
682 }
683
684 theMsg.setSourceMessage(contents);
685
686 }
687
688 public boolean saveAllMessagesAndReturnFalseIfCancelIsPressed() {
689
690 for (Hl7V2MessageCollection next : myMessagesList.getMessages()) {
691 if (next.isSaved() == false) {
692 int save = showPromptToSaveMessageBeforeClosingIt(next, true);
693 switch (save) {
694 case JOptionPane.YES_OPTION:
695 if (!saveMessages(next)) {
696 return false;
697 }
698 break;
699 case JOptionPane.NO_OPTION:
700 break;
701 case JOptionPane.CANCEL_OPTION:
702 return false;
703 default:
704
705 throw new Error("invalid option:" + save);
706 }
707 }
708 }
709
710 return true;
711 }
712
713 public boolean saveMessages(Hl7V2MessageCollection theSelectedValue) {
714 Validate.notNull(theSelectedValue);
715
716 if (theSelectedValue.getSaveFileName() == null) {
717 return saveMessagesAs(theSelectedValue);
718 } else {
719 return doSave(theSelectedValue);
720 }
721
722 }
723
724
725
726
727
728
729 public boolean saveMessagesAs(Hl7V2MessageCollection theSelectedValue) {
730 Validate.notNull(theSelectedValue);
731
732 if (mySaveMessagesFileChooser == null) {
733 mySaveMessagesFileChooser = new JFileChooser(Prefs.getInstance().getSavePathMessages());
734 mySaveMessagesFileChooser.setDialogTitle("Choose a file to save the current message(s) to");
735 mySaveMessagesFileChooserAccessory = new FileChooserSaveAccessory();
736 mySaveMessagesFileChooser.setAccessory(mySaveMessagesFileChooserAccessory);
737
738 FileFilter type = new ExtensionFilter("HL7 Files", new String[] { ".hl7" });
739 mySaveMessagesFileChooser.addChoosableFileFilter(type);
740
741 type = new ExtensionFilter("XML Files", new String[] { ".xml" });
742 mySaveMessagesFileChooser.addChoosableFileFilter(type);
743
744 type = new AllFileFilter();
745 mySaveMessagesFileChooser.addChoosableFileFilter(type);
746
747 mySaveMessagesFileChooser.setPreferredSize(new Dimension(700, 500));
748 }
749
750 int value = mySaveMessagesFileChooser.showSaveDialog(myView.getFrame());
751 if (value == JFileChooser.APPROVE_OPTION) {
752
753 File file = mySaveMessagesFileChooser.getSelectedFile();
754 Prefs.getInstance().setSavePathMessages(file.getPath());
755
756 if (!file.getName().contains(".")) {
757 switch (theSelectedValue.getEncoding()) {
758 case ER_7:
759 file = new File(file.getAbsolutePath() + ".hl7");
760 break;
761 case XML:
762 file = new File(file.getAbsolutePath() + ".xml");
763 break;
764 }
765 }
766
767 if (file.exists()) {
768 String message = "The file \"" + file.getName() + "\" already exists. Do you wish to overwrite it?";
769 int confirmed = showDialogYesNo(message);
770 if (confirmed == JOptionPane.NO_OPTION) {
771 return false;
772 }
773
774 ourLog.info("Deleting file: {}", file.getAbsolutePath());
775 file.delete();
776 }
777
778 theSelectedValue.setSaveCharset(mySaveMessagesFileChooserAccessory.getSelectedCharset());
779 theSelectedValue.setSaveFileName(file.getAbsolutePath());
780
781 theSelectedValue.setSaveStripComments(mySaveMessagesFileChooserAccessory.isSelectedSaveStripComments());
782 theSelectedValue.setSaveLineEndings(mySaveMessagesFileChooserAccessory.getSelectedLineEndings());
783
784 doSave(theSelectedValue);
785
786 return true;
787
788 } else {
789
790 return false;
791
792 }
793 }
794
795
796
797
798
799
800 public void sendMessages(OutboundConnection theConnection, Hl7V2MessageCollection theMessage, ISendProgressCallback theTransmissionCallback) {
801 theConnection.sendMessages(theMessage, theTransmissionCallback);
802 }
803
804 public void setLeftSelectedItem(Object theSelectedValue) {
805 if (myLeftSelectedItem == theSelectedValue) {
806 return;
807 }
808
809 String id = null;
810
811 myLeftSelectedItem = theSelectedValue;
812 if (myLeftSelectedItem instanceof Hl7V2MessageCollection) {
813 Hl7V2MessageEditorPanel hl7v2MessageEditorPanel = new Hl7V2MessageEditorPanel(this);
814 Hl7V2MessageCollection collection = (Hl7V2MessageCollection) myLeftSelectedItem;
815 hl7v2MessageEditorPanel.setMessage(collection);
816 myView.setMainPanel(hl7v2MessageEditorPanel);
817 id = collection.getId();
818 } else if (myLeftSelectedItem instanceof OutboundConnection) {
819 OutboundConnectionPanel panel = new OutboundConnectionPanel(this);
820 panel.setController(this);
821 OutboundConnection connection = (OutboundConnection) myLeftSelectedItem;
822 panel.setConnection(connection);
823 id = connection.getId();
824 myView.setMainPanel(panel);
825 } else if (myLeftSelectedItem instanceof InboundConnection) {
826 InboundConnectionPanel panel = new InboundConnectionPanel(this);
827 InboundConnection connection = (InboundConnection) myLeftSelectedItem;
828 panel.setConnection(connection);
829 myView.setMainPanel(panel);
830 id = connection.getId();
831 } else if (myLeftSelectedItem == myNothingSelectedMarker) {
832 myView.setMainPanel(new NothingSelectedPanel(this));
833 }
834
835 if (id != null) {
836 Prefs.getInstance().setMostRecentlySelectedItemId(id);
837 }
838 }
839
840
841
842
843
844 public void setMessageEditorInFollowMode(boolean theMessageEditorInFollowMode) {
845 myMessageEditorInFollowMode = theMessageEditorInFollowMode;
846 }
847
848 public void showAboutDialog() {
849 myView.showAboutDialog();
850 }
851
852 public void showDialogError(String message) {
853 JOptionPane.showMessageDialog(provideViewFrameIfItExists(), message, DIALOG_TITLE, JOptionPane.ERROR_MESSAGE);
854 }
855
856 public void showDialogInfo(String message) {
857 JOptionPane.showMessageDialog(provideViewFrameIfItExists(), message, DIALOG_TITLE, JOptionPane.INFORMATION_MESSAGE);
858 }
859
860 public void showDialogWarning(String message) {
861 JOptionPane.showMessageDialog(provideViewFrameIfItExists(), message, DIALOG_TITLE, JOptionPane.WARNING_MESSAGE);
862 }
863
864 public int showDialogYesNo(String message) {
865 return JOptionPane.showConfirmDialog(provideViewFrameIfItExists(), message, DIALOG_TITLE, JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
866 }
867
868 public void showProfilesAndTablesEditor() {
869 if (myProfilesAndTablesController == null) {
870 myProfilesAndTablesController = new ConformanceEditorController(this);
871 }
872 myProfilesAndTablesController.show();
873 }
874
875 private int showPromptToSaveMessageBeforeClosingIt(Hl7V2MessageCollection theMsg, boolean theShowCancelButton) {
876 Component parentComponent = myView.getFrame();
877 Object message = "<html>The following file is unsaved, do you want to save before closing?<br>" + theMsg.getBestDescription() + "</html>";
878 String title = DIALOG_TITLE;
879 int optionType = theShowCancelButton ? JOptionPane.YES_NO_CANCEL_OPTION : JOptionPane.YES_NO_OPTION;
880 int messageType = JOptionPane.QUESTION_MESSAGE;
881 return JOptionPane.showConfirmDialog(parentComponent, message, title, optionType, messageType);
882 }
883
884 public void start() {
885 ourLog.info("Starting TestPanel Controller...");
886
887 myExecutor = Executors.newSingleThreadExecutor();
888 for (Runnable next : myQueuedTasks) {
889 myExecutor.execute(next);
890 }
891 myQueuedTasks = null;
892
893 myView = new TestPanelWindow(this);
894 myView.getFrame().setVisible(true);
895
896 String leftItemId = Prefs.getInstance().getMostRecentlySelectedItemId();
897 if (isNotBlank(leftItemId)) {
898 Object leftItem = myMessagesList.getWithId(leftItemId);
899 leftItem = (leftItem != null) ? leftItem : myOutboundConnectionList.getWithId(leftItemId);
900 leftItem = (leftItem != null) ? leftItem : myInboundConnectionList.getWithId(leftItemId);
901 if (leftItem != null) {
902 setLeftSelectedItem(leftItem);
903 }
904 }
905
906 if (getLeftSelectedItem() == null) {
907 if (myMessagesList.getMessages().size() > 0) {
908 setLeftSelectedItem(myMessagesList.getMessages().get(0));
909 } else {
910 setLeftSelectedItem(myNothingSelectedMarker);
911 }
912 }
913
914 new VersionChecker().start();
915
916 Prefs.getInstance().setController(this);
917
918 }
919
920 public void startAllInboundConnections() {
921 ourLog.info("Starting all inbound connections");
922 for (InboundConnection next : myInboundConnectionList.getConnections()) {
923 next.start();
924 }
925 }
926
927 public void startAllOutboundConnections() {
928 ourLog.info("Starting all outbound connections");
929 for (OutboundConnection next : myOutboundConnectionList.getConnections()) {
930 next.start();
931 }
932 }
933
934 public void startInboundConnection(InboundConnection theLeftSelectedItem) {
935 theLeftSelectedItem.start();
936 }
937
938 public void startOutboundConnection(OutboundConnection theLeftSelectedItem) {
939 theLeftSelectedItem.start();
940 }
941
942 public void stopAllInboundConnections() {
943 ourLog.info("Stopping all inbound connections");
944 for (InboundConnection next : myInboundConnectionList.getConnections()) {
945 next.stop();
946 }
947 }
948
949 public void stopAllOutboundConnections() {
950 ourLog.info("Stopping all outbound connections");
951 for (OutboundConnection next : myOutboundConnectionList.getConnections()) {
952 next.stop();
953 }
954 }
955
956 private void tryToSelectSomething() {
957 if (myMessagesList.getMessages().size() > 0) {
958 setLeftSelectedItem(myMessagesList.getMessages().get(0));
959 } else if (myOutboundConnectionList.getConnections().size() > 0) {
960 setLeftSelectedItem(myOutboundConnectionList.getConnections().get(0));
961 } else if (myInboundConnectionList.getConnections().size() > 0) {
962 setLeftSelectedItem(myInboundConnectionList.getConnections().get(0));
963 } else {
964 setLeftSelectedItem(myNothingSelectedMarker);
965 }
966 }
967
968 private void updateRecentMessageFiles(Hl7V2MessageCollection theMessage) {
969 Prefs.getInstance().addMessagesFileXmlToRecents(myProfileFileList, Arrays.asList(theMessage));
970 if (myView != null) {
971 myView.setRecentMessageFiles(Prefs.getInstance().getRecentMessageXmlFiles(myProfileFileList));
972 }
973 }
974
975 public boolean validateNewValue(String theTerserPath, String theNewValue) {
976 String errorMsg = null;
977 if (theTerserPath.endsWith("MSH-1")) {
978 if (theNewValue.length() != 1) {
979 errorMsg = "MSH-1 must be exactly 1 character";
980 }
981 }
982
983 if (theTerserPath.endsWith("MSH-2")) {
984 if (theNewValue.length() != 4) {
985 errorMsg = "MSH-2 must be exactly 4 characters";
986 }
987 }
988
989 if (errorMsg != null) {
990 showDialogError(errorMsg);
991 return false;
992 }
993
994 return true;
995 }
996
997
998
999
1000 private class VersionChecker extends Thread {
1001
1002 @Override
1003 public void run() {
1004 String version = getAppVersionString();
1005 if (version.contains("$")) {
1006 version = "1.0";
1007 }
1008
1009 boolean isWebstart = true;
1010 try {
1011 Class.forName("javax.jnlp.ServiceManager");
1012 } catch (Throwable t) {
1013 isWebstart = false;
1014 }
1015
1016 try {
1017 String javaVersion = System.getProperty("java.version");
1018 String os = System.getProperty("os.name").replace(" ", "+");
1019
1020 URL url = new URL("http://hl7api.sourceforge.net/cgi-bin/testpanelversion.cgi?version=" + version + "&java=" + javaVersion + "&os=" + os + "&webstart=" + isWebstart + "&end");
1021 InputStream is = (InputStream) url.getContent();
1022 Reader reader = new InputStreamReader(is, "US-ASCII");
1023 String content = FileUtils.readFromReaderIntoString(reader);
1024 if (content.contains("OK")) {
1025 ourLog.info("HAPI TestPanel is up to date. Great!");
1026 } else if (content.contains("ERRORNOE ")) {
1027 final String message = content.replace("ERRORNOE ", "");
1028 ourLog.warn(message);
1029 EventQueue.invokeLater(new Runnable() {
1030 public void run() {
1031 showDialogWarning(message);
1032 }
1033 });
1034 } else {
1035 ourLog.warn(content);
1036 }
1037 } catch (MalformedURLException e) {
1038 ourLog.warn("Couldn't parse version checker URL", e);
1039 } catch (IOException e) {
1040 ourLog.info("Failed to check if we are running the latest version");
1041 }
1042 }
1043
1044 }
1045
1046 }