source: vlo/branches/to-wicket-1.6/vlo_web_app/src/main/java/eu/clarin/cmdi/vlo/pages/ShowResultPage.java @ 4240

Last change on this file since 4240 was 4240, checked in by twagoo, 10 years ago

Replaced calls getting session (either on component or statically) and casting to VloSession? with new convenience method VloSession?.get()

File size: 23.3 KB
Line 
1package eu.clarin.cmdi.vlo.pages;
2
3import eu.clarin.cmdi.vlo.FacetConstants;
4import eu.clarin.cmdi.vlo.Resources;
5import eu.clarin.cmdi.vlo.StringUtils;
6import eu.clarin.cmdi.vlo.VloSession;
7import eu.clarin.cmdi.vlo.config.VloConfig;
8import eu.clarin.cmdi.vlo.dao.DaoLocator;
9import java.io.InputStreamReader;
10import java.io.StringWriter;
11import java.io.UnsupportedEncodingException;
12import java.net.MalformedURLException;
13import java.net.URL;
14import java.net.URLEncoder;
15import java.util.ArrayList;
16import java.util.Collection;
17import java.util.HashMap;
18import java.util.Iterator;
19import java.util.List;
20import java.util.regex.Pattern;
21import javax.xml.transform.stream.StreamSource;
22import net.sf.saxon.s9api.Processor;
23import net.sf.saxon.s9api.Serializer;
24import net.sf.saxon.s9api.XdmNode;
25import net.sf.saxon.s9api.XsltCompiler;
26import net.sf.saxon.s9api.XsltExecutable;
27import net.sf.saxon.s9api.XsltTransformer;
28import org.apache.solr.common.SolrDocument;
29import org.apache.wicket.Application;
30import org.apache.wicket.Component;
31import org.apache.wicket.request.mapper.parameter.PageParameters;
32import org.apache.wicket.behavior.Behavior;
33import org.apache.wicket.extensions.ajax.markup.html.AjaxLazyLoadPanel;
34import org.apache.wicket.extensions.markup.html.basic.SmartLinkMultiLineLabel;
35import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
36import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
37import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
38import org.apache.wicket.extensions.markup.html.repeater.data.table.HeadersToolbar;
39import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
40import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
41import org.apache.wicket.markup.ComponentTag;
42import org.apache.wicket.markup.MarkupStream;
43import org.apache.wicket.markup.head.IHeaderResponse;
44import org.apache.wicket.markup.head.JavaScriptHeaderItem;
45import org.apache.wicket.markup.html.WebMarkupContainer;
46import org.apache.wicket.markup.html.basic.Label;
47import org.apache.wicket.markup.html.link.BookmarkablePageLink;
48import org.apache.wicket.markup.html.link.ExternalLink;
49import org.apache.wicket.markup.repeater.Item;
50import org.apache.wicket.markup.repeater.RepeatingView;
51import org.apache.wicket.model.IModel;
52import org.apache.wicket.model.ResourceModel;
53import org.apache.wicket.request.Url;
54import org.apache.wicket.request.cycle.RequestCycle;
55import org.apache.wicket.util.encoding.UrlDecoder;
56import org.apache.wicket.util.encoding.UrlEncoder;
57import org.slf4j.Logger;
58import org.slf4j.LoggerFactory;
59
60/**
61 * Page showing VLO search results
62 *
63 * @author keeloo, for the addLandingPage links method and annotations
64 */
65public class ShowResultPage extends BasePage {
66
67    private final static Logger LOG = LoggerFactory.getLogger(ShowResultPage.class);
68    public static final String PARAM_DOC_ID = "docId";
69    public static final String feedbackfromURL = VloConfig.getFeedbackFromUrl();
70
71    private final URL xslFile = getClass().getResource("/cmdi2xhtml.xsl");
72
73    @SuppressWarnings("serial")
74    public ShowResultPage(final PageParameters currentParam) {
75        super(currentParam);
76        //Document ID is assumed to have been encoded (typcially in DocumentLinkPanel) decode here
77        final String docId = UrlDecoder.QUERY_INSTANCE.decode(
78                getPageParameters().get(PARAM_DOC_ID).toString(),
79                Application.get().getRequestCycleSettings().getResponseRequestEncoding()); // get current character set from request cycle
80        SolrDocument solrDocument = DaoLocator.getSearchResultsDao().getSolrDocument(docId);
81        if (solrDocument != null) {
82            final SearchPageQuery query = new SearchPageQuery(currentParam);
83
84            // create parameters from the query, and add them with session related parameters
85            PageParameters newParam = new PageParameters(query.getPageParameters());
86            // add the session persistent parameters
87            newParam.mergeWith(VloSession.get().getVloSessionPageParameters());
88
89            BookmarkablePageLink<String> backLink = new BookmarkablePageLink<String>("backLink", FacetedSearchPage.class, newParam);
90            add(backLink);
91            String href = getHref(docId);
92            if (href != null) {
93                add(new ExternalLink("openBrowserLink", href, new ResourceModel(Resources.OPEN_IN_ORIGINAL_CONTEXT).getObject()));
94            } else {
95                add(new Label("openBrowserLink", new ResourceModel(Resources.ORIGINAL_CONTEXT_NOT_AVAILABLE).getObject()));
96            }
97            addAttributesTable(solrDocument);
98
99            /* If there are any, add the link or links to landing pages
100             * contained in the solr document.
101             */
102            addLandingPageLinks(solrDocument);
103
104            // also, if there are any, add the link or links to search pages
105            addSearchPageLinks(solrDocument);
106
107            // add the rest of the resource links to the result page
108            addResourceLinks(solrDocument);
109
110            addSearchServiceForm(solrDocument);
111            addCompleteCmdiView(solrDocument);
112
113            add(new AjaxLazyLoadPanel("prevNextHeader") {
114
115                @Override
116                public Component getLazyLoadComponent(String markupId) {
117                    return new PrevNextHeaderPanel(markupId, docId, query);
118                }
119
120                @Override
121                public Component getLoadingComponent(String markupId) {
122                    return new PrevNextHeaderPanel(markupId);
123                }
124            });
125        } else {
126            setResponsePage(new ResultNotFoundPage(currentParam));
127        }
128
129        // add the feedback link to the result page
130        addFeedbackLink(currentParam);
131    }
132
133    private String getHref(String linkToOriginalContext) {
134        String result = linkToOriginalContext;
135        if (linkToOriginalContext != null) {
136            if (linkToOriginalContext.startsWith(FacetConstants.TEST_HANDLE_MPI_PREFIX)) {
137                linkToOriginalContext = linkToOriginalContext.replace(FacetConstants.TEST_HANDLE_MPI_PREFIX, FacetConstants.HANDLE_MPI_PREFIX);
138            }
139            if (linkToOriginalContext.startsWith(FacetConstants.HANDLE_MPI_PREFIX)) {
140                result = VloConfig.getIMDIBrowserUrl(linkToOriginalContext);
141            } else {
142                try {
143                    new URL(linkToOriginalContext);
144                } catch (MalformedURLException e) {
145                    LOG.debug("Link to original context is incorrect:", e);
146                    result = null;
147                }
148            }
149        }
150        return result;
151    }
152
153    /*
154     * Based on the solr document, create a table of meta data attribute and value pairs
155     */
156    private void addAttributesTable(final SolrDocument solrDocument) {
157        // because of FIELD_LANGUAGE_LINK, remove the FIELD_LANDGUAGE facet
158        solrDocument.remove(FacetConstants.FIELD_LANGUAGE);
159        /* Use the data provider from the solrDocument object as a provider
160         * for the table to be instantiated here.
161         */
162        DocumentAttributesDataProvider attributeProvider = new DocumentAttributesDataProvider(solrDocument);
163
164        DataTable table;
165        /* Create table: use the provider, and pass a method to create the
166         * columns.
167         */
168        table = new DataTable("attributesTable", createAttributesColumns(), attributeProvider, 250);
169        // associate css with table
170        table.setTableBodyCss("attributesTbody");
171        table.addTopToolbar(new HeadersToolbar(table, null));
172        // add table to page
173        add(table);
174    }
175
176    /**
177     * Create the columns for the table.
178     *
179     * Create one column for the attributes and one column for their values.
180     *
181     * @newParam
182     */
183    private List<IColumn> createAttributesColumns() {
184        List<IColumn> columns = new ArrayList<IColumn>();
185
186        // create the column for the attribute names
187        IColumn column = null;
188        column = new PropertyColumn<Object, Object>(new ResourceModel(Resources.FIELD), "field") {
189
190            @Override
191            public String getCssClass() {
192                return "attribute";
193            }
194        };
195        columns.add(column);
196
197        // create the column for the values of the attributes
198        column = new AbstractColumn<DocumentAttribute, String>(new ResourceModel(Resources.VALUE)) {
199            @Override
200            public void populateItem(Item<ICellPopulator<DocumentAttribute>> cellItem,
201                    String componentId, IModel<DocumentAttribute> rowModel) {
202
203                /*
204                 * While in the data for the table, the values (for the
205                 * description) attribute are structured. Creating a single
206                 * attribute, these values are collapsed. Refer to the
207                 *
208                 * DocumentAttribute
209                 *
210                 * class.
211                 */
212                DocumentAttribute attribute = rowModel.getObject();
213
214                if (attribute.getField().equals(FacetConstants.FIELD_LANGUAGES)) {
215                    cellItem.add(new SmartLinkMultiLineLabel(componentId, attribute.getValue()) {
216                        @Override
217                        public void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag) {
218                            setEscapeModelStrings(false);
219                            CharSequence body = getDefaultModelObjectAsString();
220                            replaceComponentTagBody(markupStream, openTag, body);
221                        }
222                    });
223                } else if (attribute.getField().equals(FacetConstants.FIELD_COMPLETE_METADATA)) {
224                    cellItem.add(new SmartLinkMultiLineLabel(componentId, attribute.getValue()) {
225                        @Override
226                        public void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag) {
227                            setEscapeModelStrings(false);
228                            CharSequence body = getDefaultModelObjectAsString();
229                            replaceComponentTagBody(markupStream, openTag, "<a href=\"" + body + "\">" + body + "</a>");
230                        }
231                    });
232                } else {
233                    cellItem.add(new SmartLinkMultiLineLabel(componentId, attribute.getValue()) {
234                        @Override
235                        public void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag) {
236                            CharSequence body = StringUtils.toMultiLineHtml(getDefaultModelObjectAsString());
237                            replaceComponentTagBody(markupStream, openTag, getSmartLink(body));
238                        }
239                    });
240                }
241            }
242
243            @Override
244            public String getCssClass() {
245                return "attributeValue";
246            }
247        };
248        columns.add(column);
249
250        return columns;
251    }
252
253    /**
254     * Add landing page links to the result page.
255     *
256     * @newParam solrDocument the document to get the links from
257     */
258    private void addLandingPageLinks(SolrDocument solrDocument) {
259
260        Label oneLandingPageText;
261        oneLandingPageText = new Label("oneLandingPage",
262                new ResourceModel(Resources.LANDING_PAGE).getObject() + ":");
263        this.add(oneLandingPageText);
264
265        Label moreLandingPagesText;
266        moreLandingPagesText = new Label("moreLandingPages",
267                new ResourceModel(Resources.LANDING_PAGES).getObject() + ":");
268        this.add(moreLandingPagesText);
269
270        RepeatingView repeatingView = new RepeatingView("landingPageList");
271        add(repeatingView);
272
273        /*
274         * Depending on the number of links to be shown, at most one of the
275         * labels in the accompanying HTML page that is subject to Wicket is
276         * made visible.
277         */
278        if (!solrDocument.containsKey(FacetConstants.FIELD_LANDINGPAGE)) {
279
280            /* Since there are no links to be shown, make both labels defined in
281             * the page invisible
282             */
283            oneLandingPageText.setVisible(false);
284            moreLandingPagesText.setVisible(false);
285        } else {
286            //  make one of the two labels invisible
287
288            Collection<Object> landingPages
289                    = solrDocument.getFieldValues(FacetConstants.FIELD_LANDINGPAGE);
290            if (landingPages.size() > 1) {
291
292                // the list will contain more than one landing page link
293                oneLandingPageText.setVisible(false);
294                moreLandingPagesText.setVisible(true);
295            } else {
296                // the list will contain exactly one landing page link.
297                oneLandingPageText.setVisible(true);
298                moreLandingPagesText.setVisible(false);
299            }
300
301            // generate the list of links
302            for (Iterator<Object> it = landingPages.iterator(); it.hasNext();) {
303                final Object landingPage;
304                landingPage = it.next();
305
306                // add a link to the list
307                repeatingView.add(
308                        new AjaxLazyLoadPanel(repeatingView.newChildId()) {
309                            @Override
310                            public Component getLazyLoadComponent(String markupId) {
311                                String landingPageLink;
312                                landingPageLink = landingPage.toString();
313
314                                // create a panel for the link
315                                return new LandingPageLinkPanel(markupId,
316                                        landingPage.toString());
317                            }
318                        });
319            }
320        }
321    }
322
323    /**
324     * Add search page links to the result page.
325     *
326     * @newParam solrDocument the document to get the links from
327     */
328    private void addSearchPageLinks(SolrDocument solrDocument) {
329
330        Label oneSearchPageText;
331        oneSearchPageText = new Label("oneSearchPage",
332                new ResourceModel(Resources.SEARCH_PAGE).getObject() + ":");
333        this.add(oneSearchPageText);
334
335        Label moreSearchPagesText;
336        moreSearchPagesText = new Label("moreSearchPages",
337                new ResourceModel(Resources.SEARCH_PAGES).getObject() + ":");
338        this.add(moreSearchPagesText);
339
340        RepeatingView repeatingView = new RepeatingView("searchPageList");
341        add(repeatingView);
342
343        /*
344         * Depending on the number of links to be shown, at most one of the
345         * labels in the accompanying HTML page that is subject to Wicket is
346         * made visible.
347         */
348        if (!solrDocument.containsKey(FacetConstants.FIELD_SEARCHPAGE)) {
349
350            /* Since there are no links to be shown, make both labels defined in
351             * the page invisible
352             */
353            oneSearchPageText.setVisible(false);
354            moreSearchPagesText.setVisible(false);
355        } else {
356            //  make one of the two labels invisible
357
358            Collection<Object> searchPages
359                    = solrDocument.getFieldValues(FacetConstants.FIELD_SEARCHPAGE);
360            if (searchPages.size() > 1) {
361
362                // the list will contain more than one landing page link
363                oneSearchPageText.setVisible(false);
364                moreSearchPagesText.setVisible(true);
365            } else {
366                // the list will contain exactly one landing page link.
367                oneSearchPageText.setVisible(true);
368                moreSearchPagesText.setVisible(false);
369            }
370
371            // generate the list of links
372            for (Iterator<Object> it = searchPages.iterator(); it.hasNext();) {
373                final Object searchPage;
374                searchPage = it.next();
375
376                // add a link to the list
377                repeatingView.add(
378                        new AjaxLazyLoadPanel(repeatingView.newChildId()) {
379                            @Override
380                            public Component getLazyLoadComponent(String markupId) {
381                                String searchPageLink;
382                                searchPageLink = searchPage.toString();
383
384                                // create a panel for the link
385                                return new SearchPageLinkPanel(markupId,
386                                        searchPage.toString());
387                            }
388                        });
389            }
390        }
391    }
392
393    /**
394     * Add links to resources other than search or landing pages to the result
395     * page.
396     *
397     * @newParam solrDocument the document to get the links from
398     */
399    private void addResourceLinks(SolrDocument solrDocument) {
400        RepeatingView repeatingView = new RepeatingView("resourceList");
401        add(repeatingView);
402        if (solrDocument.containsKey(FacetConstants.FIELD_RESOURCE)) {
403            Collection<Object> resources = solrDocument.getFieldValues(FacetConstants.FIELD_RESOURCE);
404            if (resources.size() > 1) {
405                repeatingView.add(new Label(repeatingView.newChildId(), new ResourceModel(Resources.RESOURCE_PL)));
406            } else {
407                repeatingView.add(new Label(repeatingView.newChildId(), new ResourceModel(Resources.RESOURCE)));
408            }
409            for (Object resource : resources) {
410                String[] split = resource.toString().split(Pattern.quote(FacetConstants.FIELD_RESOURCE_SPLIT_CHAR), 2);
411                final String mimeType = split[0];
412                final String resourceLink = split[1];
413                repeatingView.add(new AjaxLazyLoadPanel(repeatingView.newChildId()) {
414
415                    @Override
416                    public Component getLazyLoadComponent(String markupId) {
417                        return new ResourceLinkPanel(markupId, mimeType, resourceLink);
418                    }
419                });
420            }
421        } else {
422            repeatingView.add(new Label(repeatingView.newChildId(), new ResourceModel(Resources.NO_RESOURCE_FOUND)));
423        }
424    }
425
426    private void addFeedbackLink(final PageParameters parameters) {
427
428        PageParameters newParam = new PageParameters(parameters);
429        // add the session persistent paremeters
430        newParam.mergeWith(VloSession.get().getVloSessionPageParameters());
431
432        final RequestCycle reqCycle = getRequestCycle();
433        // the following will not be necessary anymore
434        // final Url reqUrl = Url.parse(reqCycle.urlFor(ShowResultPage.class, newParam.convert()));
435        final Url reqUrl = Url.parse(reqCycle.urlFor(ShowResultPage.class, newParam));
436        String thisURL = reqCycle.getUrlRenderer().renderFullUrl(reqUrl);
437
438        try {
439            thisURL = URLEncoder.encode(thisURL, "UTF-8");
440        } catch (UnsupportedEncodingException e) {
441            LOG.error(e.toString());
442        }
443
444        // Image resourceImg = new Image("feedbackImage", FEEDBACK_IMAGE.getResource());
445        // String title = "Report an error";
446        // resourceImg.add(new SimpleAttributeModifier("title", title));
447        // resourceImg.add(new SimpleAttributeModifier("alt", title));
448        String href = getHref(feedbackfromURL + thisURL);
449        String name = feedbackfromURL + thisURL;
450        ExternalLink link = new ExternalLink("feedbackLink", href, "found an error?");
451        // link.add(resourceImg);
452        // add(new Label("feedbackLabel", "Found an error?"));
453        add(link);
454    }
455
456    public static BookmarkablePageLink<ShowResultPage> createBookMarkableLink(String linkId, SearchPageQuery query, String docId) {
457
458        // create new page parameters from the query parameters and the session related ones
459        PageParameters newParam;
460        newParam = new PageParameters(query.getPageParameters());
461        newParam.add(ShowResultPage.PARAM_DOC_ID, UrlEncoder.QUERY_INSTANCE.encode(
462                docId,
463                Application.get().getRequestCycleSettings().getResponseRequestEncoding())); // get current character set from request cycle
464        // add the session persistent parameters
465        newParam.mergeWith(VloSession.get().getVloSessionPageParameters());
466        BookmarkablePageLink<ShowResultPage> docLink = new BookmarkablePageLink<ShowResultPage>(linkId, ShowResultPage.class,
467                newParam);
468        return docLink;
469    }
470
471    /**
472     * Add contentSearch form (FCS)
473     *
474     * @newParam solrDocument
475     */
476    private void addSearchServiceForm(final SolrDocument solrDocument) {
477        final WebMarkupContainer contentSearchContainer = new WebMarkupContainer("contentSearch");
478        add(contentSearchContainer);
479
480        if (solrDocument.containsKey(FacetConstants.FIELD_SEARCH_SERVICE)) {
481            try {
482                // building map (CQL endpoint -> List with resource ID)
483                HashMap<String, List<String>> aggregrationContextMap = new HashMap<String, List<String>>();
484                List<String> idList = new ArrayList<String>();
485                idList.add(solrDocument.getFirstValue(FacetConstants.FIELD_ID).toString());
486                aggregrationContextMap.put(solrDocument.getFirstValue(FacetConstants.FIELD_SEARCH_SERVICE).toString(), idList);
487                Label contentSearchLabel = new Label("contentSearchForm", HtmlFormCreator.getContentSearchForm(aggregrationContextMap, "Plain text search via Federated Content Search"));
488                contentSearchLabel.setEscapeModelStrings(false);
489                contentSearchContainer.add(contentSearchLabel);
490            } catch (UnsupportedEncodingException uee) {
491                contentSearchContainer.setVisible(false);
492            }
493        } else {
494            contentSearchContainer.setVisible(false);
495        }
496    }
497
498    /**
499     * Add complete CMDI view
500     *
501     * @newParam solrDocument
502     */
503    private void addCompleteCmdiView(final SolrDocument solrDocument) {
504        StringWriter strWriter = new StringWriter();
505
506        final Processor proc = new Processor(false);
507        final XsltCompiler comp = proc.newXsltCompiler();
508
509        try {
510            final XsltExecutable exp = comp.compile(new StreamSource(xslFile.getFile()));
511            final XdmNode source = proc.newDocumentBuilder().build(
512                    new StreamSource(new InputStreamReader(new URL(solrDocument.getFirstValue(FacetConstants.FIELD_COMPLETE_METADATA).toString()).openStream())));
513            final Serializer out = new Serializer();
514            out.setOutputProperty(Serializer.Property.METHOD, "html");
515            out.setOutputProperty(Serializer.Property.INDENT, "yes");
516            out.setOutputProperty(Serializer.Property.ENCODING, "UTF-8");
517            out.setOutputWriter(strWriter);
518            final XsltTransformer trans = exp.load();
519
520            trans.setInitialContextNode(source);
521            trans.setDestination(out);
522            trans.transform();
523        } catch (Exception e) {
524            LOG.error("Couldn't create CMDI metadata: " + e.getMessage());
525            strWriter = new StringWriter().append("<b>Could not load complete CMDI metadata</b>");
526        }
527
528        Label completeCmdiLabel = new Label("completeCmdi", strWriter.toString());
529        completeCmdiLabel.setEscapeModelStrings(false);
530        add(completeCmdiLabel);
531
532        // remove complete CMDI view on page load
533        add(new Behavior() {
534            private static final long serialVersionUID = 1865219352602175954L;
535
536            public void renderHead(IHeaderResponse response) {
537                response.render(JavaScriptHeaderItem.forScript("toogleDiv('completeCmdi', 'toogleLink')", null));
538            }
539        });
540    }
541}
Note: See TracBrowser for help on using the repository browser.