1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.panels.teststeps;
14
15 import java.awt.BorderLayout;
16 import java.awt.Component;
17 import java.awt.Dimension;
18 import java.awt.GridLayout;
19 import java.awt.event.ActionEvent;
20 import java.awt.event.ItemEvent;
21 import java.awt.event.ItemListener;
22 import java.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Date;
27 import java.util.List;
28
29 import javax.swing.AbstractAction;
30 import javax.swing.Action;
31 import javax.swing.BorderFactory;
32 import javax.swing.DefaultComboBoxModel;
33 import javax.swing.DefaultListCellRenderer;
34 import javax.swing.DefaultListModel;
35 import javax.swing.JButton;
36 import javax.swing.JCheckBox;
37 import javax.swing.JComboBox;
38 import javax.swing.JComponent;
39 import javax.swing.JLabel;
40 import javax.swing.JList;
41 import javax.swing.JPanel;
42 import javax.swing.JScrollPane;
43 import javax.swing.JSplitPane;
44 import javax.swing.JTextArea;
45 import javax.swing.ListSelectionModel;
46 import javax.swing.event.ChangeEvent;
47 import javax.swing.event.ChangeListener;
48 import javax.swing.event.ListSelectionEvent;
49 import javax.swing.event.ListSelectionListener;
50 import javax.swing.table.AbstractTableModel;
51 import javax.swing.text.Document;
52
53 import org.jdesktop.swingx.JXTable;
54
55 import com.eviware.soapui.SoapUI;
56 import com.eviware.soapui.impl.wsdl.actions.support.ShowOnlineHelpAction;
57 import com.eviware.soapui.impl.wsdl.panels.support.TestRunComponentEnabler;
58 import com.eviware.soapui.impl.wsdl.support.HelpUrls;
59 import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
60 import com.eviware.soapui.impl.wsdl.teststeps.PropertyTransfer;
61 import com.eviware.soapui.impl.wsdl.teststeps.TransferResponseValuesTestStep;
62 import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequest;
63 import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep;
64 import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStep;
65 import com.eviware.soapui.impl.wsdl.teststeps.TransferResponseValuesTestStep.ValueTransferResult;
66 import com.eviware.soapui.model.ModelItem;
67 import com.eviware.soapui.model.TestModelItem;
68 import com.eviware.soapui.model.TestPropertyHolder;
69 import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
70 import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
71 import com.eviware.soapui.model.support.TestRunListenerAdapter;
72 import com.eviware.soapui.model.support.TestSuiteListenerAdapter;
73 import com.eviware.soapui.model.testsuite.TestProperty;
74 import com.eviware.soapui.model.testsuite.TestPropertyListener;
75 import com.eviware.soapui.model.testsuite.TestRunContext;
76 import com.eviware.soapui.model.testsuite.TestRunner;
77 import com.eviware.soapui.model.testsuite.TestStep;
78 import com.eviware.soapui.model.testsuite.TestStepResult;
79 import com.eviware.soapui.support.DocumentListenerAdapter;
80 import com.eviware.soapui.support.UISupport;
81 import com.eviware.soapui.support.components.JComponentInspector;
82 import com.eviware.soapui.support.components.JInspectorPanel;
83 import com.eviware.soapui.support.components.JUndoableTextArea;
84 import com.eviware.soapui.support.components.JXToolBar;
85 import com.eviware.soapui.support.xml.XmlUtils;
86 import com.eviware.soapui.ui.desktop.DesktopPanel;
87 import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
88
89 /***
90 * DesktopPanel for TransferResponseValuesTestStep
91 *
92 * @author Ole.Matzura
93 */
94
95 public class TransferResponseValuesDesktopPanel extends ModelItemDesktopPanel<TransferResponseValuesTestStep>
96 {
97 private final TransferResponseValuesTestStep transferStep;
98 private DefaultListModel listModel;
99 private JList transferList;
100 private JTextArea sourceArea;
101 private JTextArea targetArea;
102 private JButton copyButton;
103 private JButton deleteButton;
104 private JButton declareButton;
105 private JComboBox sourcePropertyCombo;
106 private JComboBox targetPropertyCombo;
107 private JComboBox sourceStepCombo;
108 private JComboBox targetStepCombo;
109 private DefaultComboBoxModel sourceStepModel;
110 private DefaultComboBoxModel targetStepModel;
111 private TestStepPropertiesListener sourceStepPropertiesListener;
112 private TestStepPropertiesListener targetStepPropertiesListener;
113 private TransferPropertyChangeListener transferPropertyChangeListener = new TransferPropertyChangeListener();
114 private boolean selecting;
115 private InternalTestSuiteListener testSuiteListener;
116 private TestRunComponentEnabler componentEnabler;
117 private JCheckBox failTransferCheckBox;
118 private JButton runButton;
119 private JButton renameButton;
120 private JCheckBox setNullCheckBox;
121 private JCheckBox transferTextContentCheckBox;
122 private JCheckBox ignoreEmptyCheckBox;
123 private JCheckBox transferAllCheckBox;
124 private DesktopPanel resultDesktopPanel;
125 private TransfersTableModel transfersTableModel;
126 private InternalTestRunListener testRunListener;
127 private JComponentInspector logInspector;
128 private JCheckBox useXQueryCheckBox;
129 private JButton runAllButton;
130 private JInspectorPanel inspectorPanel;
131
132 public TransferResponseValuesDesktopPanel(TransferResponseValuesTestStep testStep)
133 {
134 super( testStep );
135 this.transferStep = testStep;
136 componentEnabler = new TestRunComponentEnabler( testStep.getTestCase() );
137
138 buildUI();
139
140 testSuiteListener = new InternalTestSuiteListener();
141 transferStep.getTestCase().getTestSuite().addTestSuiteListener( testSuiteListener );
142
143 testRunListener = new InternalTestRunListener();
144 transferStep.getTestCase().addTestRunListener( testRunListener );
145 }
146
147 protected void buildUI()
148 {
149 JSplitPane splitPane = UISupport.createHorizontalSplit();
150
151 listModel = new DefaultListModel();
152
153 for( int c = 0; c < transferStep.getTransferCount(); c++ )
154 {
155 listModel.addElement( transferStep.getTransferAt( c ).getName() );
156 }
157
158 transferList = new JList( listModel );
159 transferList.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
160 transferList.addListSelectionListener( new TransferListSelectionListener());
161 componentEnabler.add( transferList );
162
163 JScrollPane listScrollPane = new JScrollPane( transferList );
164 UISupport.addTitledBorder( listScrollPane, "Transfers" );
165
166 JPanel p = new JPanel( new BorderLayout() );
167 p.add( listScrollPane, BorderLayout.CENTER );
168 p.add( createPropertiesToolbar(), BorderLayout.NORTH );
169
170 splitPane.setLeftComponent( p );
171
172 JSplitPane innerSplit = UISupport.createVerticalSplit();
173 innerSplit.setBorder( null );
174 sourceArea = new JUndoableTextArea();
175 sourceArea.setToolTipText( "XPath selection from source property" );
176 sourceArea.setEnabled( false );
177 sourceArea.getDocument().addDocumentListener( new SourceAreaDocumentListener());
178 componentEnabler.add( sourceArea );
179
180 targetArea = new JUndoableTextArea();
181 targetArea.setToolTipText( "XPath target in target property" );
182 targetArea.setEnabled( false );
183 targetArea.getDocument().addDocumentListener( new TargetAreaDocumentListener());
184 componentEnabler.add( targetArea );
185
186 JPanel sourcePanel = new JPanel( new BorderLayout() );
187 sourcePanel.add( new JScrollPane( sourceArea ), BorderLayout.CENTER );
188 JXToolBar toolbar = createSourceToolbar();
189 sourcePanel.add( toolbar, BorderLayout.NORTH );
190 sourcePanel.setBorder( BorderFactory.createEmptyBorder( 0, 3, 3, 3 ));
191 innerSplit.setTopComponent( sourcePanel );
192
193 JPanel targetPanel = new JPanel( new BorderLayout() );
194 targetPanel.add( new JScrollPane( targetArea ), BorderLayout.CENTER );
195 toolbar = createTargetToolbar();
196 targetPanel.add( toolbar, BorderLayout.NORTH );
197 targetPanel.setBorder( BorderFactory.createEmptyBorder( 0, 3, 3, 3 ));
198
199 innerSplit.setBottomComponent( targetPanel );
200
201 innerSplit.setResizeWeight( 0.5 );
202 innerSplit.setDividerLocation( 0.5 );
203
204 JPanel panel = createTransferOptions();
205
206 JPanel innerPanel = new JPanel( new BorderLayout() );
207 innerPanel.add( innerSplit, BorderLayout.CENTER );
208 innerPanel.add( panel, BorderLayout.SOUTH );
209 innerPanel.add( createConfigToolbar(), BorderLayout.NORTH );
210
211 splitPane.setRightComponent( innerPanel );
212 splitPane.setResizeWeight( 0.1 );
213 splitPane.setDividerLocation( 120 );
214
215 inspectorPanel = new JInspectorPanel( splitPane );
216 logInspector = new JComponentInspector( buildLog(), "Transfer Log (0)", "A log of performed transfers while the editor was open", true );
217 inspectorPanel.addInspector( logInspector );
218 add( inspectorPanel, BorderLayout.CENTER );
219
220 setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ));
221 setPreferredSize( new Dimension( 550, 400 ));
222
223 if( listModel.getSize() > 0 )
224 transferList.setSelectedIndex( 0 );
225
226 componentEnabler.add( deleteButton );
227 componentEnabler.add( declareButton );
228 componentEnabler.add( runButton );
229 componentEnabler.add( runAllButton );
230 componentEnabler.add( copyButton );
231 componentEnabler.add( renameButton );
232 componentEnabler.add( failTransferCheckBox );
233 componentEnabler.add( setNullCheckBox );
234 componentEnabler.add( transferTextContentCheckBox );
235 componentEnabler.add( ignoreEmptyCheckBox );
236 componentEnabler.add( transferAllCheckBox );
237 componentEnabler.add( useXQueryCheckBox );
238 }
239
240 private JComponent buildLog()
241 {
242 JPanel logPanel = new JPanel( new BorderLayout() );
243
244 transfersTableModel = new TransfersTableModel();
245 JXTable table = new JXTable( transfersTableModel );
246
247 table.setHorizontalScrollEnabled( true );
248 table.packAll();
249
250 JXToolBar toolbar = UISupport.createSmallToolbar();
251 toolbar.add( new ClearLogAction() );
252
253 JScrollPane scrollPane = new JScrollPane( table);
254 scrollPane.setBorder( BorderFactory.createCompoundBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ),
255 scrollPane.getBorder() ));
256
257 logPanel.add( toolbar, BorderLayout.NORTH );
258 logPanel.add( scrollPane, BorderLayout.CENTER );
259
260 return logPanel;
261 }
262
263 protected JXToolBar createPropertiesToolbar()
264 {
265 JXToolBar toolbar = UISupport.createSmallToolbar();
266 toolbar.addFixed( UISupport.createToolbarButton( new AddAction() ) );
267 deleteButton = UISupport.createToolbarButton( new DeleteAction() );
268 deleteButton.setEnabled( false );
269 toolbar.addFixed( deleteButton);
270 copyButton = UISupport.createToolbarButton( new CopyAction() );
271 copyButton.setEnabled( false );
272 toolbar.addFixed( copyButton);
273 renameButton = UISupport.createToolbarButton( new RenameAction() );
274 renameButton.setEnabled( false );
275 toolbar.addFixed( renameButton);
276 return toolbar;
277 }
278
279 protected JXToolBar createConfigToolbar()
280 {
281 JXToolBar toolbar = UISupport.createToolbar();
282
283 toolbar.setBorder( BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) );
284
285 runButton = UISupport.createToolbarButton( new RunAction() );
286 runButton.setEnabled( transferList.getSelectedIndex() != -1 );
287 toolbar.addFixed( runButton);
288
289 runAllButton = UISupport.createToolbarButton( new RunAllAction() );
290 runAllButton.setEnabled( transferStep.getTransferCount() > 0 );
291 toolbar.addFixed( runAllButton);
292
293 declareButton = UISupport.createToolbarButton( new DeclareNamespacesAction() );
294 declareButton.setEnabled( false );
295 toolbar.addFixed( declareButton);
296 toolbar.addGlue();
297 toolbar.addFixed( UISupport.createToolbarButton( new ShowOnlineHelpAction( HelpUrls.TRANSFERSTEPEDITOR_HELP_URL )));
298 return toolbar;
299 }
300
301 protected JPanel createTransferOptions()
302 {
303 JPanel panel = new JPanel( new GridLayout( 3, 2 ));
304 failTransferCheckBox = new JCheckBox( "Fail transfer on error", false );
305 failTransferCheckBox.setToolTipText( "Fails the Property Transfer Step if an error occurs" );
306 failTransferCheckBox.addChangeListener( new ChangeListener() {
307
308 public void stateChanged(ChangeEvent e)
309 {
310 PropertyTransfer currentTransfer = getCurrentTransfer();
311 if( currentTransfer != null )
312 {
313 currentTransfer.setFailOnError( failTransferCheckBox.isSelected() );
314 }
315 }} );
316
317 setNullCheckBox = new JCheckBox( "Set null on missing source", false );
318 setNullCheckBox.setToolTipText( "Will set target to null if source is missing or null" );
319 setNullCheckBox.addChangeListener( new ChangeListener() {
320
321 public void stateChanged(ChangeEvent e)
322 {
323 PropertyTransfer currentTransfer = getCurrentTransfer();
324 if( currentTransfer != null )
325 {
326 currentTransfer.setSetNullOnMissingSource( setNullCheckBox.isSelected() );
327 }
328 }} );
329
330 transferTextContentCheckBox = new JCheckBox( "Transfer text content", false );
331 transferTextContentCheckBox.setToolTipText( "Will only transfer text content of source/target elements" );
332 transferTextContentCheckBox.addChangeListener( new ChangeListener() {
333
334 public void stateChanged(ChangeEvent e)
335 {
336 PropertyTransfer currentTransfer = getCurrentTransfer();
337 if( currentTransfer != null )
338 {
339 currentTransfer.setTransferTextContent( transferTextContentCheckBox.isSelected() );
340 }
341 }} );
342
343 ignoreEmptyCheckBox = new JCheckBox( "Ignore empty/missing values", false );
344 ignoreEmptyCheckBox.setToolTipText( "Will not transfer empty or missing values" );
345 ignoreEmptyCheckBox.addChangeListener( new ChangeListener() {
346
347 public void stateChanged(ChangeEvent e)
348 {
349 PropertyTransfer currentTransfer = getCurrentTransfer();
350 if( currentTransfer != null )
351 {
352 currentTransfer.setIgnoreEmpty( ignoreEmptyCheckBox.isSelected() );
353 }
354 }} );
355
356 transferAllCheckBox = new JCheckBox( "Transfer to all", false );
357 transferAllCheckBox.setToolTipText( "Will transfer to all matching target selections" );
358 transferAllCheckBox.addChangeListener( new ChangeListener() {
359
360 public void stateChanged(ChangeEvent e)
361 {
362 PropertyTransfer currentTransfer = getCurrentTransfer();
363 if( currentTransfer != null )
364 {
365 currentTransfer.setTransferToAll( transferAllCheckBox.isSelected() );
366 }
367 }} );
368
369 useXQueryCheckBox = new JCheckBox( "Use XQuery", false );
370 useXQueryCheckBox.setToolTipText( "Interprets the source xpath as an XQuery expression" );
371 useXQueryCheckBox.addChangeListener( new ChangeListener() {
372
373 public void stateChanged(ChangeEvent e)
374 {
375 PropertyTransfer currentTransfer = getCurrentTransfer();
376 if( currentTransfer != null )
377 {
378 currentTransfer.setUseXQuery( useXQueryCheckBox.isSelected() );
379 }
380 }} );
381
382 panel.add( failTransferCheckBox );
383 panel.add( setNullCheckBox );
384 panel.add( transferTextContentCheckBox );
385 panel.add( ignoreEmptyCheckBox );
386 panel.add( transferAllCheckBox );
387 panel.add( useXQueryCheckBox );
388 panel.setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) );
389 return panel;
390 }
391
392 protected JXToolBar createTargetToolbar()
393 {
394 JXToolBar toolbar;
395 toolbar = UISupport.createToolbar();
396 toolbar.addSpace( 3 );
397 toolbar.addFixed( new JLabel( "<html><b>Target:</b></html>"));
398 toolbar.addUnrelatedGap();
399
400 targetStepCombo.setSelectedItem( null );
401 targetStepCombo.setToolTipText( "The step the value will be transferred to" );
402 targetStepCombo.setEnabled( false );
403 targetStepCombo.addItemListener(
404 new StepComboItemListener( targetPropertyCombo, targetStepPropertiesListener ) );
405 targetStepCombo.addItemListener( new ItemListener() {
406
407 public void itemStateChanged(ItemEvent e)
408 {
409 if( e.getStateChange() == ItemEvent.SELECTED && !selecting )
410 {
411 TestPropertyHolder targetStep = ( TestPropertyHolder ) targetStepCombo.getSelectedItem();
412 PropertyTransfer valueTransfer = getCurrentTransfer();
413
414 if( valueTransfer != null )
415 {
416 String name = "";
417
418 if( targetStep == PropertyExpansionUtils.getGlobalProperties() )
419 name = PropertyExpansion.GLOBAL_REFERENCE;
420 else if( targetStep == transferStep.getTestCase().getTestSuite().getProject() )
421 name = PropertyExpansion.PROJECT_REFERENCE;
422 else if( targetStep == transferStep.getTestCase().getTestSuite())
423 name = PropertyExpansion.TESTSUITE_REFERENCE;
424 else if( targetStep == transferStep.getTestCase() )
425 name = PropertyExpansion.TESTCASE_REFERENCE;
426 else
427 name = targetStep.getModelItem().getName();
428
429 valueTransfer.setTargetStepName( name );
430 }
431 }
432 }} );
433
434 toolbar.add( UISupport.setFixedSize( targetStepCombo, 180, 21 ) );
435 toolbar.addUnrelatedGap();
436
437 toolbar.addFixed( new JLabel( "Property:"));
438 toolbar.addRelatedGap();
439
440 targetPropertyCombo.setToolTipText( "The property the value will be transferred to" );
441 targetPropertyCombo.setEnabled( false );
442 targetPropertyCombo.addItemListener( new ItemListener() {
443
444 public void itemStateChanged(ItemEvent e)
445 {
446 if( e.getStateChange() == ItemEvent.SELECTED && !selecting )
447 {
448 TestProperty targetProperty = (TestProperty) targetPropertyCombo.getSelectedItem();
449 PropertyTransfer valueTransfer = getCurrentTransfer();
450
451 if( valueTransfer != null )
452 {
453 valueTransfer.setTargetPropertyName( targetProperty.getName() );
454 }
455 }
456 }} );
457
458 toolbar.add( UISupport.setFixedSize( targetPropertyCombo, 180, 21 ) );
459 toolbar.addGlue();
460 return toolbar;
461 }
462
463 protected JXToolBar createSourceToolbar()
464 {
465 JXToolBar toolbar = UISupport.createToolbar();
466 toolbar.addSpace( 3 );
467 toolbar.addFixed( new JLabel( "<html><b>Source:</b></html>"));
468 toolbar.addUnrelatedGap();
469
470 sourcePropertyCombo = new JComboBox();
471 sourceStepModel = new DefaultComboBoxModel();
472 sourceStepCombo = new JComboBox( sourceStepModel );
473 sourceStepCombo.setRenderer( new StepComboRenderer() );
474 sourcePropertyCombo.setRenderer( new PropertyComboRenderer() );
475
476 componentEnabler.add( sourcePropertyCombo );
477 componentEnabler.add( sourceStepCombo );
478
479 targetPropertyCombo = new JComboBox();
480 targetStepModel = new DefaultComboBoxModel();
481 targetStepCombo = new JComboBox( targetStepModel );
482 targetStepCombo.setRenderer( new StepComboRenderer() );
483 targetPropertyCombo.setRenderer( new PropertyComboRenderer() );
484
485 componentEnabler.add( targetPropertyCombo );
486 componentEnabler.add( targetStepCombo );
487
488 sourceStepPropertiesListener = new TestStepPropertiesListener( sourcePropertyCombo );
489 targetStepPropertiesListener = new TestStepPropertiesListener( targetPropertyCombo );
490
491 sourceStepModel.addElement( PropertyExpansionUtils.getGlobalProperties() );
492 sourceStepModel.addElement( transferStep.getTestCase().getTestSuite().getProject() );
493 sourceStepModel.addElement( transferStep.getTestCase().getTestSuite() );
494 sourceStepModel.addElement( transferStep.getTestCase() );
495
496 for( int c = 0; c < transferStep.getTestCase().getTestStepCount(); c++ )
497 {
498 WsdlTestStep testStep = (WsdlTestStep) transferStep.getTestCase().getTestStepAt( c );
499 if( testStep == transferStep )
500 continue;
501
502 sourceStepModel.addElement( testStep );
503 }
504
505 for( int c = 0; c < sourceStepModel.getSize(); c++ )
506 targetStepModel.addElement( sourceStepModel.getElementAt( c ) );
507
508 sourceStepCombo.setSelectedItem( null );
509 sourceStepCombo.setToolTipText( "The step the value will be transferred from" );
510 sourceStepCombo.setEnabled( false );
511 sourceStepCombo.addItemListener(
512 new StepComboItemListener( sourcePropertyCombo, sourceStepPropertiesListener ) );
513 sourceStepCombo.addItemListener( new ItemListener() {
514
515 public void itemStateChanged(ItemEvent e)
516 {
517 if( e.getStateChange() == ItemEvent.SELECTED && !selecting )
518 {
519 TestPropertyHolder sourceStep = ( TestPropertyHolder ) sourceStepCombo.getSelectedItem();
520 PropertyTransfer valueTransfer = getCurrentTransfer();
521
522 if( valueTransfer != null )
523 {
524 String name = "";
525
526 if( sourceStep == PropertyExpansionUtils.getGlobalProperties() )
527 name = PropertyExpansion.GLOBAL_REFERENCE;
528 else if( sourceStep == transferStep.getTestCase().getTestSuite().getProject() )
529 name = PropertyExpansion.PROJECT_REFERENCE;
530 else if( sourceStep == transferStep.getTestCase().getTestSuite())
531 name = PropertyExpansion.TESTSUITE_REFERENCE;
532 else if( sourceStep == transferStep.getTestCase() )
533 name = PropertyExpansion.TESTCASE_REFERENCE;
534 else
535 name = sourceStep.getModelItem().getName();
536
537 valueTransfer.setSourceStepName( name );
538 }
539 }
540 }} );
541
542 toolbar.add( UISupport.setFixedSize( sourceStepCombo, 180, 21 ));
543 toolbar.addUnrelatedGap();
544
545 toolbar.addFixed( new JLabel( "Property:"));
546 toolbar.addRelatedGap();
547
548 sourcePropertyCombo.setToolTipText( "The property the value will be transferred from" );
549 sourcePropertyCombo.setEnabled( false );
550 sourcePropertyCombo.addItemListener( new ItemListener() {
551
552 public void itemStateChanged(ItemEvent e)
553 {
554 if( e.getStateChange() == ItemEvent.SELECTED && !selecting )
555 {
556 TestProperty sourceProperty = (TestProperty) sourcePropertyCombo.getSelectedItem();
557 PropertyTransfer valueTransfer = getCurrentTransfer();
558
559 if( valueTransfer != null )
560 {
561 valueTransfer.setSourcePropertyName( sourceProperty.getName() );
562 }
563 }
564 }} );
565
566 toolbar.add( UISupport.setFixedSize( sourcePropertyCombo, 180, 21 ) );
567 toolbar.addGlue();
568 return toolbar;
569 }
570
571 public PropertyTransfer getCurrentTransfer()
572 {
573 int ix = transferList.getSelectedIndex();
574 return ix == -1 ? null : transferStep.getTransferAt( ix );
575 }
576
577 /***
578 * Listen for testStep property changes and update properties combo accordingly
579 */
580
581 private final class TestStepPropertiesListener implements TestPropertyListener
582 {
583 private final JComboBox combo;
584
585 public TestStepPropertiesListener(JComboBox combo)
586 {
587 this.combo = combo;
588 }
589
590 public void propertyAdded(String name)
591 {
592 TestProperty property = combo == targetPropertyCombo ?
593 getCurrentTransfer().getTargetStep().getProperty( name ) :
594 getCurrentTransfer().getSourceStep().getProperty( name );
595
596 combo.addItem( property );
597 combo.setEnabled( true );
598 }
599
600 public void propertyRemoved(String name)
601 {
602 if( ((TestProperty)combo.getSelectedItem()).getName().equals( name ))
603 combo.setSelectedItem( null );
604
605 for( int c = 0; c < combo.getItemCount(); c++ )
606 {
607 if( ((TestProperty)combo.getItemAt( c )).getName().equals( name ))
608 {
609 combo.removeItemAt( c );
610 break;
611 }
612 }
613
614 combo.setEnabled( combo.getItemCount() > 0 );
615 }
616
617 public void propertyRenamed(String oldName, String newName)
618 {
619 }
620
621 public void propertyValueChanged(String name, String oldValue, String newValue)
622 {
623 }
624 }
625
626 /***
627 * Listen for teststep changes and update source/target step combos accordingly
628 */
629
630 private final class InternalTestSuiteListener extends TestSuiteListenerAdapter
631 {
632 public void testStepAdded(TestStep testStep, int index)
633 {
634 if( testStep.getTestCase() == transferStep.getTestCase() )
635 {
636 sourceStepModel.addElement( testStep );
637 targetStepModel.addElement( testStep );
638 }
639 }
640
641 public void testStepMoved(TestStep testStep, int fromIndex, int offset)
642 {
643 if( testStep.getTestCase() == transferStep.getTestCase() )
644 {
645 String testStepName = testStep.getName();
646 if( sourceStepModel.getIndexOf( testStepName ) == fromIndex )
647 {
648 String sourceStep = ( String ) sourceStepCombo.getSelectedItem();
649 String sourceProperty = ( String ) sourcePropertyCombo.getSelectedItem();
650
651 sourceStepModel.removeElementAt( fromIndex );
652 if( fromIndex + offset > sourceStepModel.getSize() )
653 sourceStepModel.addElement( testStepName );
654 else
655 sourceStepModel.insertElementAt( testStepName, fromIndex + offset );
656
657 sourceStepCombo.setSelectedItem( sourceStep );
658 sourcePropertyCombo.setSelectedItem( sourceProperty );
659 }
660
661 if( targetStepModel.getIndexOf( testStepName ) == fromIndex )
662 {
663 String targetStep = ( String ) targetStepCombo.getSelectedItem();
664 String targetProperty = ( String ) targetPropertyCombo.getSelectedItem();
665
666 targetStepModel.removeElementAt( fromIndex );
667 if( fromIndex + offset > targetStepModel.getSize() )
668 targetStepModel.addElement( testStepName );
669 else
670 targetStepModel.insertElementAt( testStepName, fromIndex + offset );
671
672 targetStepCombo.setSelectedItem( targetStep );
673 targetPropertyCombo.setSelectedItem( targetProperty );
674 }
675 }
676 }
677
678 public void testStepRemoved(TestStep testStep, int index)
679 {
680 if( testStep.getTestCase() == transferStep.getTestCase() )
681 {
682 sourceStepModel.removeElement( testStep );
683 targetStepModel.removeElement( testStep );
684 }
685 }
686 }
687
688 /***
689 * Listen to step selections and update properties combo accordingly
690 */
691
692 private final class StepComboItemListener implements ItemListener
693 {
694 private final JComboBox propertyCombo;
695 private final TestStepPropertiesListener testStepPropertiesListener;
696
697 public StepComboItemListener(final JComboBox propertyCombo, TestStepPropertiesListener testStepPropertiesListener)
698 {
699 this.propertyCombo = propertyCombo;
700 this.testStepPropertiesListener = testStepPropertiesListener;
701 }
702
703 public void itemStateChanged(ItemEvent e)
704 {
705 if( e.getStateChange() == ItemEvent.SELECTED )
706 {
707 TestPropertyHolder selectedItem = ( TestPropertyHolder ) e.getItem();
708 String[] propertyNames = selectedItem.getPropertyNames();
709
710
711 if( propertyCombo == targetPropertyCombo )
712 {
713 List<String> names = new ArrayList<String>();
714 for( String name : propertyNames )
715 {
716 TestProperty property = selectedItem.getProperty( name );
717 if( property != null && !property.isReadOnly() )
718 names.add( property.getName() );
719 }
720
721 propertyNames = names.toArray( new String[names.size()] );
722 }
723
724 DefaultComboBoxModel model = new DefaultComboBoxModel();
725 for( String name : propertyNames )
726 model.addElement( selectedItem.getProperty( name ) );
727
728 propertyCombo.setModel( model);
729 propertyCombo.setEnabled( propertyNames.length > 0 );
730
731 if( propertyCombo == targetPropertyCombo )
732 propertyCombo.setSelectedItem( getCurrentTransfer().getTargetProperty() );
733 else
734 propertyCombo.setSelectedItem( getCurrentTransfer().getSourceProperty() );
735
736 selectedItem.addTestPropertyListener( testStepPropertiesListener );
737 }
738 else
739 {
740 propertyCombo.removeAllItems();
741 propertyCombo.setEnabled( false );
742 }
743 }
744 }
745
746 /***
747 * Handle updates to source path
748 */
749
750 private final class SourceAreaDocumentListener extends DocumentListenerAdapter
751 {
752 public void update(Document document)
753 {
754 int ix = transferList.getSelectedIndex();
755 if( ix != -1 )
756 {
757 transferStep.getTransferAt( ix ).setSourcePath( sourceArea.getText() );
758 }
759 }
760 }
761
762 /***
763 * Handle updates to target path
764 */
765
766 private final class TargetAreaDocumentListener extends DocumentListenerAdapter
767 {
768 public void update( Document document )
769 {
770 int ix = transferList.getSelectedIndex();
771 if( ix != -1 )
772 {
773 transferStep.getTransferAt( ix ).setTargetPath( targetArea.getText() );
774 }
775 }
776 }
777
778 /***
779 * Listen to selection changes in transfer list and update controls accordingly
780 */
781
782 private final class TransferListSelectionListener implements ListSelectionListener
783 {
784 private PropertyTransfer transfer;
785
786 public void valueChanged(ListSelectionEvent e)
787 {
788 selecting = true;
789
790 if( transfer != null )
791 {
792 transfer.removePropertyChangeListener( transferPropertyChangeListener );
793 }
794
795 transfer = getCurrentTransfer();
796
797 if( transfer == null )
798 {
799 sourceArea.setText( "" );
800 targetArea.setText( "" );
801
802 sourcePropertyCombo.removeAllItems();
803 targetPropertyCombo.removeAllItems();
804
805 sourceStepCombo.setSelectedIndex( -1 );
806 targetStepCombo.setSelectedIndex( -1 );
807 }
808 else
809 {
810 transfer.addPropertyChangeListener( transferPropertyChangeListener );
811
812 sourceArea.setText( transfer.getSourcePath() );
813 sourceArea.setCaretPosition( 0 );
814 targetArea.setText( transfer.getTargetPath() );
815 targetArea.setCaretPosition( 0 );
816
817 sourceStepCombo.setSelectedItem( transfer.getSourceStep() );
818 sourcePropertyCombo.setSelectedItem( transfer.getSourceProperty() );
819
820 targetStepCombo.setSelectedItem( transfer.getTargetStep() );
821 targetPropertyCombo.setSelectedItem( transfer.getTargetProperty() );
822
823 failTransferCheckBox.setSelected( transfer.getFailOnError() );
824 setNullCheckBox.setSelected( transfer.getSetNullOnMissingSource() );
825 transferTextContentCheckBox.setSelected( transfer.getTransferTextContent() );
826 ignoreEmptyCheckBox.setSelected( transfer.getIgnoreEmpty() );
827 transferAllCheckBox.setSelected( transfer.getTransferToAll() );
828 useXQueryCheckBox.setSelected( transfer.getUseXQuery() );
829 }
830
831 copyButton.setEnabled( transfer != null );
832 renameButton.setEnabled( transfer != null );
833 deleteButton.setEnabled( transfer != null );
834 declareButton.setEnabled( transfer != null );
835 sourceStepCombo.setEnabled( transfer != null );
836 targetStepCombo.setEnabled( transfer != null );
837 sourceArea.setEnabled( transfer != null );
838 targetArea.setEnabled( transfer != null );
839 failTransferCheckBox.setEnabled( transfer != null );
840 setNullCheckBox.setEnabled( transfer != null );
841 transferTextContentCheckBox.setEnabled( transfer != null );
842 ignoreEmptyCheckBox.setEnabled( transfer != null );
843 transferAllCheckBox.setEnabled( transfer != null );
844 useXQueryCheckBox.setEnabled( transfer != null );
845
846 runAllButton.setEnabled( transferList.getModel().getSize() > 0 );
847 runButton.setEnabled( transfer != null );
848
849 sourcePropertyCombo.setEnabled( transfer != null );
850 targetPropertyCombo.setEnabled( transfer != null );
851
852 selecting = false;
853 }
854 }
855
856 /***
857 * Listen to property changes and update UI objects. These may have been triggered by UI so first check
858 * for actual difference so we dont end up in loop.
859 */
860
861 private class TransferPropertyChangeListener implements PropertyChangeListener
862 {
863 public void propertyChange(PropertyChangeEvent evt)
864 {
865 Object newValue = evt.getNewValue();
866
867 if( evt.getPropertyName().equals( PropertyTransfer.SOURCE_PATH_PROPERTY ))
868 {
869 if( !sourceArea.getText().equals( newValue ))
870 sourceArea.setText( (String) newValue );
871 }
872 else if( evt.getPropertyName().equals( PropertyTransfer.TARGET_PATH_PROPERTY ))
873 {
874 if( !targetArea.getText().equals( newValue ))
875 targetArea.setText( (String) newValue );
876 }
877 else if( evt.getPropertyName().equals( PropertyTransfer.SOURCE_STEP_PROPERTY ))
878 {
879 Object selectedItem = sourceStepCombo.getSelectedItem();
880 if( newValue == null || selectedItem == null || !selectedItem.equals( newValue ))
881 {
882 selecting = true;
883 sourceStepCombo.setSelectedItem( newValue );
884 selecting = false;
885 }
886 }
887 else if( evt.getPropertyName().equals( PropertyTransfer.TARGET_STEP_PROPERTY ))
888 {
889 Object selectedItem = targetStepCombo.getSelectedItem();
890 if( newValue == null || selectedItem == null || !selectedItem.equals( newValue ))
891 {
892 selecting = true;
893 targetStepCombo.setSelectedItem( newValue );
894 selecting = false;
895 }
896 }
897 else if( evt.getPropertyName().equals( PropertyTransfer.SOURCE_TYPE_PROPERTY ))
898 {
899 Object selectedItem = sourcePropertyCombo.getSelectedItem();
900 if( selectedItem == null || !selectedItem.equals( newValue ))
901 sourcePropertyCombo.setSelectedItem( newValue );
902 }
903 else if( evt.getPropertyName().equals( PropertyTransfer.TARGET_TYPE_PROPERTY ))
904 {
905 Object selectedItem = targetPropertyCombo.getSelectedItem();
906 if( selectedItem == null || !selectedItem.equals( newValue ))
907 targetPropertyCombo.setSelectedItem( newValue );
908 }
909 }
910 }
911
912 private final class AddAction extends AbstractAction
913 {
914 public AddAction()
915 {
916 putValue( Action.SHORT_DESCRIPTION, "Adds a new Property Transfer" );
917 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/add_property.gif" ));
918 }
919
920 public void actionPerformed(ActionEvent e)
921 {
922 String name = UISupport.prompt( "Specify name for value transfer", "Add Transfer", "" );
923 if( name == null || name.trim().length() == 0 ) return;
924
925 transferStep.addTransfer( name );
926
927 listModel.addElement( name );
928 transferList.setSelectedIndex( listModel.getSize()-1 );
929 }
930 }
931
932 private final class CopyAction extends AbstractAction
933 {
934 public CopyAction()
935 {
936 putValue( Action.SHORT_DESCRIPTION, "Copies the selected Property Transfer" );
937 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clone_request.gif" ));
938 }
939
940 public void actionPerformed(ActionEvent e)
941 {
942 int ix = transferList.getSelectedIndex();
943 PropertyTransfer config = transferStep.getTransferAt( ix );
944
945 String name = UISupport.prompt( "Specify name for value transfer", "Copy Transfer", config.getName() );
946 if( name == null || name.trim().length() == 0 ) return;
947
948 PropertyTransfer transfer = transferStep.addTransfer( name );
949 transfer.setSourceStepName( config.getSourceStepName() );
950 transfer.setSourcePropertyName( config.getSourcePropertyName() );
951 transfer.setSourcePath( config.getSourcePath() );
952 transfer.setTargetStepName( config.getTargetStepName() );
953 transfer.setTargetPropertyName( config.getTargetPropertyName() );
954 transfer.setTargetPath( config.getTargetPath() );
955
956 listModel.addElement( name );
957 transferList.setSelectedIndex( listModel.getSize()-1 );
958 }
959 }
960
961 private final class DeleteAction extends AbstractAction
962 {
963 public DeleteAction()
964 {
965 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/remove_property.gif" ));
966 putValue( Action.SHORT_DESCRIPTION, "Deletes the selected Property Transfer" );
967 }
968
969 public void actionPerformed(ActionEvent e)
970 {
971 if( UISupport.confirm( "Delete selected transfer", "Delete Transfer" ))
972 {
973 transferList.setSelectedIndex( -1 );
974
975 int ix = transferList.getSelectedIndex();
976 transferStep.removeTransferAt( ix );
977 listModel.remove( ix );
978
979 if( listModel.getSize() > 0 )
980 {
981 transferList.setSelectedIndex( ix > listModel.getSize()-1 ? listModel.getSize()-1 : ix );
982 }
983 }
984 }
985 }
986
987 private final class ClearLogAction extends AbstractAction
988 {
989 public ClearLogAction()
990 {
991 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clear_properties.gif" ));
992 putValue( Action.SHORT_DESCRIPTION, "Clears the property-transfer log" );
993 }
994
995 public void actionPerformed(ActionEvent e)
996 {
997 transfersTableModel.clear();
998 }
999 }
1000
1001 private final class RenameAction extends AbstractAction
1002 {
1003 public RenameAction()
1004 {
1005 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/rename.gif" ));
1006 putValue( Action.SHORT_DESCRIPTION, "Renames the selected Property Transfer" );
1007 }
1008
1009 public void actionPerformed(ActionEvent e)
1010 {
1011 PropertyTransfer transfer = getCurrentTransfer();
1012
1013 String newName = UISupport.prompt( "Specify new name for transfer", "Rename Transfer", transfer.getName() );
1014
1015 if( newName != null && !transfer.getName().equals( newName ))
1016 {
1017 listModel.setElementAt( newName, transferList.getSelectedIndex() );
1018 transfer.setName( newName );
1019 }
1020 }
1021 }
1022
1023 private final class DeclareNamespacesAction extends AbstractAction
1024 {
1025 public DeclareNamespacesAction()
1026 {
1027 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/declareNs.gif" ));
1028 putValue( Action.SHORT_DESCRIPTION, "Declare available response/request namespaces in source/target expressions" );
1029 }
1030
1031 public void actionPerformed(ActionEvent e)
1032 {
1033 try
1034 {
1035 TestPropertyHolder previousStep = getCurrentTransfer().getSourceStep();
1036
1037 if ( previousStep instanceof WsdlTestRequestStep )
1038 {
1039 WsdlTestRequest testRequest = ((WsdlTestRequestStep)previousStep).getTestRequest();
1040 sourceArea.setText( XmlUtils.declareXPathNamespaces( testRequest.getOperation().getInterface() ) + sourceArea.getText() );
1041 }
1042 else UISupport.showErrorMessage( "Property Source is not a Request" );
1043
1044 TestPropertyHolder nextStep = getCurrentTransfer().getTargetStep();
1045
1046 if (nextStep instanceof WsdlTestRequestStep)
1047 {
1048 WsdlTestRequest testRequest = ((WsdlTestRequestStep)nextStep).getTestRequest();
1049 targetArea.setText( XmlUtils.declareXPathNamespaces( testRequest.getOperation().getInterface()) + targetArea.getText() );
1050 }
1051 else UISupport.showErrorMessage( "Property Target is not a Request" );
1052 }
1053 catch (Exception e1)
1054 {
1055 UISupport.showErrorMessage( e1 );
1056 }
1057 }
1058 }
1059
1060 private final class RunAllAction extends AbstractAction
1061 {
1062 public RunAllAction()
1063 {
1064 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run_all.gif" ));
1065 putValue( Action.SHORT_DESCRIPTION, "Runs all Property Transfers" );
1066 }
1067
1068 public void actionPerformed(ActionEvent e)
1069 {
1070 if( listModel.getSize() == 0 )
1071 {
1072 UISupport.showErrorMessage( "Missing transfers!" );
1073 return;
1074 }
1075
1076 WsdlTestRunContext context = new WsdlTestRunContext( transferStep );
1077 ValueTransferResult result = (ValueTransferResult) transferStep.run( null, context );
1078 transfersTableModel.addResult( result );
1079 }
1080 }
1081
1082 private final class RunAction extends AbstractAction
1083 {
1084 public RunAction()
1085 {
1086 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run.gif" ));
1087 putValue( Action.SHORT_DESCRIPTION, "Runs selected PropertyTransfer" );
1088 }
1089
1090 public void actionPerformed(ActionEvent e)
1091 {
1092 if( transferList.getSelectedIndex() == -1 )
1093 {
1094 UISupport.showErrorMessage( "No transfer selectd!" );
1095 return;
1096 }
1097
1098 WsdlTestRunContext context = new WsdlTestRunContext( transferStep );
1099 ValueTransferResult result = (ValueTransferResult) transferStep.run( null, context, getCurrentTransfer() );
1100 transfersTableModel.addResult( result );
1101 }
1102 }
1103
1104 public boolean onClose( boolean canCancel )
1105 {
1106 super.release();
1107 transferStep.getTestCase().getTestSuite().removeTestSuiteListener( testSuiteListener );
1108 transferStep.getTestCase().removeTestRunListener( testRunListener );
1109
1110 PropertyTransfer transfer = getCurrentTransfer();
1111
1112 if( transfer != null )
1113 {
1114 transfer.removePropertyChangeListener( transferPropertyChangeListener );
1115 }
1116
1117 TestPropertyHolder item = ( TestPropertyHolder ) sourceStepCombo.getSelectedItem();
1118 if( item != null )
1119 {
1120 item.removeTestPropertyListener( sourceStepPropertiesListener );
1121 }
1122
1123 item = ( TestPropertyHolder ) targetStepCombo.getSelectedItem();
1124 if( item != null )
1125 {
1126 item.removeTestPropertyListener( targetStepPropertiesListener );
1127 }
1128
1129 componentEnabler.release();
1130 if( resultDesktopPanel != null )
1131 SoapUI.getDesktop().closeDesktopPanel( resultDesktopPanel );
1132
1133 return true;
1134 }
1135
1136 public JComponent getComponent()
1137 {
1138 return this;
1139 }
1140
1141 protected JTextArea getSourceArea()
1142 {
1143 return sourceArea;
1144 }
1145
1146 protected JTextArea getTargetArea()
1147 {
1148 return targetArea;
1149 }
1150
1151 public boolean dependsOn(ModelItem modelItem)
1152 {
1153 return modelItem == transferStep || modelItem == transferStep.getTestCase() ||
1154 modelItem == transferStep.getTestCase().getTestSuite() ||
1155 modelItem == transferStep.getTestCase().getTestSuite().getProject();
1156 }
1157
1158 public boolean selectTransfer(PropertyTransfer transfer)
1159 {
1160 for( int c = 0; c < transferStep.getTransferCount(); c++ )
1161 {
1162 if( transferStep.getTransferAt( c ) == transfer )
1163 {
1164 transferList.setSelectedIndex( c );
1165 return true;
1166 }
1167 }
1168
1169 return false;
1170 }
1171
1172 private class TransfersTableModel extends AbstractTableModel
1173 {
1174 private List<ValueTransferResult> results = new ArrayList<ValueTransferResult>();
1175
1176 public synchronized int getRowCount()
1177 {
1178 int sum = 0;
1179 for( ValueTransferResult result : results )
1180 {
1181 sum += result.getTransferCount();
1182 }
1183
1184 return sum;
1185 }
1186
1187 public synchronized void clear()
1188 {
1189 results.clear();
1190 fireTableDataChanged();
1191 logInspector.setTitle( "Transfer Log (0)" );
1192 }
1193
1194 public synchronized void addResult( ValueTransferResult result )
1195 {
1196 int rowCount = getRowCount();
1197 results.add( result );
1198 fireTableRowsInserted( rowCount, rowCount + result.getTransferCount() );
1199
1200 logInspector.setTitle( "Transfer Log (" + getRowCount() + ")" );
1201 inspectorPanel.activate( logInspector );
1202 }
1203
1204 public int getColumnCount()
1205 {
1206 return 3;
1207 }
1208
1209 public String getColumnName(int column)
1210 {
1211 switch( column )
1212 {
1213 case 0 : return "Timestamp";
1214 case 1 : return "Transfer Name";
1215 case 2 : return "Transferred Values";
1216 }
1217
1218 return null;
1219 }
1220
1221 public synchronized Object getValueAt(int rowIndex, int columnIndex)
1222 {
1223
1224 ValueTransferResult result = null;
1225 int sum = 0;
1226
1227 for( int c = 0; c < results.size(); c++ )
1228 {
1229 if( sum + results.get( c ).getTransferCount() > rowIndex )
1230 {
1231 result = results.get( c );
1232 break;
1233 }
1234 else
1235 {
1236 sum += results.get( c ).getTransferCount();
1237 }
1238 }
1239
1240 if( result != null )
1241 {
1242 switch( columnIndex )
1243 {
1244 case 0 : return new Date( result.getTimeStamp() ).toString();
1245 case 1 : return result.getTransferAt( rowIndex-sum ).getName();
1246 case 2 : return Arrays.toString( result.getTransferredValuesAt( rowIndex-sum ) );
1247 }
1248 }
1249
1250 return null;
1251 }
1252
1253 }
1254
1255 private class InternalTestRunListener extends TestRunListenerAdapter
1256 {
1257 @Override
1258 public void afterStep( TestRunner testRunner, TestRunContext runContext, TestStepResult result )
1259 {
1260 if( result.getTestStep() == transferStep )
1261 {
1262 transfersTableModel.addResult( ( ValueTransferResult ) result );
1263 }
1264 }
1265 }
1266
1267 private class StepComboRenderer extends DefaultListCellRenderer
1268 {
1269 @Override
1270 public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus )
1271 {
1272 Component result = super.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
1273
1274 if( value instanceof TestModelItem )
1275 {
1276 TestModelItem item = ( TestModelItem ) value;
1277 setIcon( item.getIcon() );
1278 setText( item.getName() );
1279 }
1280 else if( value == PropertyExpansionUtils.getGlobalProperties())
1281 {
1282 setText( "Global" );
1283 }
1284
1285 return result;
1286 }
1287 }
1288
1289 private class PropertyComboRenderer extends DefaultListCellRenderer
1290 {
1291 @Override
1292 public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus )
1293 {
1294 Component result = super.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
1295
1296 if( value != null )
1297 {
1298 TestProperty item = ( TestProperty ) value;
1299 setText( item.getName() );
1300 }
1301
1302 return result;
1303 }
1304 }
1305 }