def testSruTermDrilldown(self):
        sruTermDrilldown = SruTermDrilldown()

        drilldownData = [
                {'fieldname': 'field0', 'terms': [{'term': 'value0_0', 'count': 14}]},
                {'fieldname': 'field1', 'terms': [{'term': 'value1_0', 'count': 13}, {'term': 'value1_1', 'count': 11}]},
                {'fieldname': 'field2', 'terms': [{'term': 'value2_0', 'count': 3}, {'term': 'value2_1', 'count': 2}, {'term': 'value2_2', 'count': 1}]}
        ]

        response = ''.join(compose(sruTermDrilldown.extraResponseData(drilldownData, sruArguments={})))

        self.assertEqualsWS(DRILLDOWN_HEADER + """<dd:term-drilldown><dd:navigator name="field0">
    <dd:item count="14">value0_0</dd:item>
</dd:navigator>
<dd:navigator name="field1">
    <dd:item count="13">value1_0</dd:item>
    <dd:item count="11">value1_1</dd:item>
</dd:navigator>
<dd:navigator name="field2">
    <dd:item count="3">value2_0</dd:item>
    <dd:item count="2">value2_1</dd:item>
    <dd:item count="1">value2_2</dd:item>
</dd:navigator></dd:term-drilldown></dd:drilldown>""", response)

        xsdFilename = self._getXsdFilename(response)
        assertValid(response, join(schemasPath, xsdFilename))
    def testEchoedExtraRequestDataWithJsonFormat(self):
        component = SruTermDrilldown()

        result = "".join(
            list(
                component.echoedExtraRequestData(sruArguments={
                    'x-term-drilldown': ['field0/field1,field2', 'field3'],
                    'version':
                    '1.1',
                    'x-drilldown-format': ['json']
                },
                                                 version='1.1')))

        self.assertEqualsWS(_DRILLDOWN_HEADER % _DRILLDOWN_XSD_2013 + """
            <dd:request>
                <dd:x-term-drilldown>field0/field1</dd:x-term-drilldown>
                <dd:x-term-drilldown>field2</dd:x-term-drilldown>
                <dd:x-term-drilldown>field3</dd:x-term-drilldown>
                <dd:x-drilldown-format>json</dd:x-drilldown-format>
            </dd:request>""" +\
            DRILLDOWN_FOOTER, result)

        xsdFilename = self._getXsdFilename(result)
        assertValid(result, join(schemasPath, xsdFilename))
        with open(join(schemasPath, xsdFilename)) as fp:
            assertValid(fp.read(), join(schemasPath, 'XMLSchema.xsd'))
    def testEchoedExtraRequestData(self):
        component = SruTermDrilldown()

        result = "".join(list(component.echoedExtraRequestData(sruArguments={'x-term-drilldown': ['field0,field1'], 'version': '1.1'}, version='1.1')))

        self.assertEqualsWS(DRILLDOWN_HEADER \
        + """<dd:term-drilldown>field0,field1</dd:term-drilldown>"""\
        + DRILLDOWN_FOOTER, result)
    def testSruTermDrilldown(self):
        sruTermDrilldown = SruTermDrilldown()

        drilldownData = [{
            'fieldname': 'field0',
            'terms': [{
                'term': 'value0_0',
                'count': 14
            }]
        }, {
            'fieldname':
            'field1',
            'terms': [{
                'term': 'value1_0',
                'count': 13
            }, {
                'term': 'value1_1',
                'count': 11
            }]
        }, {
            'fieldname':
            'field2',
            'terms': [{
                'term': 'value2_0',
                'count': 3
            }, {
                'term': 'value2_1',
                'count': 2
            }, {
                'term': 'value2_2',
                'count': 1
            }]
        }]

        response = ''.join(
            compose(
                sruTermDrilldown.extraResponseData(drilldownData,
                                                   sruArguments={})))

        self.assertEqualsWS(
            DRILLDOWN_HEADER +
            """<dd:term-drilldown><dd:navigator name="field0">
    <dd:item count="14">value0_0</dd:item>
</dd:navigator>
<dd:navigator name="field1">
    <dd:item count="13">value1_0</dd:item>
    <dd:item count="11">value1_1</dd:item>
</dd:navigator>
<dd:navigator name="field2">
    <dd:item count="3">value2_0</dd:item>
    <dd:item count="2">value2_1</dd:item>
    <dd:item count="1">value2_2</dd:item>
</dd:navigator></dd:term-drilldown></dd:drilldown>""", response)

        xsdFilename = self._getXsdFilename(response)
        assertValid(response, join(schemasPath, xsdFilename))
    def testEchoedExtraRequestDataWithEmptyTermDrilldownFormat(self):
        component = SruTermDrilldown(defaultFormat=FORMAT_XML)

        result = "".join(
            list(
                component.echoedExtraRequestData(sruArguments={
                    'x-term-drilldown': [''],
                    'version': '1.1'
                },
                                                 version='1.1')))

        self.assertEqualsWS("", result)
    def testEchoedExtraRequestData(self):
        component = SruTermDrilldown()

        result = "".join(
            list(
                component.echoedExtraRequestData(sruArguments={
                    'x-term-drilldown': ['field0,field1'],
                    'version':
                    '1.1'
                },
                                                 version='1.1')))

        self.assertEqualsWS(DRILLDOWN_HEADER \
        + """<dd:term-drilldown>field0,field1</dd:term-drilldown>"""\
        + DRILLDOWN_FOOTER, result)
    def testDrilldownNoResults(self):
        sruTermDrilldown = SruTermDrilldown()
        drilldownData = [
                {'fieldname': 'field0', 'terms': []},
            ]

        composedGenerator = compose(sruTermDrilldown.extraResponseData(drilldownData, sruArguments={}))
        result = "".join(composedGenerator)

        expected = DRILLDOWN_HEADER + """
            <dd:term-drilldown>
                <dd:navigator name="field0"/>
            </dd:term-drilldown>
        """ + DRILLDOWN_FOOTER
        self.assertEqualsWS(expected, result)
    def testWrongFormat(self):
        sruTermDrilldown = SruTermDrilldown()
        drilldownData = [
                {
                    'fieldname': 'field0',
                    'terms': [
                        {
                            'term': 'value0',
                            'count': 1,
                        }
                    ]
                }
            ]

        response = parse(StringIO(''.join(compose(sruTermDrilldown.extraResponseData(drilldownData, sruArguments={'x-drilldown-format':'text'})))))

        self.assertEqualsWS("Expected x-drilldown-format to be one of: ['xml', 'json']", xpathFirst(response, '//drilldown:term-drilldown/diag:diagnostic/diag:message/text()'))
    def testEchoedExtraRequestDataWithJsonFormat(self):
        component = SruTermDrilldown()

        result = "".join(list(component.echoedExtraRequestData(sruArguments={'x-term-drilldown': ['field0/field1,field2','field3'], 'version': '1.1', 'x-drilldown-format': ['json']}, version='1.1')))

        self.assertEqualsWS(_DRILLDOWN_HEADER % _DRILLDOWN_XSD_2013 + """
            <dd:request>
                <dd:x-term-drilldown>field0/field1</dd:x-term-drilldown>
                <dd:x-term-drilldown>field2</dd:x-term-drilldown>
                <dd:x-term-drilldown>field3</dd:x-term-drilldown>
                <dd:x-drilldown-format>json</dd:x-drilldown-format>
            </dd:request>""" +\
            DRILLDOWN_FOOTER, result)

        xsdFilename = self._getXsdFilename(result)
        assertValid(result, join(schemasPath, xsdFilename))
        assertValid(open(join(schemasPath, xsdFilename)).read(), join(schemasPath, 'XMLSchema.xsd'))
    def testDefaultFormat(self):
        self.assertRaises(ValueError, lambda: SruTermDrilldown(defaultFormat='text'))
        sruTermDrilldown = SruTermDrilldown(defaultFormat='json')
        drilldownData = [
                {
                    'fieldname': 'field0',
                    'terms': [
                        {
                            'term': 'value0',
                            'count': 1,
                        }
                    ]
                }
            ]

        response = parse(StringIO(''.join(compose(sruTermDrilldown.extraResponseData(drilldownData, sruArguments={})))))

        self.assertEquals(drilldownData, loads(xpathFirst(response, '//drilldown:term-drilldown/drilldown:json/text()')))
    def testDrilldownNoResults(self):
        sruTermDrilldown = SruTermDrilldown()
        drilldownData = [
            {
                'fieldname': 'field0',
                'terms': []
            },
        ]

        composedGenerator = compose(
            sruTermDrilldown.extraResponseData(drilldownData, sruArguments={}))
        result = "".join(composedGenerator)

        expected = DRILLDOWN_HEADER + """
            <dd:term-drilldown>
                <dd:navigator name="field0"/>
            </dd:term-drilldown>
        """ + DRILLDOWN_FOOTER
        self.assertEqualsWS(expected, result)
    def testSruTermDrilldownWithSubTerms(self):
        sruTermDrilldown = SruTermDrilldown(defaultFormat=FORMAT_XML)

        drilldownData = [{
            'fieldname':
            'field0',
            'terms': [{
                'term':
                'value0',
                'count':
                1,
                'subterms': [{
                    'term': 'value0_0',
                    'count': 10,
                }, {
                    'term': 'value0_1',
                    'count': 20
                }]
            }, {
                'term': 'value1',
                'count': 2
            }]
        }]

        response = ''.join(
            compose(
                sruTermDrilldown.extraResponseData(drilldownData,
                                                   sruArguments={})))

        self.assertEqualsWS(
            _DRILLDOWN_HEADER % _DRILLDOWN_XSD_2013 +
            """<dd:term-drilldown><dd:navigator name="field0">
    <dd:item count="1" value="value0">
        <dd:navigator name="subterms">
            <dd:item count="10" value="value0_0"/>
            <dd:item count="20" value="value0_1"/>
        </dd:navigator>
    </dd:item>
    <dd:item count="2" value="value1"/>
</dd:navigator></dd:term-drilldown></dd:drilldown>""", response)
        xsdFilename = self._getXsdFilename(response)
        assertValid(response, join(schemasPath, xsdFilename))
    def testSruTermDrilldownWithSubTerms(self):
        sruTermDrilldown = SruTermDrilldown(defaultFormat=FORMAT_XML)

        drilldownData = [
                {
                    'fieldname': 'field0',
                    'terms': [
                        {
                            'term': 'value0',
                            'count': 1,
                            'subterms': [
                                {
                                    'term': 'value0_0',
                                    'count': 10,
                                },
                                {
                                    'term': 'value0_1',
                                    'count': 20
                                }
                            ]
                        },
                        {
                            'term': 'value1',
                            'count': 2
                        }
                    ]
                }
            ]

        response = ''.join(compose(sruTermDrilldown.extraResponseData(drilldownData, sruArguments={})))

        self.assertEqualsWS(_DRILLDOWN_HEADER % _DRILLDOWN_XSD_2013 + """<dd:term-drilldown><dd:navigator name="field0">
    <dd:item count="1" value="value0">
        <dd:navigator name="subterms">
            <dd:item count="10" value="value0_0"/>
            <dd:item count="20" value="value0_1"/>
        </dd:navigator>
    </dd:item>
    <dd:item count="2" value="value1"/>
</dd:navigator></dd:term-drilldown></dd:drilldown>""", response)
        xsdFilename = self._getXsdFilename(response)
        assertValid(response, join(schemasPath, xsdFilename))
    def testSruTermDrilldownWithPivotsInJson(self):
        sruTermDrilldown = SruTermDrilldown(defaultFormat=FORMAT_JSON)

        drilldownData = [{
            'fieldname':
            'field0',
            'terms': [{
                'term': 'value0',
                'count': 1,
                'pivot': {
                    'fieldname':
                    'field1',
                    'terms': [{
                        'term': 'value0_0',
                        'count': 10,
                    }, {
                        'term': 'value0 & 1',
                        'count': 20
                    }]
                }
            }, {
                'term': 'value1',
                'count': 2
            }]
        }]

        response = ''.join(
            compose(
                sruTermDrilldown.extraResponseData(
                    drilldownData,
                    sruArguments={'x-drilldown-format': ['json']})))
        self.assertEqual(
            drilldownData,
            loads(
                xpathFirst(
                    XML(response),
                    '//drilldown:term-drilldown/drilldown:json/text()')))

        xsdFilename = self._getXsdFilename(response)
        assertValid(response, join(schemasPath, xsdFilename))
    def testWrongFormat(self):
        sruTermDrilldown = SruTermDrilldown()
        drilldownData = [{
            'fieldname': 'field0',
            'terms': [{
                'term': 'value0',
                'count': 1,
            }]
        }]

        response = parse(
            StringIO(''.join(
                compose(
                    sruTermDrilldown.extraResponseData(
                        drilldownData,
                        sruArguments={'x-drilldown-format': 'text'})))))

        self.assertEqualsWS(
            "Expected x-drilldown-format to be one of: ['xml', 'json']",
            xpathFirst(
                response,
                '//drilldown:term-drilldown/diag:diagnostic/diag:message/text()'
            ))
    def testSruTermDrilldownWithPivotsInJson(self):
        sruTermDrilldown = SruTermDrilldown(defaultFormat=FORMAT_JSON)

        drilldownData = [
                {
                    'fieldname': 'field0',
                    'terms': [
                        {
                            'term': 'value0',
                            'count': 1,
                            'pivot': {
                                'fieldname': 'field1',
                                'terms': [
                                    {
                                        'term': 'value0_0',
                                        'count': 10,
                                    },
                                    {
                                        'term': 'value0 & 1',
                                        'count': 20
                                    }
                                ]
                            }
                        },
                        {
                            'term': 'value1',
                            'count': 2
                        }
                    ]
                }
            ]

        response = ''.join(compose(sruTermDrilldown.extraResponseData(drilldownData, sruArguments={'x-drilldown-format': ['json']})))
        self.assertEquals(drilldownData, loads(xpathFirst(XML(response), '//drilldown:term-drilldown/drilldown:json/text()')))

        xsdFilename = self._getXsdFilename(response)
        assertValid(response, join(schemasPath, xsdFilename))
    def testDefaultFormat(self):
        self.assertRaises(ValueError,
                          lambda: SruTermDrilldown(defaultFormat='text'))
        sruTermDrilldown = SruTermDrilldown(defaultFormat='json')
        drilldownData = [{
            'fieldname': 'field0',
            'terms': [{
                'term': 'value0',
                'count': 1,
            }]
        }]

        response = parse(
            StringIO(''.join(
                compose(
                    sruTermDrilldown.extraResponseData(drilldownData,
                                                       sruArguments={})))))

        self.assertEqual(
            drilldownData,
            loads(
                xpathFirst(
                    response,
                    '//drilldown:term-drilldown/drilldown:json/text()')))
