Skip to content

Commit

Permalink
Merge pull request #912 from ZakarFin/csw-query-params
Browse files Browse the repository at this point in the history
Make CSW query type and fields configurable
  • Loading branch information
ZakarFin authored Jan 27, 2023
2 parents e7656a5 + c2bd95f commit 09d6baf
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 58 deletions.
24 changes: 12 additions & 12 deletions service-csw/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
<dependency>
<dependency>
<groupId>org.oskari</groupId>
<artifactId>service-control</artifactId>
</dependency>
<dependency>
<groupId>javax.vecmath</groupId>
<artifactId>vecmath</artifactId>
</dependency>
<artifactId>service-control</artifactId>
</dependency>
<dependency>
<groupId>javax.vecmath</groupId>
<artifactId>vecmath</artifactId>
</dependency>

<dependency>
<groupId>junit</groupId>
Expand All @@ -51,16 +51,16 @@
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>

<dependency>
<groupId>org.oskari</groupId>
<artifactId>shared-test-resources</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
*
* Configurable by properties:
* - Server: service.metadata.url (for example "https://www.paikkatietohakemisto.fi/geonetwork/srv/fin/csw")
* - localized urls for images: search.channel.METADATA_CATALOGUE_CHANNEL.image.url.[lang code] (as contentURL in conjunction with resourceId)
* - localized urls for service: search.channel.METADATA_CATALOGUE_CHANNEL.fetchpage.url.[lang code] (as actionURL in conjunction with resourceId)
* - Query type: search.channel.METADATA_CATALOGUE_CHANNEL.queryType (defaults to "summary")
* - Query fields: search.channel.METADATA_CATALOGUE_CHANNEL.queryFields (comma-separted list like "Title, Abstract" - defaults to "csw:anyText")
* - advanced filter fields (dropdowns) that are available on form based on the service:
* search.channel.METADATA_CATALOGUE_CHANNEL.fields (Note! Uses GetDomain Operation on CSW to populate values for fields)
* - per field processing definitions (each property prefixed with "search.channel.METADATA_CATALOGUE_CHANNEL.field.[field name]."):
Expand All @@ -61,32 +61,22 @@ public class MetadataCatalogueChannelSearchService extends SearchChannel {

public static final String ID = "METADATA_CATALOGUE_CHANNEL";
private static String serverURL = PropertyUtil.get(PROP_SERVICE_URL);
private String queryType;
private String[] queryFields;

private final static List<MetadataField> fields = new ArrayList<>();

private MetadataCatalogueResultParser RESULT_PARSER = null;
private final MetadataCatalogueQueryHelper QUERY_HELPER = new MetadataCatalogueQueryHelper();

private OskariLayerService mapLayerService = OskariComponentManager.getComponentOfType(OskariLayerService.class);
private static final String PROPERTY_RESULTPARSER = "search.channel.METADATA_CATALOGUE_CHANNEL.resultparser";

@Override
public void init() {
super.init();
// hook for customized parsing
// TODO: this was only used for ELF to inject rating for metadata. We can probably remove it now
final String customResultParser = PropertyUtil.getOptional(PROPERTY_RESULTPARSER);
if (customResultParser != null) {
try {
final Class clazz = Class.forName(customResultParser);
RESULT_PARSER = (MetadataCatalogueResultParser) clazz.newInstance();
} catch (Exception e) {
log.error(e, "Error instantiating custom metadata result parser:", customResultParser);
}
}
if (RESULT_PARSER == null) {
RESULT_PARSER = new MetadataCatalogueResultParser();
}
queryType = getProperty("queryType", "summary");
queryFields = getProperty("queryFields", "csw:anyText").split("\\s*,\\s*");
RESULT_PARSER = new MetadataCatalogueResultParser();
}

/**
Expand Down Expand Up @@ -176,19 +166,10 @@ public ChannelSearchResult parseResults(Element root, SearchCriteria searchCrite
getResults(root).forEach(metadata -> {
try {
final SearchResultItem item = RESULT_PARSER.parseResult(metadata);
/*
// done in frontend now?
final List<OskariLayer> oskariLayers = getOskariLayerWithUuid(item);
for(OskariLayer oskariLayer : oskariLayers){
log.debug("METAID: " + oskariLayer.getMetadataId());
item.addUuId(oskariLayer.getMetadataId());
}
*/

item.addValue("geom", getWKT(item, WKTHelper.PROJ_EPSG_4326, srs));
channelSearchResult.addItem(item);
} catch (Exception e) {
log.warn(e);
log.info("Error parsing metadata search result item", e);
}
});

