Changeset 6123 for SRUAggregator


Ignore:
Timestamp:
04/01/15 13:04:47 (9 years ago)
Author:
emanuel.dima@uni-tuebingen.de
Message:
  1. beta-31: support for query&mode params, and for x-aggregation-context on POST
Location:
SRUAggregator/trunk
Files:
9 edited
1 moved

Legend:

Unmodified
Added
Removed
  • SRUAggregator/trunk/pom.xml

    r6111 r6123  
    88        <groupId>eu.clarin.sru.fcs</groupId>
    99        <artifactId>Aggregator2</artifactId>
    10         <version>2.0.0-beta-30</version>
     10        <version>2.0.0-beta-31</version>
    1111        <name>FCS Aggregator</name>
    1212
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/app/Aggregator.java

    r6093 r6123  
    3434import java.util.concurrent.ScheduledExecutorService;
    3535import java.util.concurrent.atomic.AtomicReference;
     36import org.eclipse.jetty.server.session.SessionHandler;
    3637import org.slf4j.LoggerFactory;
    3738
     
    4849 * If invoked with 'x-aggregation-context' and 'query' parameter, the aggregator
    4950 * will pre-select provided resources and fill in the query field. This
    50  * mechanism is currently used by VLO. Example: POST
    51  * http://weblicht.sfs.uni-tuebingen.de/Aggregator HTTP/1.1 operation =
    52  * searchRetrieve & version = 1.2 & query = bellen & x-aggregation-context =
     51 * mechanism is currently used by VLO.
     52 *
     53 * Example: POST
     54 * http://weblicht.sfs.uni-tuebingen.de/Aggregator HTTP/1.1
     55 * query = bellen & x-aggregation-context =
    5356 * {"http://fedora.clarin-d.uni-saarland.de/sru/":["hdl:11858/00-246C-0000-0008-5F2A-0"]}
    5457 *
    55  *
    56  * Additionally, if run with the a URL query string parameter 'mode', the
    57  * special behavior of the aggregator is triggered:
    58  *
    59  * /?mode=testing corresponds to the mode where the CQL endpoints are taken not
    60  * from Clarin center repository, but from a hard-coded endpoints list; this
    61  * functionality is useful for testing the development instances of endpoints,
    62  * before they are moved to production. Was done to meet the request from MPI.
    63  *
    64  * /?mode=search corresponds to the mode where the aggregator page is requested
    65  * with the already known query and (optionally) resources to search in, and if
    66  * the immediate search is desired. In this case the aggregator search results
    67  * page is displayed and search results of the provided query start to fill it
    68  * in immediately (i.e. users don't need to click 'search' in the aggregator
    69  * page). Was done to meet the request from CLARIN ERIC (Martin Wynne contacted
    70  * us).
    71  *
    72  * /?mode=live corresponds to the mode where the information about corpora are
    73  * taken not from the scan cache (crawled in advance), but loaded live, starting
    74  * from the request to center registry and then performing scan operation
    75  * requests on each CQL endpoint listed there. It takes time to get the
    76  * corresponding responses from the endpoints, therefore the Aggregator page
    77  * loads very slow in this mode. But this mode is useful for testing of the
    78  * newly added or changed corpora without waiting for the next crawl.
    79  *
    80  *
    81  * Adds Application initialization and clean up: only one SRU threaded client is
    82  * used in the application, it has to be shut down when the application stops.
    83  * One Languages object instance is used within the application.
     58 * If the Aggregator web page has the URL query string parameter 'mode'
     59 * set to the string 'search', and the 'query' parameter is set,
     60 * then the aggregator search results for this query are immediately displayed
     61 * (i.e. users don't need to click 'search' in the aggregator page).
     62 * This feature has been requested initially by Martin Wynne from CLARIN ERIC
    8463 *
    8564 * @author Yana Panchenko
    8665 * @author edima
    8766 *
    88  * TODO: add the modes described above (except live)
     67 * TODO: improve help page text
    8968 *
    9069 * TODO: update comments everywhere
     
    10382 *
    10483 * TODO: tri-state for parent collections; search + message implications
    105  *
    106  * TODO: improve help page text
    10784 *
    10885 */
     
    161138                }
    162139
    163                 environment.getApplicationContext().setErrorHandler(new ErrorPageHandler());
     140                environment.getApplicationContext().setSessionHandler(new SessionHandler());
     141                environment.getApplicationContext().setErrorHandler(new ErrorHandler());
    164142                environment.jersey().setUrlPattern("/rest/*");
    165143                environment.jersey().register(new RestService());
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/app/ErrorHandler.java

    r6044 r6123  
    11package eu.clarin.sru.fcs.aggregator.app;
    22
    3 import java.util.ArrayList;
    4 import java.util.List;
     3import com.fasterxml.jackson.databind.ObjectMapper;
     4import java.io.IOException;
     5import javax.servlet.RequestDispatcher;
     6import javax.servlet.ServletException;
    57import javax.servlet.http.HttpServletRequest;
    6 import javax.ws.rs.ext.Provider;
    7 import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
     8import javax.servlet.http.HttpServletResponse;
     9import org.eclipse.jetty.http.HttpMethod;
     10import org.eclipse.jetty.server.Request;
     11import org.slf4j.LoggerFactory;
    812
    913/**
     
    1115 * @author edima
    1216 */
    13 @Provider
    14 public class ErrorPageHandler extends ErrorPageErrorHandler {
     17public class ErrorHandler extends org.eclipse.jetty.server.handler.ErrorHandler {
    1518
    16         List<String> staticRoutes;
     19        private static final org.slf4j.Logger log = LoggerFactory.getLogger(Aggregator.class);
    1720
    18         public ErrorPageHandler() {
    19                 staticRoutes = new ArrayList<String>();
    20                 staticRoutes.add("/rest");
    21                 staticRoutes.add("/admin");
    22                 staticRoutes.add("/lib");
    23                 staticRoutes.add("/js");
    24                 staticRoutes.add("/fonts");
    25                 staticRoutes.add("/img");
     21        private final String redirectRoute = "/index.html";
     22
     23        @Override
     24        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException {
     25                // On 404 page we need to show index.html and let JS router do the work, otherwise show error page
     26                if (response.getStatus() == HttpServletResponse.SC_NOT_FOUND) {
     27                        forward(redirectRoute, baseRequest, response);
     28                } else if (request.getMethod().equals("POST")
     29                                && response.getStatus() == HttpServletResponse.SC_METHOD_NOT_ALLOWED
     30                                && request.getParameterValues("x-aggregation-context") != null) {
     31
     32                        // this request must come from VLO
     33                        String[] queryValues = request.getParameterValues("query");
     34                        if (queryValues != null && queryValues.length > 0) {
     35                                baseRequest.getSession().setAttribute("query", queryValues[0]);
     36                        }
     37
     38                        String[] contextValues = request.getParameterValues("x-aggregation-context");
     39                        if (contextValues != null && contextValues.length > 0) {
     40                                baseRequest.getSession().setAttribute("x-aggregation-context", contextValues[0]);
     41                        }
     42
     43                        baseRequest.setMethod(HttpMethod.GET, HttpMethod.GET.asString());
     44
     45                        forward(redirectRoute, baseRequest, response);
     46                } else {
     47                        super.handle(target, baseRequest, request, response);
     48                }
    2649        }
    2750
    28         static boolean prefix(String url, String prefix) {
    29                 return url.equals(prefix) || url.startsWith(prefix + "/") || url.startsWith(prefix + "?");
    30         }
    31 
    32         @Override
    33         public String getErrorPage(HttpServletRequest request) {
    34                 String url = request.getPathInfo();
    35                 for (String pre : staticRoutes) {
    36                         if (prefix(url, pre)) {
    37                                 return null;
     51        void forward(String target, Request request, HttpServletResponse response) throws IOException {
     52                RequestDispatcher dispatcher = request.getRequestDispatcher(target);
     53                if (dispatcher != null) {
     54                        try {
     55                                response.reset();
     56                                dispatcher.forward(request, response);
     57                        } catch (ServletException e) {
     58                                super.handle(target, request, request, response);
    3859                        }
     60                } else {
     61                        log.error("Can not find internal redirect route '" + target + "' while handling error. Will show system error page");
     62                        super.handle(target, request, request, response);
    3963                }
    40                 return "/index.html";
    4164        }
    4265}
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/rest/RestService.java

    r6092 r6123  
    8181        @GET
    8282        @Path("init")
    83         public Response getInit() throws IOException {
     83        public Response getInit(@Context HttpServletRequest request) throws IOException {
    8484                log.info("get initial data");
    8585                final Corpora corpora = Aggregator.getInstance().getCorpora();
     86                final Object contextString = request.getSession().getAttribute("x-aggregation-context");
     87                final Object query = request.getSession().getAttribute("query");
     88                final Object mode = request.getSession().getAttribute("mode");
    8689                Object j = new HashMap<String, Object>() {
    8790                        {
     91                                if (query != null) {
     92                                        put("query", query);
     93                                }
     94                                if (contextString instanceof String) {
     95                                        Object context = new ObjectMapper().readValue((String) contextString, Object.class);
     96                                        put("x-aggregation-context", context); // preselected corpora
     97                                }
    8898                                put("corpora", corpora.getCorpora());
    8999                                put("languages", LanguagesISO693.getInstance().getLanguageMap(corpora.getLanguages()));
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/search/Exports.java

    r6081 r6123  
    168168                        return null;
    169169                } else {
    170                         WLData data;
    171                         MetaData md = new MetaData();
    172170                        String lang = LanguagesISO693.getInstance().code_1ForCode_3(searchLanguage);
    173171                        if (filterLanguage != null) {
     
    176174                        TextCorpusStored tc = new TextCorpusStored(lang);
    177175                        tc.createTextLayer().addText(text);
    178                         data = new WLData(md, tc);
     176                        WLData data = new WLData(new MetaData(), tc);
    179177                        ByteArrayOutputStream os = new ByteArrayOutputStream();
    180178                        try {
  • SRUAggregator/trunk/src/main/resources/assets/index.html

    r6081 r6123  
    4646        <div id="main-container">
    4747                <div id="body"></div>
     48                <!-- <div>
     49                        <form id="contentSearchForm" method="post" name="fcsForm" target="_blank" action="http://localhost:4019/Aggregator-testing/">
     50                        <fieldset style="border:0px;">
     51                            <input type="hidden" name="query" id="query" value="">
     52                            <input type="hidden" name="x-aggregation-context" value="{&quot;http://cqlservlet.mpi.nl/&quot;: [&quot;tla.mpi.nl:collections:childes&quot;]}">
     53                            <input type="hidden" name="operation" value="searchRetrieve">
     54                            <input type="hidden" name="version" value="1.2">
     55                        </fieldset>
     56                    </form>
     57                    <a href="#" onclick="document.fcsForm.submit();">Plain text search via Federated Content Search</a>
     58                </div> -->
    4859                <div id="footer"></div>
    4960        </div>
  • SRUAggregator/trunk/src/main/resources/assets/js/main.js

    r6111 r6123  
    33"use strict";
    44
    5 var VERSION = window.MyAggregator.VERSION = "VERSION 2.0.0-beta-30";
     5var VERSION = window.MyAggregator.VERSION = "VERSION 2.0.0-beta-31";
    66var URLROOT = window.MyAggregator.URLROOT = "/Aggregator-testing";
    77
     
    1313var Main = React.createClass({displayName: 'Main',
    1414        componentWillMount: function() {
    15                 routeFromLocation.bind(this);
     15                routeFromLocation.bind(this)();
    1616        },
    1717
     
    111111        },
    112112
    113         toAggregator: function(doPushHistory) { this.gotoPage(doPushHistory, ''); },
     113        toAggregator: function(doPushHistory, query) { this.gotoPage(doPushHistory, ''); },
    114114        toHelp: function(doPushHistory) { this.gotoPage(doPushHistory, 'help'); },
    115115        toAbout: function(doPushHistory) { this.gotoPage(doPushHistory, 'about'); },
     
    557557window.onpopstate = routeFromLocation.bind(main);
    558558
    559 routeFromLocation.bind(main)();
     559// routeFromLocation.bind(main)();
    560560
    561561})();
    562 
    563 
    564 
    565 
    566 
    567 
    568 
  • SRUAggregator/trunk/src/main/resources/assets/js/main.jsx

    r6111 r6123  
    33"use strict";
    44
    5 var VERSION = window.MyAggregator.VERSION = "VERSION 2.0.0-beta-30";
     5var VERSION = window.MyAggregator.VERSION = "VERSION 2.0.0-beta-31";
    66var URLROOT = window.MyAggregator.URLROOT = "/Aggregator-testing";
    77
     
    1313var Main = React.createClass({
    1414        componentWillMount: function() {
    15                 routeFromLocation.bind(this);
     15                routeFromLocation.bind(this)();
    1616        },
    1717
     
    557557window.onpopstate = routeFromLocation.bind(main);
    558558
    559 routeFromLocation.bind(main)();
    560 
    561559})();
    562 
    563 
    564 
    565 
    566 
    567 
    568 
  • SRUAggregator/trunk/src/main/resources/assets/js/search.js

    r6111 r6123  
    4444        sampa: layers[1],
    4545};
     46
     47function getQueryVariable(variable) {
     48    var query = window.location.search.substring(1);
     49    var vars = query.split('&');
     50    for (var i = 0; i < vars.length; i++) {
     51        var pair = vars[i].split('=');
     52        if (decodeURIComponent(pair[0]) == variable) {
     53            return decodeURIComponent(pair[1]);
     54        }
     55    }
     56    return null;
     57}
    4658
    4759function Corpora(corpora, updateFn) {
     
    139151};
    140152
     153Corpora.prototype.setAggregationContext = function(endpoints2handles) {
     154        console.log('setAggregationContext', endpoints2handles, this.corpora);
     155
     156        var recurseSelect = function(select, corpus) {
     157                corpus.selected = false;
     158                this.recurseCorpora(corpus.subCorpora, function(c) { c.selected = corpus.selected; });
     159        };
     160
     161        this.corpora.forEach(recurseSelect.bind(this, false));
     162
     163        var corporaToSelect = [];
     164        _.pairs(endpoints2handles).forEach(function(endp){
     165                var endpoint = endp[0];
     166                var handles = endp[1];
     167                handles.forEach(function(handle){
     168                        this.recurse(function(corpus){
     169                                if (corpus.handle === handle) {
     170                                        corporaToSelect.push(corpus);
     171                                }
     172                        }.bind(this));
     173                }.bind(this));
     174        }.bind(this));
     175
     176        corporaToSelect.forEach(recurseSelect.bind(this, true));
     177};
     178
    141179Corpora.prototype.getSelectedIds = function() {
    142180        var ids = [];
     
    189227                        languageMap: {},
    190228                        weblichtLanguages: [],
    191                         query: "",
     229                        query: getQueryVariable('query') || '',
    192230                        language: this.anyLanguage,
    193231                        languageFilter: 'byMeta',
     
    208246                        success: function(json, textStatus, jqXHR) {
    209247                                if (this.isMounted()) {
     248                                        var corpora = new Corpora(json.corpora, this.updateCorpora);
    210249                                        this.setState({
    211                                                 corpora : new Corpora(json.corpora, this.updateCorpora),
     250                                                corpora : corpora,
    212251                                                languageMap: json.languages,
    213252                                                weblichtLanguages: json.weblichtLanguages,
     253                                                query: this.state.query || json.query || '',
    214254                                        });
     255
     256                                        if (json['x-aggregation-context']) {
     257                                                console.log("x-aggregation-context: ", json["x-aggregation-context"]);
     258                                                corpora.setAggregationContext(json["x-aggregation-context"]);
     259                                                corpora.update();
     260                                        }
     261
     262                                        if (getQueryVariable('mode') === 'search' ||
     263                                                json.mode === 'search') {
     264                                                        this.search();
     265                                        }
    215266                                }
    216267                        }.bind(this),
     
    433484                if (this.props.embedded) {
    434485                        var query = this.state.query;
    435                         var newurl = query ? (window.MyAggregator.URLROOT + "?search=" + query) : "#";
     486                        var newurl = !query ? "#" :
     487                                (window.MyAggregator.URLROOT + "?" + encodeQueryData({query:query, mode:'search'}));
    436488                        return (
    437489                                React.createElement("a", {className: "btn btn-default input-lg", type: "button", target: "_blank", href: newurl},
  • SRUAggregator/trunk/src/main/resources/assets/js/search.jsx

    r6111 r6123  
    4444        sampa: layers[1],
    4545};
     46
     47function getQueryVariable(variable) {
     48    var query = window.location.search.substring(1);
     49    var vars = query.split('&');
     50    for (var i = 0; i < vars.length; i++) {
     51        var pair = vars[i].split('=');
     52        if (decodeURIComponent(pair[0]) == variable) {
     53            return decodeURIComponent(pair[1]);
     54        }
     55    }
     56    return null;
     57}
    4658
    4759function Corpora(corpora, updateFn) {
     
    139151};
    140152
     153Corpora.prototype.setAggregationContext = function(endpoints2handles) {
     154        console.log('setAggregationContext', endpoints2handles, this.corpora);
     155
     156        var recurseSelect = function(select, corpus) {
     157                corpus.selected = false;
     158                this.recurseCorpora(corpus.subCorpora, function(c) { c.selected = corpus.selected; });
     159        };
     160
     161        this.corpora.forEach(recurseSelect.bind(this, false));
     162
     163        var corporaToSelect = [];
     164        _.pairs(endpoints2handles).forEach(function(endp){
     165                var endpoint = endp[0];
     166                var handles = endp[1];
     167                handles.forEach(function(handle){
     168                        this.recurse(function(corpus){
     169                                if (corpus.handle === handle) {
     170                                        corporaToSelect.push(corpus);
     171                                }
     172                        }.bind(this));
     173                }.bind(this));
     174        }.bind(this));
     175
     176        corporaToSelect.forEach(recurseSelect.bind(this, true));
     177};
     178
    141179Corpora.prototype.getSelectedIds = function() {
    142180        var ids = [];
     
    189227                        languageMap: {},
    190228                        weblichtLanguages: [],
    191                         query: "",
     229                        query: getQueryVariable('query') || '',
    192230                        language: this.anyLanguage,
    193231                        languageFilter: 'byMeta',
     
    208246                        success: function(json, textStatus, jqXHR) {
    209247                                if (this.isMounted()) {
     248                                        var corpora = new Corpora(json.corpora, this.updateCorpora);
    210249                                        this.setState({
    211                                                 corpora : new Corpora(json.corpora, this.updateCorpora),
     250                                                corpora : corpora,
    212251                                                languageMap: json.languages,
    213252                                                weblichtLanguages: json.weblichtLanguages,
     253                                                query: this.state.query || json.query || '',
    214254                                        });
     255
     256                                        if (json['x-aggregation-context']) {
     257                                                console.log("x-aggregation-context: ", json["x-aggregation-context"]);
     258                                                corpora.setAggregationContext(json["x-aggregation-context"]);
     259                                                corpora.update();
     260                                        }
     261
     262                                        if (getQueryVariable('mode') === 'search' ||
     263                                                json.mode === 'search') {
     264                                                        this.search();
     265                                        }
    215266                                }
    216267                        }.bind(this),
     
    433484                if (this.props.embedded) {
    434485                        var query = this.state.query;
    435                         var newurl = query ? (window.MyAggregator.URLROOT + "?search=" + query) : "#";
     486                        var newurl = !query ? "#" :
     487                                (window.MyAggregator.URLROOT + "?" + encodeQueryData({query:query, mode:'search'}));
    436488                        return (
    437489                                <a className="btn btn-default input-lg" type="button" target="_blank" href={newurl}>
Note: See TracChangeset for help on using the changeset viewer.