def main(reactor, port, statePath, lucenePort, **ignored):


######## START Lucene Integration ###############################################################
    defaultLuceneSettings = LuceneSettings(
        commitTimeout=30,
        readonly=True,)
    
    
    http11Request = be(
        (HttpRequest1_1(),
            (SocketPool(reactor=reactor, unusedTimeout=5, limits=dict(totalSize=100, destinationSize=10)),),
        )
    )
    
    luceneIndex = luceneAndReaderConfig(defaultLuceneSettings.clone(readonly=True), http11Request, lucenePort)
    
    
    luceneRoHelix = be(
        (AdapterToLuceneQuery(
                defaultCore=DEFAULT_CORE,
                coreConverters={
                    DEFAULT_CORE: QueryExpressionToLuceneQueryDict(UNQUALIFIED_TERM_FIELDS, luceneSettings=luceneIndex.settings),
                }
            ),
            (MultiLucene(host='127.0.0.1', port=lucenePort, defaultCore=DEFAULT_CORE),
                (luceneIndex,),
                (http11Request,),
            )
        )
    )

######## END Lucene Integration ###############################################################


    fieldnameRewrites = {}

    def fieldnameRewrite(name):
        return fieldnameRewrites.get(name, name)

    def drilldownFieldnamesTranslate(fieldname):
        untokenizedName = untokenizedFieldname(fieldname)
        if untokenizedName in untokenizedFieldnames:
            fieldname = untokenizedName
        return fieldnameRewrite(fieldname)

    convertToComposedQuery = ConvertToComposedQuery(
            resultsFrom=DEFAULT_CORE,
            matches=[],
            drilldownFieldnamesTranslate=drilldownFieldnamesTranslate
        )


    strategie = Md5HashDistributeStrategy()
    storage = StorageComponent(join(statePath, 'store'), strategy=strategie, partsRemovedOnDelete=[HEADER_PARTNAME, META_PARTNAME, METADATA_PARTNAME, OAI_DC_PARTNAME, LONG_PARTNAME, SHORT_PARTNAME])


    # Wat doet dit?
    cqlClauseConverters = [
        RenameFieldForExact(
            untokenizedFields=untokenizedFieldnames,
            untokenizedPrefix=UNTOKENIZED_PREFIX,
        ).filterAndModifier(),
        SearchTermFilterAndModifier(
            shouldModifyFieldValue=lambda *args: True,
            fieldnameModifier=fieldnameRewrite
        ).filterAndModifier(),
    ]



    executeQueryHelix = \
        (FilterMessages(allowed=['executeQuery']),
            (CqlMultiSearchClauseConversion(cqlClauseConverters, fromKwarg='query'),
                (DrilldownQueries(),
                    (convertToComposedQuery,
                        (luceneRoHelix,),
                    )
                )
            )
        )


    return \
    (Observable(),
        
        (ObservableHttpServer(reactor, port, compressResponse=True),
            (BasicHttpHandler(),
                (PathFilter(['/sru']),
                    (SruParser(
                            host='sru.narcis.nl',
                            port=80,
                            defaultRecordSchema='knaw_short',
                            defaultRecordPacking='xml'),
                        (SruLimitStartRecord(limitBeyond=4000),
                            (SruHandler(
                                    includeQueryTimes=False,
                                    extraXParameters=[],
                                    enableCollectLog=False), #2017-03-24T12:00:33Z 127.0.0.1 3.5K 0.019s - /sru OF (TRUE): 2017-03-24T11:58:53Z 127.0.0.1 2.3K 0.004s 1hits /sru maximumRecords=10&operation=searchRetrieve&query=untokenized.dd_year+exact+%221993%22&recordPacking=xml&recordSchema=knaw_short&startRecord=1&version=1.2
                                (SruTermDrilldown(),),
                                executeQueryHelix,
                                (StorageAdapter(),
                                    (storage,)
                                )
                            )
                        )
                    )
                ),
                (PathFilter('/rss'),
                    (Rss(   supportedLanguages = ['nl','en'], # defaults to first, if requested language is not available or supplied.
                            title = {'nl':'NARCIS', 'en':'NARCIS'},
                            description = {'nl':'NARCIS: De toegang tot de Nederlandse wetenschapsinformatie', 'en':'NARCIS: The gateway to Dutch scientific information'},
                            link = {'nl':'http://www.narcis.nl/?Language=nl', 'en':'http://www.narcis.nl/?Language=en'},
                            maximumRecords = 20),
                        executeQueryHelix,
                        (RssItem(
                                nsMap=NAMESPACEMAP,                                            
                                title = ('knaw_short', {'nl':'//short:metadata/short:titleInfo[not (@xml:lang)]/short:title/text()', 'en':'//short:metadata/short:titleInfo[@xml:lang="en"]/short:title/text()'}),
                                description = ('knaw_short', {'nl':'//short:abstract[not (@xml:lang)]/text()', 'en':'//short:abstract[@xml:lang="en"]/text()'}),
                                pubdate = ('knaw_short', '//short:dateIssued/short:parsed/text()'),
                                linkTemplate = 'http://www.narcis.nl/%(wcpcollection)s/RecordID/%(oai_identifier)s/Language/%(language)s',                                
                                wcpcollection = ('meta', '//*[local-name() = "collection"]/text()'),
                                oai_identifier = ('meta', '//meta:record/meta:id/text()'),
                                language = ('Dummy: Language is auto provided by the calling RSS component, but needs to be present to serve the linkTemplate.')
                            ),
                            (StorageAdapter(),
                                (storage,)
                            )
                        )
                    )
                )
            )
        )
    )
    def testEchoedExtraRequestDataWithEmptyTermDrilldownFormat(self):
        component = SruTermDrilldown(defaultFormat=FORMAT_XML)

        result = "".join(list(component.echoedExtraRequestData(sruArguments={'x-term-drilldown': [''], 'version': '1.1'}, version='1.1')))

        self.assertEqualsWS("", result)
