source: FCSEndpointTester/trunk/src/main/java/eu/clarin/fcs/tester/ui/TesterUI.java @ 7196

Last change on this file since 7196 was 7196, checked in by Oliver Schonefeld, 6 years ago
  • rewrite to use SRUClient instead of SRUSimpleClient
  • add Tests for Endpoint Description (FCS 1.0 and FCS 2.0)
  • Property svn:eol-style set to native
File size: 19.4 KB
Line 
1/**
2 * This software is copyright (c) 2013-2016 by
3 *  - Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
4 * This is free software. You can redistribute it
5 * and/or modify it under the terms described in
6 * the GNU General Public License v3 of which you
7 * should have received a copy. Otherwise you can download
8 * it from
9 *
10 *   http://www.gnu.org/licenses/gpl-3.0.txt
11 *
12 * @copyright Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
13 *
14 * @license http://www.gnu.org/licenses/gpl-3.0.txt
15 *  GNU General Public License v3
16 */
17package eu.clarin.fcs.tester.ui;
18
19import java.io.IOException;
20import java.net.MalformedURLException;
21import java.net.URL;
22import java.util.List;
23
24import javax.servlet.ServletContext;
25import javax.servlet.http.Cookie;
26
27import org.slf4j.Logger;
28import org.slf4j.LoggerFactory;
29import org.vaadin.hene.popupbutton.PopupButton;
30
31import com.vaadin.annotations.PreserveOnRefresh;
32import com.vaadin.annotations.Theme;
33import com.vaadin.annotations.Title;
34import com.vaadin.annotations.Widgetset;
35import com.vaadin.data.Validator;
36import com.vaadin.data.Validator.InvalidValueException;
37import com.vaadin.server.ErrorMessage;
38import com.vaadin.server.UserError;
39import com.vaadin.server.VaadinRequest;
40import com.vaadin.server.VaadinService;
41import com.vaadin.server.VaadinServlet;
42import com.vaadin.shared.ui.MarginInfo;
43import com.vaadin.shared.ui.label.ContentMode;
44import com.vaadin.ui.Alignment;
45import com.vaadin.ui.Button;
46import com.vaadin.ui.Button.ClickEvent;
47import com.vaadin.ui.CheckBox;
48import com.vaadin.ui.ComboBox;
49import com.vaadin.ui.Component;
50import com.vaadin.ui.FormLayout;
51import com.vaadin.ui.HorizontalLayout;
52import com.vaadin.ui.Label;
53import com.vaadin.ui.Notification;
54import com.vaadin.ui.Panel;
55import com.vaadin.ui.TextField;
56import com.vaadin.ui.UI;
57import com.vaadin.ui.VerticalLayout;
58
59import eu.clarin.fcs.tester.FCSEndpointTester;
60import eu.clarin.fcs.tester.FCSTestContext;
61import eu.clarin.fcs.tester.FCSTestProfile;
62import eu.clarin.fcs.tester.FCSTestResult;
63
64
65@SuppressWarnings("serial")
66@PreserveOnRefresh
67@Theme("clarin")
68@Title("CLARIN-FCS endpoint conformance tester")
69@Widgetset("eu.clarin.fcs.tester.ui.Widgetset")
70public class TesterUI extends UI {
71    private static final String PARAM_DEFAULT_ENDPOINT_URI =
72            "eu.clarin.fcs.tester.defaultEndpointURI";
73    private static final String PARAM_DEFAULT_SEARCH_TERM =
74            "eu.clarin.fcs.tester.defaultSearchTerm";
75    private static final String COOKIE_NAME_ENDPOINT_URI =
76            "lastEndpointURI";
77    private static final String COOKIE_NAME_SEARCH_TERM =
78            "lastSearchTerm";
79    private static final Logger logger =
80            LoggerFactory.getLogger(TesterUI.class);
81    private static final ErrorMessage ERROR_INVALID_INPUT =
82            new UserError("Invalid input:");
83    private TextField uriField;
84    private TextField queryField;
85    private ComboBox profileCombo;
86    private CheckBox strictModeCheckbox;
87    private CheckBox performProbeCheckbox;
88    private ComboBox connectTimeoutCombo;
89    private ComboBox socketTimeoutCombo;
90    private Panel content;
91    private int pollingRequests = 0;
92
93
94    @Override
95    protected void init(VaadinRequest request) {
96        logger.debug("init(): remoteAddr={}, session={}",
97                request.getRemoteAddr(), request.getWrappedSession().getId());
98
99        final ServletContext ctx =
100                VaadinServlet.getCurrent().getServletContext();
101
102        final VerticalLayout layout = new VerticalLayout();
103        layout.setSizeFull();
104        layout.setMargin(true);
105        layout.setSpacing(false);
106        layout.setStyleName("small-margin");
107        setContent(layout);
108
109        final Label title = new Label(
110                "<h1>CLARIN-FCS endpoint conformance tester</h1>",
111                ContentMode.HTML);
112        title.setStyleName("header");
113        layout.addComponent(title);
114
115        /*
116         * input panel
117         */
118        final HorizontalLayout top = new HorizontalLayout();
119        top.setSpacing(true);
120        top.setMargin(new MarginInfo(false, true, false, true));
121        top.setWidth("100%");
122        top.setStyleName("small-margin");
123
124        final FormLayout inputForm = new FormLayout();
125        top.addComponent(inputForm);
126        top.setComponentAlignment(inputForm, Alignment.MIDDLE_LEFT);
127        top.setExpandRatio(inputForm, 1.0f);
128
129        uriField = new TextField("Endpoint BaseURI:");
130        uriField.setWidth("100%");
131        uriField.setInputPrompt("Please enter BaseURI of endpoint.");
132        uriField.setRequiredError("An endpoint BaseURI is required!");
133        uriField.setMaxLength(255);
134        uriField.setNullRepresentation("");
135        uriField.setRequired(true);
136        uriField.addValidator(new Validator() {
137            @Override
138            public void validate(Object value) throws InvalidValueException {
139                if (value != null) {
140                    String s = (String) value;
141                    s = s.trim();
142                    if (!s.isEmpty()) {
143                        try {
144                            new URL(s);
145                        } catch (MalformedURLException e) {
146                            throw new InvalidValueException("Invalid URI syntax!");
147                        }
148                    }
149                }
150            }
151        });
152        String defaultEndpointURI = getCookie(COOKIE_NAME_ENDPOINT_URI);
153        if (defaultEndpointURI == null) {
154            defaultEndpointURI =
155                    ctx.getInitParameter(PARAM_DEFAULT_ENDPOINT_URI);
156            if (defaultEndpointURI != null) {
157                defaultEndpointURI = defaultEndpointURI.trim();
158                if (defaultEndpointURI.isEmpty()) {
159                    defaultEndpointURI = null;
160                }
161            }
162        }
163
164        uriField.setValue(defaultEndpointURI);
165        inputForm.addComponent(uriField);
166
167        queryField = new TextField("Search Term:");
168        queryField.setWidth("100%");
169        queryField.setInputPrompt("Please enter a word that occurs at least once in you data.");
170        queryField.setMaxLength(64);
171        queryField.setNullRepresentation("");
172        queryField.setRequired(true);
173        queryField.setRequiredError("A search term is required!");
174
175        String defaultSearchTerm = getCookie(COOKIE_NAME_SEARCH_TERM);
176        if (defaultSearchTerm == null) {
177            defaultSearchTerm = ctx.getInitParameter(PARAM_DEFAULT_SEARCH_TERM);
178            if (defaultSearchTerm != null) {
179                defaultSearchTerm = defaultSearchTerm.trim();
180            }
181        }
182        queryField.setValue(defaultSearchTerm);
183        inputForm.addComponent(queryField);
184
185        final Button goButton = new Button("Go");
186        top.addComponent(goButton);
187        top.setComponentAlignment(goButton, Alignment.MIDDLE_LEFT);
188
189        /* options panel */
190        final VerticalLayout optionsContent = new VerticalLayout();
191        optionsContent.setMargin(true);
192        optionsContent.setSpacing(true);
193        optionsContent.setStyleName("small-margin");
194
195        profileCombo = new ComboBox("CLARIN-FCS test profile:");
196        profileCombo.addItem(PROFILE_AUTODETECT);
197        profileCombo.setItemCaption(PROFILE_AUTODETECT, "Auto detect");
198        profileCombo.addItem(PROFILE_FCS_LEGACY);
199        profileCombo.setItemCaption(PROFILE_FCS_LEGACY, "Legacy FCS");
200        profileCombo.addItem(PROFILE_FCS_1_0);
201        profileCombo.setItemCaption(PROFILE_FCS_1_0, "CLARIN-FCS 1.0");
202        profileCombo.addItem(PROFILE_FCS_2_0);
203        profileCombo.setItemCaption(PROFILE_FCS_2_0, "CLARIN-FCS 2.0");
204        profileCombo.select(PROFILE_AUTODETECT);
205        profileCombo.setNullSelectionAllowed(false);
206        profileCombo.setTextInputAllowed(false);
207        profileCombo.setWidth("100%");
208        optionsContent.addComponent(profileCombo);
209
210        strictModeCheckbox = new CheckBox("Perform checks in strict mode");
211        strictModeCheckbox.setWidth("100%");
212        strictModeCheckbox.setValue(Boolean.TRUE);
213        optionsContent.addComponent(strictModeCheckbox);
214
215        performProbeCheckbox = new CheckBox("Perform HTTP HEAD probe request");
216        performProbeCheckbox.setWidth("100%");
217        performProbeCheckbox.setValue(Boolean.TRUE);
218        optionsContent.addComponent(performProbeCheckbox);
219
220        connectTimeoutCombo = new ComboBox("Connect timeout:");
221        fillTimeoutCombo(connectTimeoutCombo);
222        connectTimeoutCombo.select(TIMEOUT_15_SECONDS);
223        connectTimeoutCombo.setNullSelectionAllowed(false);
224        connectTimeoutCombo.setTextInputAllowed(false);
225        connectTimeoutCombo.setWidth("100%");
226        optionsContent.addComponent(connectTimeoutCombo);
227
228        socketTimeoutCombo = new ComboBox("Socket timeout:");
229        fillTimeoutCombo(socketTimeoutCombo);
230        socketTimeoutCombo.select(TIMEOUT_30_SECONDS);
231        socketTimeoutCombo.setNullSelectionAllowed(false);
232        socketTimeoutCombo.setTextInputAllowed(false);
233        socketTimeoutCombo.setWidth("100%");
234        optionsContent.addComponent(socketTimeoutCombo);
235
236//        final Table x = new Table("Custom Request Parameters");
237//        x.setWidth("100%");
238//        x.setHeight("200px");
239//        // x.setIt
240//        IndexedContainer data = new IndexedContainer();
241//        data.addContainerProperty("KEY", String.class, "");
242//        data.addContainerProperty("VALUE", String.class, "");
243//
244//        Object id1 = data.addItem();
245//        data.getContainerProperty(id1, "KEY").setValue("key1");
246//        data.getContainerProperty(id1, "VALUE").setValue("value1");
247//
248//        x.setContainerDataSource(data);
249//        optionsContent.addComponent(x);
250//
251//        HorizontalLayout addLayout = new HorizontalLayout();
252//        addLayout.setSpacing(true);
253//        final TextField keyField = new TextField();
254//        addLayout.addComponent(keyField);
255//        final TextField valueField = new TextField();
256//        addLayout.addComponent(valueField);
257//        final Button addButton = new Button("Add");
258//        addLayout.addComponent(addButton);
259//        optionsContent.addComponent(addLayout);
260
261        final PopupButton optionsButton = new PopupButton("Options");
262        optionsButton.setContent(optionsContent);
263        top.addComponent(optionsButton);
264        top.setComponentAlignment(optionsButton, Alignment.MIDDLE_LEFT);
265        layout.addComponent(top);
266
267        /*
268         * main content
269         */
270        content = new Panel();
271        content.setSizeFull();
272        content.setStyleName("main-content");
273        layout.addComponent(content);
274        layout.setExpandRatio(content, 1.0f);
275
276        setNoResultsView();
277
278        /* setup up some behaviors */
279        goButton.addClickListener(new Button.ClickListener() {
280            @Override
281            public void buttonClick(ClickEvent event) {
282                boolean valid = true;
283                try {
284                    uriField.validate();
285                    uriField.setComponentError(null);
286                } catch (InvalidValueException e) {
287                    valid = false;
288                    uriField.setComponentError(ERROR_INVALID_INPUT);
289                }
290                try {
291                    queryField.validate();
292                    queryField.setComponentError(null);
293                } catch (InvalidValueException e) {
294                    valid = false;
295                    queryField.setComponentError(ERROR_INVALID_INPUT);
296                }
297
298                if (valid) {
299                    performAction();
300                }
301
302            }
303        });
304
305        uriField.focus();
306
307//        final Notification info =
308//                new Notification("The CLARIN-FCS endpoint conformance tester does" +
309//                        " not yet support the new FCS specification!",
310//                        Notification.Type.ERROR_MESSAGE);
311//        info.setDelayMsec(5000);
312//        info.setDescription("(Dismiss this message by clicking it)");
313//        info.show(Page.getCurrent());
314    }
315
316
317    @Override
318    public void detach() {
319        setPollInterval(-1);
320        super.detach();
321    }
322
323
324    void enablePolling() {
325        if (++pollingRequests > 0) {
326            setPollInterval(250);
327        }
328    }
329
330
331    void disablePolling() {
332        if (--pollingRequests <= 0) {
333            setPollInterval(-1);
334            pollingRequests = 0;
335        }
336    }
337
338
339    private void setNoResultsView() {
340        Component component = content.getContent();
341        if ((component == null) ||
342                !component.getClass().equals(NoResultsView.class)) {
343            content.setContent(new NoResultsView());
344        }
345    }
346
347
348    private void performAction() {
349        FCSTestProfile profile = null;
350        switch (((Integer) profileCombo.getValue()).intValue()) {
351        case PROFILE_FCS_1_0:
352            profile = FCSTestProfile.CLARIN_FCS_1_0;
353            break;
354        case PROFILE_FCS_2_0:
355            profile = FCSTestProfile.CLARIN_FCS_2_0;
356            break;
357        case PROFILE_FCS_LEGACY:
358            profile = FCSTestProfile.CLARIN_FCS_LEGACY;
359            break;
360        default:
361            /* DO NOTHING */
362        }
363
364        final String endpointURI = uriField.getValue();
365        final String searchTerm = queryField.getValue();
366        final boolean strictMode =
367                strictModeCheckbox.getValue().booleanValue();
368        final boolean performProbeRequest =
369                performProbeCheckbox.getValue().booleanValue();
370        final int connectTimeout =
371                ((Integer) connectTimeoutCombo.getValue()).intValue();
372        final int socketTimeout =
373                ((Integer) socketTimeoutCombo.getValue()).intValue();
374
375        setCookie(COOKIE_NAME_ENDPOINT_URI, endpointURI);
376        setCookie(COOKIE_NAME_SEARCH_TERM, searchTerm);
377
378        logger.info("perform check for: profile={}, endpointURI={} query={}, strict={}",
379                profile, endpointURI, searchTerm, (strictMode ? "yes" : "no"));
380
381        final FCSEndpointTester tester = FCSEndpointTester.getInstance();
382
383        final ProgressWindow progressWindow = new ProgressWindow(
384                "Checking SRU/CQL endpoint ....", "Initializing ...");
385        setNoResultsView();
386        addWindow(progressWindow);
387
388        final FCSEndpointTester.ProgressListener listener =
389                new FCSEndpointTester.ProgressListener() {
390            private int test = -1;
391            @Override
392            public void updateProgress(final String message) {
393                accessSynchronously(new Runnable() {
394                    @Override
395                    public void run() {
396                        progressWindow.updateStatus(message, test);
397                        if (test != -1) {
398                            test++;
399                        }
400                    }
401                });
402            }
403
404            @Override
405            public void updateMaximum(final int maximum) {
406                accessSynchronously(new Runnable() {
407                    @Override
408                    public void run() {
409                        if (maximum > 0) {
410                            progressWindow.updateMaximum(maximum);
411                            test = 0;
412                        }
413                    }
414                });
415            }
416
417            @Override
418            public void onDone(final FCSTestContext context,
419                    final List<FCSTestResult> results) {
420                // force update of status bar
421                accessSynchronously(new Runnable() {
422                    @Override
423                    public void run() {
424                        progressWindow.updateStatus("Rendering results ...",
425                                Integer.MAX_VALUE);
426                    }
427                });
428
429                // render results
430                accessSynchronously(new Runnable() {
431                    @Override
432                    public void run() {
433                        content.setContent(
434                                new ResultsView(context, results));
435                        progressWindow.close();
436                    }
437                });
438            }
439
440
441            @Override
442            public void onError(final String message, Throwable t) {
443                final String desc = (t != null) ? t.getMessage() : null;
444                accessSynchronously(new Runnable() {
445                    @Override
446                    public void run() {
447                        setNoResultsView();
448                        progressWindow.close();
449                        Notification.show(message, desc,
450                                Notification.Type.ERROR_MESSAGE);
451                    }
452                });
453            }
454        };
455
456        /*
457         * now finally submit to tester for running ...
458         */
459        tester.performTests(listener,
460                    profile,
461                    endpointURI,
462                    searchTerm,
463                    strictMode,
464                    performProbeRequest,
465                    connectTimeout,
466                    socketTimeout);
467    }
468
469
470    private void readObject(java.io.ObjectInputStream in) throws IOException,
471            ClassNotFoundException {
472        in.defaultReadObject();
473        setNoResultsView();
474    }
475
476
477    private String getCookie(String name) {
478        Cookie[] cookies = VaadinService.getCurrentRequest().getCookies();
479        if (cookies != null) {
480            for (Cookie cookie : cookies) {
481                if (name.equals(cookie.getName())) {
482                    String s = cookie.getValue();
483                    if (s != null) {
484                        s = s.trim();
485                        if (s.isEmpty()) {
486                            s = null;
487                        }
488                        return s;
489                    }
490                }
491            }
492        }
493        return null;
494    }
495
496
497    private void setCookie(String name, String value) {
498        Cookie cookie = new Cookie(name, value);
499        cookie.setMaxAge(Integer.MAX_VALUE);
500        cookie.setPath(VaadinService.getCurrentRequest().getContextPath());
501        VaadinService.getCurrentResponse().addCookie(cookie);
502    }
503
504    private static final int PROFILE_AUTODETECT  = 1;
505    private static final int PROFILE_FCS_1_0     = 2;
506    private static final int PROFILE_FCS_2_0     = 3;
507    private static final int PROFILE_FCS_LEGACY = 4;
508
509    private static final int TIMEOUT_5_SECONDS   =   5 * 1000;
510    private static final int TIMEOUT_10_SECONDS  =  10 * 1000;
511    private static final int TIMEOUT_15_SECONDS  =  15 * 1000;
512    private static final int TIMEOUT_30_SECONDS  =  30 * 1000;
513    private static final int TIMEOUT_60_SECONDS  =  60 * 1000;
514    private static final int TIMEOUT_120_SECONDS = 120 * 1000;
515    private static final int TIMEOUT_180_SECONDS = 180 * 1000;
516    private static final int TIMEOUT_300_SECONDS = 300 * 1000;
517
518    private void fillTimeoutCombo(ComboBox combo) {
519        combo.addItem(TIMEOUT_5_SECONDS);
520        combo.setItemCaption(TIMEOUT_5_SECONDS, "5 seconds");
521        combo.addItem(TIMEOUT_10_SECONDS);
522        combo.setItemCaption(TIMEOUT_10_SECONDS, "10 seconds");
523        combo.addItem(TIMEOUT_15_SECONDS);
524        combo.setItemCaption(TIMEOUT_15_SECONDS, "15 seconds");
525        combo.addItem(TIMEOUT_30_SECONDS);
526        combo.setItemCaption(TIMEOUT_30_SECONDS, "30 seconds");
527        combo.addItem(TIMEOUT_60_SECONDS);
528        combo.setItemCaption(TIMEOUT_60_SECONDS, "1 minute");
529        combo.addItem(TIMEOUT_120_SECONDS);
530        combo.setItemCaption(TIMEOUT_120_SECONDS, "2 minutes");
531        combo.addItem(TIMEOUT_180_SECONDS);
532        combo.setItemCaption(TIMEOUT_180_SECONDS, "3 minutes");
533        combo.addItem(TIMEOUT_300_SECONDS);
534        combo.setItemCaption(TIMEOUT_300_SECONDS, "5 minutes");
535    }
536
537} // class TesterUI
Note: See TracBrowser for help on using the repository browser.