Expand Down Expand Up @@ -238,7 +219,7 @@ private String getWKT(final SearchResultItem item, final String sourceSRS, final

private Element makeQuery(SearchCriteria searchCriteria) throws Exception {
final long start = System.currentTimeMillis();
final String payload = QUERY_HELPER.getQueryPayload(searchCriteria);
final String payload = QUERY_HELPER.getQueryPayload(searchCriteria, queryType, queryFields);
if (payload == null) {
// no point in making the query without payload
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import java.util.List;
import java.util.Map;

import static org.oskari.csw.request.GetRecords.DEFAULT_QUERY_TYPE;

/**
* Helper class for creating search queries for MetadataCatalogue
*/
Expand All @@ -35,6 +37,7 @@ public class MetadataCatalogueQueryHelper {
public final static String WILDCARD_CHARACTER = "*";
public final static String SINGLE_WILDCARD_CHARACTER = "?";
public final static String ESCAPE_CHARACTER = "/";
private static final String[] DEFAULT_QUERY_FIELDS = new String[] { "csw:anyText" };

private static final Logger log = LogFactory.getLogger(MetadataCatalogueQueryHelper.class);
private FilterFactory2 filterFactory;
Expand All @@ -45,7 +48,10 @@ public MetadataCatalogueQueryHelper() {
}

public String getQueryPayload(SearchCriteria searchCriteria) {
final List<Filter> filters = getFiltersForQuery(searchCriteria);
return getQueryPayload(searchCriteria, DEFAULT_QUERY_TYPE, DEFAULT_QUERY_FIELDS);
}
public String getQueryPayload(SearchCriteria searchCriteria, String queryType, String... queryFields) {
final List<Filter> filters = getFiltersForQuery(searchCriteria, queryFields);
if (filters.isEmpty()) {
// no point in making the query without GetRecords, but throw exception instead?
//throw new ServiceRuntimeException("Can't create GetRecords request without filters");
Expand All @@ -58,19 +64,27 @@ public String getQueryPayload(SearchCriteria searchCriteria) {
filter = filterFactory.and(filters);
}

return GetRecords.createRequest(filter);
return GetRecords.createRequest(filter, queryType);
}

private List<Filter> getFiltersForQuery(SearchCriteria searchCriteria) {
private List<Filter> getFiltersForQuery(SearchCriteria searchCriteria, String... queryFields) {
final List<Filter> list = new ArrayList<>();
final List<Filter> theOrList = new ArrayList<>();

// user input
Filter userInput = createLikeFilter(searchCriteria.getSearchString(), "csw:anyText");
if (userInput != null) {
list.add(userInput);
if (queryFields == null || queryFields.length == 0) {
queryFields = DEFAULT_QUERY_FIELDS;
}

List<Filter> queryFilters = new ArrayList<>();
for (String field: queryFields) {
queryFilters.add(createLikeFilter(searchCriteria.getSearchString(), field));
}
if (queryFilters.size() == 1) {
list.add(queryFilters.get(0));
} else if (queryFilters.size() > 1) {
list.add(filterFactory.or(queryFilters));
}
// "advanced fields"
for (MetadataField field : MetadataCatalogueChannelSearchService.getFields()) {
final Filter operation = getFilterForField(searchCriteria, field);
if (operation == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
*/
public class MetadataCatalogueResultParser {

private static final Logger log = LogFactory.getLogger(MetadataCatalogueResultParser.class);

public static final String KEY_IDENTIFICATION = "identification";
public static final String KEY_IDENTIFICATION_DATE = "date";
public static final String KEY_IDENTIFICATION_CODELIST = "code";
Expand All @@ -42,7 +40,6 @@ public SearchResultItem parseResult(final Element elem) throws Exception {
XmlHelper.getFirstChild(elem, "fileIdentifier"),
"CharacterString");
item.setResourceId(uuid);
//item.addUuId(uuid);
// lang
Element languageCode = XmlHelper.getFirstChild(
XmlHelper.getFirstChild(elem, "language"),
Expand Down
22 changes: 17 additions & 5 deletions service-csw/src/main/java/org/oskari/csw/request/GetRecords.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,25 @@ public class GetRecords {

private static final String CSW_VERSION = "2.0.2";
private static final String CONSTRAINT_VERSION = "1.0.0";
public static final String DEFAULT_QUERY_TYPE = "summary";

private GetRecords() {}

public static String createRequest(Filter filter) {
return createRequest(filter, DEFAULT_QUERY_TYPE);
}
/**
* Builds a GetRecords request payload for CSW-service with the given filters.
* @param filter required
* @return
*/
public static String createRequest(Filter filter) {
public static String createRequest(Filter filter, String queryType) {
if (filter == null) {
throw new ServiceRuntimeException("Filter is required");
}
final StringWriter writer = new StringWriter();
XMLStreamWriter xsw = getXMLWriter(writer);
startDocument(xsw);
startDocument(xsw, queryType);
writeRawXMLUnsafe(xsw, writer, getFilterAsString(filter));
endDocument(xsw);
return writer.toString();
Expand All @@ -59,7 +63,7 @@ private static XMLStreamWriter getXMLWriter(Writer writer) {
<csw:Constraint version="1.1.0">
...
*/
private static void startDocument(XMLStreamWriter xsw) {
private static void startDocument(XMLStreamWriter xsw, String queryType) {
try {
xsw.writeStartDocument();
xsw.writeStartElement("csw", "GetRecords", CSW_URI);
Expand All @@ -72,7 +76,7 @@ private static void startDocument(XMLStreamWriter xsw) {
xsw.writeAttribute("service", "CSW");
xsw.writeAttribute("version", CSW_VERSION);

xsw.writeAttribute("maxRecords", "10000");
xsw.writeAttribute("maxRecords", "100");
xsw.writeAttribute("startPosition", "1");

xsw.writeAttribute("resultType", "results"); // or "validate" or "hits"
Expand All @@ -90,7 +94,15 @@ private static void startDocument(XMLStreamWriter xsw) {
// parse but it's safe.
xsw.writeStartElement(CSW_URI, "ElementSetName");
// changes from full to summary for performance reasons. "brief" would be even faster but doesn't include dates
xsw.writeCharacters("summary");
String type = queryType;
// these are the valid values
if (type == null) {
type = "summary";
}
if (!("summary".equals(type) || "brief".equals(type) || "full".equals(type))) {
throw new IllegalArgumentException("Type needs to be one of: summary, brief, full. Was: " + type);
}
xsw.writeCharacters(type);
xsw.writeEndElement(); // ElementSetName


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,28 @@ public void testWithNoFilter() {
fail("Should have thrown exception");
}

@Test
public void testRequestType() {
// build filter
Filter filter = createEqualsFilter("csw:Any", "testing");
String request = org.oskari.csw.request.GetRecords.createRequest(filter);

assertTrue("Should get 'summary' as request type", request.contains("<csw:ElementSetName>summary</csw:ElementSetName>"));

request = org.oskari.csw.request.GetRecords.createRequest(filter, "brief");
assertTrue("Should get 'brief' as request type", request.contains("<csw:ElementSetName>brief</csw:ElementSetName>"));

request = org.oskari.csw.request.GetRecords.createRequest(filter, "full");
assertTrue("Should get 'full' as request type", request.contains("<csw:ElementSetName>full</csw:ElementSetName>"));
}

@Test(expected = IllegalArgumentException.class)
public void testRequestTypeInvalid() {
// build filter
Filter filter = createEqualsFilter("csw:Any", "testing");
org.oskari.csw.request.GetRecords.createRequest(filter, "dummy");
}

@Test
public void testSimpleFilter() throws IOException, SAXException {
// build filter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<csw:GetRecords xmlns:csw="http://www.opengis.net/cat/csw/2.0.2" xmlns:gmd="http://www.isotc211.org/2005/gmd"
xmlns:gml="http://www.opengis.net/gml" xmlns:ows="http://www.opengis.net/ows"
xmlns:ogc="http://www.opengis.net/ogc"
service="CSW" version="2.0.2" maxRecords="10000" startPosition="1" resultType="results"
service="CSW" version="2.0.2" maxRecords="100" startPosition="1" resultType="results"
outputFormat="application/xml" outputSchema="http://www.isotc211.org/2005/gmd">
<csw:Query typeNames="gmd:MD_Metadata">
<csw:ElementSetName>summary</csw:ElementSetName>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
<csw:GetRecords xmlns:csw="http://www.opengis.net/cat/csw/2.0.2" xmlns:gmd="http://www.isotc211.org/2005/gmd"
xmlns:ogc="http://www.opengis.net/ogc" service="CSW" version="2.0.2" maxRecords="10000"
xmlns:ogc="http://www.opengis.net/ogc" service="CSW" version="2.0.2" maxRecords="100"
startPosition="1" resultType="results" outputFormat="application/xml"
outputSchema="http://www.isotc211.org/2005/gmd">
<csw:Query typeNames="gmd:MD_Metadata">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
<csw:GetRecords xmlns:csw="http://www.opengis.net/cat/csw/2.0.2" xmlns:gmd="http://www.isotc211.org/2005/gmd"
xmlns:ogc="http://www.opengis.net/ogc" service="CSW" version="2.0.2" maxRecords="10000"
xmlns:ogc="http://www.opengis.net/ogc" service="CSW" version="2.0.2" maxRecords="100"
startPosition="1" resultType="results" outputFormat="application/xml"
outputSchema="http://www.isotc211.org/2005/gmd">
<csw:Query typeNames="gmd:MD_Metadata">
Expand Down

0 comments on commit 09d6baf

Please sign in to comment.