示例#20
0
def main(reactor,
         port,
         statePath,
         lucenePort,
         gatewayPort,
         quickCommit=False,
         **ignored):

    ######## START Lucene Integration ###############################################################
    defaultLuceneSettings = LuceneSettings(
        commitTimeout=30,
        readonly=True,
    )

    http11Request = be((
        HttpRequest1_1(),
        (SocketPool(reactor=reactor,
                    unusedTimeout=5,
                    limits=dict(totalSize=100, destinationSize=10)), ),
    ))

    luceneIndex = luceneAndReaderConfig(
        defaultLuceneSettings.clone(readonly=True), http11Request, lucenePort)

    luceneRoHelix = be(
        (AdapterToLuceneQuery(defaultCore=DEFAULT_CORE,
                              coreConverters={
                                  DEFAULT_CORE:
                                  QueryExpressionToLuceneQueryDict(
                                      UNQUALIFIED_TERM_FIELDS,
                                      luceneSettings=luceneIndex.settings),
                              }), (
                                  MultiLucene(host='localhost',
                                              port=lucenePort,
                                              defaultCore=DEFAULT_CORE),
                                  (luceneIndex, ),
                                  (http11Request, ),
                              )))

    ######## END Lucene Integration ###############################################################

    fieldnameRewrites = {
        #         UNTOKENIZED_PREFIX+'genre': UNTOKENIZED_PREFIX+'dc:genre',
    }

    def fieldnameRewrite(name):
        return fieldnameRewrites.get(name, name)

    def drilldownFieldnamesTranslate(fieldname):
        untokenizedName = untokenizedFieldname(fieldname)
        if untokenizedName in untokenizedFieldnames:
            fieldname = untokenizedName
        return fieldnameRewrite(fieldname)

    convertToComposedQuery = ConvertToComposedQuery(
        resultsFrom=DEFAULT_CORE,
        matches=[],
        drilldownFieldnamesTranslate=drilldownFieldnamesTranslate)

    strategie = Md5HashDistributeStrategy()
    storage = StorageComponent(join(statePath, 'store'),
                               strategy=strategie,
                               partsRemovedOnDelete=[
                                   HEADER_PARTNAME, META_PARTNAME,
                                   METADATA_PARTNAME, OAI_DC_PARTNAME,
                                   LONG_PARTNAME, SHORT_PARTNAME,
                                   OPENAIRE_PARTNAME
                               ])

    oaiJazz = OaiJazz(join(statePath, 'oai'))
    oaiJazz.updateMetadataFormat(
        OAI_DC_PARTNAME, "http://www.openarchives.org/OAI/2.0/oai_dc.xsd",
        "http://purl.org/dc/elements/1.1/")

    oai_oa_cerifJazz = OaiJazz(join(statePath, 'oai_cerif'))
    oai_oa_cerifJazz.updateMetadataFormat(
        OPENAIRE_PARTNAME,
        "https://www.openaire.eu/schema/cris/current/openaire-cerif-profile.xsd",
        "https://www.openaire.eu/cerif-profile/1.1/")
    # All of the following OAI-PMH sets shall be recognized by the CRIS, even if not all of them are populated.
    oai_oa_cerifJazz.updateSet("openaire_cris_projects",
                               "OpenAIRE_CRIS_projects")
    oai_oa_cerifJazz.updateSet("openaire_cris_orgunits",
                               "OpenAIRE_CRIS_orgunits")
    oai_oa_cerifJazz.updateSet("openaire_cris_persons",
                               "OpenAIRE_CRIS_persons")
    oai_oa_cerifJazz.updateSet("openaire_cris_patents",
                               "OpenAIRE_CRIS_patents")
    oai_oa_cerifJazz.updateSet("openaire_cris_products",
                               "OpenAIRE_CRIS_products")
    oai_oa_cerifJazz.updateSet("openaire_cris_publications",
                               "OpenAIRE_CRIS_publications")

    oai_oa_cerifJazz.updateSet("openaire_cris_funding",
                               "OpenAIRE_CRIS_funding")
    oai_oa_cerifJazz.updateSet("openaire_cris_events", "OpenAIRE_CRIS_events")
    oai_oa_cerifJazz.updateSet("openaire_cris_equipments",
                               "OpenAIRE_CRIS_equipments")

    cqlClauseConverters = [
        RenameFieldForExact(
            untokenizedFields=untokenizedFieldnames,
            untokenizedPrefix=UNTOKENIZED_PREFIX,
        ).filterAndModifier(),
        SearchTermFilterAndModifier(
            shouldModifyFieldValue=lambda *args: True,
            fieldnameModifier=fieldnameRewrite).filterAndModifier(),
    ]

    periodicGateWayDownload = PeriodicDownload(
        reactor,
        host='localhost',
        port=gatewayPort,
        schedule=Schedule(
            period=1 if quickCommit else 10
        ),  # WST: Interval in seconds before sending a new request to the GATEWAY in case of an error while processing batch records.(default=1). IntegrationTests need 1 second! Otherwise tests will fail!
        name='api',
        autoStart=True)

    oaiDownload = OaiDownloadProcessor(path='/oaix',
                                       metadataPrefix=NORMALISED_DOC_NAME,
                                       workingDirectory=join(
                                           statePath, 'harvesterstate',
                                           'gateway'),
                                       userAgentAddition='ApiServer',
                                       xWait=True,
                                       name='api',
                                       autoCommit=False)

    executeQueryHelix = \
        (FilterMessages(allowed=['executeQuery']),
            (CqlMultiSearchClauseConversion(cqlClauseConverters, fromKwarg='query'),
                (DrilldownQueries(),
                    (convertToComposedQuery,
                        (luceneRoHelix,),
                    )
                )
            )
        )

    return \
    (Observable(),
        createDownloadHelix(reactor, periodicGateWayDownload, oaiDownload, storage, oaiJazz, oai_oa_cerifJazz),
        (ObservableHttpServer(reactor, port, compressResponse=True),
            (BasicHttpHandler(),
                (PathFilter(["/oai"]),
                    (OaiPmh(repositoryName="NARCIS OAI-pmh", adminEmail="*****@*****.**", externalUrl="http://oai.narcis.nl"),
                        (oaiJazz,),
                        (StorageAdapter(),
                            (storage,)
                        ),
                        (OaiBranding(
                            url="http://www.narcis.nl/images/logos/logo-knaw-house.gif",
                            link="http://oai.narcis.nl",
                            title="Narcis - The gateway to scholarly information in The Netherlands"),
                        ),
                        (OaiProvenance(
                            nsMap=NAMESPACEMAP,
                            baseURL=('meta', '//meta:repository/meta:baseurl/text()'),
                            harvestDate=('meta', '//meta:record/meta:harvestdate/text()'),
                            metadataNamespace=('meta', '//meta:record/meta:metadataNamespace/text()'),
                            identifier=('header','//oai:identifier/text()'),
                            datestamp=('header', '//oai:datestamp/text()')
                            ),
                            (storage,)
                        )
                    )
                ),
                (PathFilter(["/cerif"]),
                    (OaiPmhDans(repositoryName="OpenAIRE CERIF", adminEmail="*****@*****.**", repositoryIdentifier="services.nod.dans.knaw.nl", externalUrl="http://services.nod.dans.knaw.nl"), #TODO: pathFilter should resemble proxy path
                        (oai_oa_cerifJazz,),
                        (StorageAdapter(),
                            (storage,)
                        ),
                        (OaiOpenAIREDescription(
                            serviceid='organisation:ORG1242054',
                            acronym='services.nod.dans.knaw.nl',
                            name='NARCIS',
                            description='Compliant with the OpenAIRE Guidelines for CRIS Managers v.1.1.',
                            website='https://www.narcis.nl',
                            baseurl='http://services.nod.dans.knaw.nl/oa-cerif',
                            subjectheading='',
                            orgunitid='organisation:ORG1242054',
                            owneracronym='DANS'),
                        ),
                        # (OaiBranding(
                        #     url="http://www.narcis.nl/images/logos/logo-knaw-house.gif",
                        #     link="http://oai.narcis.nl",
                        #     title="Narcis - The gateway to scholarly information in The Netherlands"),
                        # ),
                        (OaiProvenance(
                            nsMap=NAMESPACEMAP,
                            baseURL=('meta', '//meta:repository/meta:baseurl/text()'),
                            harvestDate=('meta', '//meta:record/meta:harvestdate/text()'),
                            metadataNamespace=('meta', '//meta:record/meta:metadataNamespace/text()'),
                            identifier=('header','//oai:identifier/text()'),
                            datestamp=('header', '//oai:datestamp/text()')
                            ),
                            (storage,)
                        )
                    )
                ),
                (PathFilter(['/sru']),
                    (SruParser(
                            host='sru.narcis.nl',
                            port=80,
                            defaultRecordSchema='knaw_short',
                            defaultRecordPacking='xml'),
                        (SruLimitStartRecord(limitBeyond=4000),
                            (SruHandler(
                                    includeQueryTimes=False,
                                    extraXParameters=[],
                                    enableCollectLog=False),
                                (SruTermDrilldown(),),
                                executeQueryHelix,
                                (StorageAdapter(),
                                    (storage,)
                                )
                            )
                        )
                    )
                ),
                (PathFilter('/rss'),
                    (Rss(   supportedLanguages = ['nl','en'], # defaults to first, if requested language is not available or supplied.
                            title = {'nl':'NARCIS', 'en':'NARCIS'},
                            description = {'nl':'NARCIS: De toegang tot de Nederlandse wetenschapsinformatie', 'en':'NARCIS: The gateway to Dutch scientific information'},
                            link = {'nl':'http://www.narcis.nl/?Language=nl', 'en':'http://www.narcis.nl/?Language=en'},
                            maximumRecords = 20),
                        executeQueryHelix,
                        (RssItem(
                                nsMap=NAMESPACEMAP,
                                title = ('knaw_short', {'nl':'//short:metadata/short:titleInfo[not (@xml:lang)]/short:title/text()', 'en':'//short:metadata/short:titleInfo[@xml:lang="en"]/short:title/text()'}),
                                description = ('knaw_short', {'nl':'//short:abstract[not (@xml:lang)]/text()', 'en':'//short:abstract[@xml:lang="en"]/text()'}),
                                pubdate = ('knaw_short', '//short:dateIssued/short:parsed/text()'),
                                linkTemplate = 'http://www.narcis.nl/%(wcpcollection)s/RecordID/%(oai_identifier)s/Language/%(language)s',
                                wcpcollection = ('meta', '//*[local-name() = "collection"]/text()'),
                                oai_identifier = ('meta', '//meta:record/meta:id/text()'),
                                language = ('Dummy: Language is auto provided by the calling RSS component, but needs to be present to serve the linkTemplate.')
                            ),
                            (StorageAdapter(),
                                (storage,)
                            )
                        )
                    )
                )
            )
        )
    )