Commit 1b5d0292 authored by Matija Obreza's avatar Matija Obreza
Browse files

Filter selection

parent ad052e8e
......@@ -16,6 +16,7 @@
package org.genesys2.server.service;
import java.util.Collection;
import java.util.List;
import org.genesys2.server.model.genesys.Accession;
......@@ -31,6 +32,8 @@ public interface GenesysFilterService {
List<GenesysFilter> listAvailableFilters();
public static interface GenesysFilter {
public String getKey();
public enum DataType {
FIXEDSTRING, STRING, NUMERIC, BOOLEAN
......@@ -40,4 +43,8 @@ public interface GenesysFilterService {
EXACT, RANGE, LIST
}
}
List<GenesysFilter> selectFilters(String[] selectedFilters);
Collection<GenesysFilter> generateFilters(Collection<Long> methodIds);
}
......@@ -16,7 +16,6 @@
package org.genesys2.server.service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
......@@ -25,7 +24,6 @@ import org.genesys2.server.model.genesys.Method;
import org.genesys2.server.model.genesys.Parameter;
import org.genesys2.server.model.genesys.ParameterCategory;
import org.genesys2.server.model.impl.Crop;
import org.genesys2.server.service.GenesysFilterService.GenesysFilter;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
......@@ -89,6 +87,4 @@ public interface TraitService {
Map<Long, List<Method>> mapMethods(Crop crop);
Collection<GenesysFilter> generateFilters(List<Long> methodIds);
}
......@@ -17,19 +17,25 @@
package org.genesys2.server.service.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import javax.sql.DataSource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.genesys.Method;
import org.genesys2.server.persistence.domain.AccessionRepository;
import org.genesys2.server.persistence.domain.MethodRepository;
import org.genesys2.server.persistence.domain.TraitValueRepository;
import org.genesys2.server.service.GenesysFilterService;
import org.genesys2.server.service.GenesysFilterService.GenesysFilter.DataType;
......@@ -58,6 +64,9 @@ public class GenesysFilterServiceImpl implements GenesysFilterService {
@Autowired
private TraitValueRepository traitValueRepository;
@Autowired
private MethodRepository methodRepository;
@Autowired
private AccessionRepository accessionRepository;
......@@ -77,16 +86,18 @@ public class GenesysFilterServiceImpl implements GenesysFilterService {
public GenesysFilterServiceImpl() {
this.availableFilters = new ArrayList<GenesysFilter>();
// "origin", "institute", "lat", "lon", "alt", "genus"
this.availableFilters.add(new GenesysFilterImpl("accenumb", DataType.NUMERIC));
this.availableFilters.add(new GenesysFilterImpl("crop", DataType.STRING));
this.availableFilters.add(new GenesysFilterImpl("genus", DataType.STRING));
this.availableFilters.add(new GenesysFilterImpl("taxon", DataType.STRING));
this.availableFilters.add(new GenesysFilterImpl("origin", DataType.FIXEDSTRING, 3));
this.availableFilters.add(new GenesysFilterImpl("institute", DataType.FIXEDSTRING, 6));
this.availableFilters.add(new GenesysFilterImpl("organization", DataType.STRING));
this.availableFilters.add(new GenesysFilterImpl("lat", DataType.NUMERIC));
this.availableFilters.add(new GenesysFilterImpl("lon", DataType.NUMERIC));
this.availableFilters.add(new GenesysFilterImpl("elevation", DataType.NUMERIC));
this.availableFilters.add(new GenesysFilterImpl("genus", DataType.STRING));
this.availableFilters.add(new GenesysFilterImpl("taxon", DataType.STRING));
this.availableFilters.add(new GenesysFilterImpl("crop", DataType.STRING));
this.availableFilters.add(new GenesysFilterImpl("organization", DataType.STRING));
this.availableFilters.add(new GenesysFilterImpl("institute", DataType.FIXEDSTRING, 6));
this.availableFilters.add(new GenesysFilterImpl("accenumb", DataType.NUMERIC));
this.availableFilters.add(new GenesysFilterImpl("inSvalbard", DataType.BOOLEAN));
this.availableFilters.add(new GenesysFilterImpl("mls", DataType.BOOLEAN));
this.availableFilters.add(new GenesysFilterImpl("available", DataType.BOOLEAN));
......@@ -97,6 +108,50 @@ public class GenesysFilterServiceImpl implements GenesysFilterService {
return Collections.unmodifiableList(this.availableFilters);
}
@Override
public List<GenesysFilter> selectFilters(String[] selectedFilters) {
List<GenesysFilter> filters = new ArrayList<GenesysFilter>();
Set<Long> methodIds = new HashSet<Long>();
for (final String selectedFilter : selectedFilters) {
if (selectedFilter.startsWith("gm:")) {
try {
methodIds.add(Long.parseLong(selectedFilter.substring(3)));
} catch (NumberFormatException | NullPointerException e) {
LOG.warn(e);
}
} else {
GenesysFilter coreFilter = CollectionUtils.find(this.availableFilters, new Predicate<GenesysFilter>() {
@Override
public boolean evaluate(GenesysFilter object) {
return object.getKey().equals(selectedFilter);
}
});
if (coreFilter != null) {
filters.add(coreFilter);
}
}
}
filters.addAll(generateFilters(methodIds));
return filters;
}
@Override
public Collection<GenesysFilter> generateFilters(Collection<Long> methodIds) {
List<GenesysFilter> filters = new ArrayList<GenesysFilter>();
for (long methodId : methodIds) {
Method method = methodRepository.findOne(methodId);
if (method == null) {
continue;
}
filters.add(new GenesysMethodFilterImpl("gm:" + method.getId(), method.getParameter().getTitle(), method.getFieldType() == 1
|| method.getFieldType() == 2 ? DataType.NUMERIC : DataType.STRING));
}
return filters;
}
@Override
public Page<Accession> listAccessions(JsonNode jsonTree, Pageable pageable) {
Iterator<Entry<String, JsonNode>> fields = jsonTree.fields();
......@@ -376,6 +431,10 @@ public class GenesysFilterServiceImpl implements GenesysFilterService {
private DataType dataType;
private FilterType filterType;
private Integer maxLength;
public boolean isCore() {
return true;
}
public GenesysFilterImpl(String name, DataType type) {
this.name = name;
......@@ -397,6 +456,11 @@ public class GenesysFilterServiceImpl implements GenesysFilterService {
this.maxLength = i;
}
@Override
public String getKey() {
return name;
}
public String getName() {
return name;
}
......@@ -404,7 +468,7 @@ public class GenesysFilterServiceImpl implements GenesysFilterService {
public DataType getDataType() {
return dataType;
}
public FilterType getFilterType() {
return filterType;
}
......@@ -413,4 +477,22 @@ public class GenesysFilterServiceImpl implements GenesysFilterService {
return maxLength;
}
}
public static class GenesysMethodFilterImpl extends GenesysFilterImpl {
private String title;
@Override
public boolean isCore() {
return false;
}
public GenesysMethodFilterImpl(String name, String title, DataType dataType) {
super(name, dataType);
this.title = title;
}
public String getTitle() {
return title;
}
}
}
......@@ -82,11 +82,9 @@ import org.genesys2.server.persistence.domain.TraitValueRepository;
import org.genesys2.server.security.AuthUserDetails;
import org.genesys2.server.service.AclService;
import org.genesys2.server.service.DatasetService;
import org.genesys2.server.service.GenesysFilterService.GenesysFilter.DataType;
import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.HtmlSanitizer;
import org.genesys2.server.service.TraitService;
import org.genesys2.server.service.GenesysFilterService.GenesysFilter;
import org.genesys2.spring.SecurityContextUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
......@@ -1181,17 +1179,4 @@ public class GenesysServiceImpl implements GenesysService, TraitService, Dataset
return paramMethods;
}
@Override
public Collection<GenesysFilter> generateFilters(List<Long> methodIds) {
List<GenesysFilter> filters = new ArrayList<GenesysFilter>();
for (long methodId : methodIds) {
Method method = methodRepository.findOne(methodId);
if (method == null) {
continue;
}
filters.add(new GenesysFilterServiceImpl.GenesysFilterImpl("gm:" + method.getId(),
method.getFieldType() == 1 || method.getFieldType() == 2 ? DataType.NUMERIC : DataType.STRING));
}
return filters;
}
}
......@@ -16,17 +16,13 @@
package org.genesys2.server.servlet.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.genesys.ParameterCategory;
import org.genesys2.server.model.impl.Crop;
import org.genesys2.server.model.impl.CropTaxonomy;
import org.genesys2.server.service.CropService;
import org.genesys2.server.service.GenesysFilterService;
import org.genesys2.server.service.GenesysFilterService.GenesysFilter;
import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.TraitService;
import org.genesys2.spring.ResourceNotFoundException;
......@@ -116,40 +112,6 @@ public class CropController extends BaseController {
return "/accession/data";
}
@RequestMapping(value = "/{shortName}/data/descriptors", method = RequestMethod.GET)
public String viewDescriptors(ModelMap model, @PathVariable(value = "shortName") String shortName) {
_logger.warn("Viewing crop descriptors " + shortName);
Crop crop = cropService.getCrop(shortName);
if (crop == null) {
throw new ResourceNotFoundException();
}
model.addAttribute("crop", crop);
List<ParameterCategory> parameterCategories = traitService.listCategories();
model.addAttribute("categories", parameterCategories);
model.addAttribute("descriptors", traitService.mapTraits(crop, parameterCategories));
model.addAttribute("methods", traitService.mapMethods(crop));
return "/filter/cropdescriptors";
}
@RequestMapping(value = "/{shortName}/data/descriptors", method = RequestMethod.POST)
public String selectDescriptors(ModelMap model, @PathVariable(value = "shortName") String shortName, @RequestParam("methods") List<Long> methodIds) {
_logger.warn("Viewing crop descriptors " + shortName);
Crop crop = cropService.getCrop(shortName);
if (crop == null) {
throw new ResourceNotFoundException();
}
// What filters do we support?
List<GenesysFilter> availableFilters = new ArrayList<GenesysFilter>();
availableFilters.addAll(filterService.listAvailableFilters());
availableFilters.addAll(traitService.generateFilters(methodIds));
model.addAttribute("availableFilters", availableFilters);
return "/filter/index";
}
@RequestMapping("/{shortName}/descriptors")
public String viewDescriptors(ModelMap model, @PathVariable(value = "shortName") String shortName,
@RequestParam(value = "page", required = false, defaultValue = "1") int page) {
......
......@@ -62,6 +62,18 @@ public class DescriptorController extends BaseController {
return "/descr/details";
}
/**
* Redirect "/descriptor/gm:1234" URLs to "/descriptor/{traitId}/{methodId}"
*/
@RequestMapping("/gm:{methodId}")
public String viewMethod(ModelMap model, @PathVariable("methodId") long methodId) {
Method method = traitService.getMethod(methodId);
if (method == null) {
throw new ResourceNotFoundException();
}
return "redirect:/descriptors/" + method.getParameter().getId() + "/" + method.getId();
}
@RequestMapping("/{traitId}/{methodId}")
public String view(ModelMap model, @PathVariable("traitId") long traitId, @PathVariable("methodId") long methodId) {
Parameter trait = traitService.getTrait(traitId);
......@@ -86,7 +98,6 @@ public class DescriptorController extends BaseController {
model.addAttribute("codeStatistics", traitService.getMethodStatistics(method));
}
return "/descr/method";
}
}
/**
* Copyright 2013 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
package org.genesys2.server.servlet.controller;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.genesys2.server.model.genesys.ParameterCategory;
import org.genesys2.server.model.impl.Crop;
import org.genesys2.server.service.CropService;
import org.genesys2.server.service.GenesysFilterService;
import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.InstituteService;
import org.genesys2.server.service.TaxonomyService;
import org.genesys2.server.service.TraitService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@Controller
@RequestMapping("/explore")
public class ExplorerController extends BaseController {
@Autowired
private GenesysFilterService filterService;
@Autowired
private CropService cropService;
@Autowired
private TraitService traitService;
@Autowired
private InstituteService instituteService;
@Autowired
private GenesysService genesysService;
@Autowired
private TaxonomyService taxonomyService;
private ObjectMapper mapper = new ObjectMapper();
@RequestMapping(value = "/pick", method = RequestMethod.GET)
public String pickFilters(ModelMap model, @RequestParam(value = "filter", required = false, defaultValue = "{}") String jsonFilter,
@RequestParam(value = "pick", required = false, defaultValue = "[]") String pick, @RequestParam(value = "crop", required = false) String shortName) {
String[] selectedFilters = new String[0];
try {
selectedFilters = mapper.readValue(pick, selectedFilters.getClass());
} catch (IOException e) {
_logger.error(e.getMessage(), e);
}
if (StringUtils.isNotBlank(shortName)) {
// Add crop descriptors
Crop crop = cropService.getCrop(shortName);
if (crop != null) {
model.addAttribute("crop", crop);
List<ParameterCategory> parameterCategories = traitService.listCategories();
model.addAttribute("categories", parameterCategories);
model.addAttribute("descriptors", traitService.mapTraits(crop, parameterCategories));
model.addAttribute("methods", traitService.mapMethods(crop));
}
}
// What filters do we support?
model.addAttribute("availableFilters", filterService.listAvailableFilters());
model.addAttribute("jsonString", jsonFilter);
model.addAttribute("selectedFilters", new HashSet<String>(Arrays.asList(selectedFilters)));
model.addAttribute("crops", cropService.list(getLocale()));
return "/filter/pick";
}
@RequestMapping(value = "/pick", method = RequestMethod.POST)
public String doPickFilters(ModelMap model, @RequestParam(value = "filter", required = false, defaultValue = "{}") String jsonFilter,
@RequestParam(value = "pick", required = false) String[] pick, @RequestParam(value = "crop", required = false) String shortName) {
if (StringUtils.isNotBlank(shortName)) {
Crop crop = cropService.getCrop(shortName);
if (crop != null) {
model.addAttribute("crop", crop.getShortName());
}
}
try {
if (pick != null)
model.addAttribute("pick", mapper.writeValueAsString(pick));
} catch (JsonProcessingException e) {
_logger.error(e.getMessage(), e);
}
model.addAttribute("filter", jsonFilter);
return "redirect:/explore/pick";
}
@RequestMapping(value = "/pick", method = RequestMethod.POST, params = { "doView" })
public String doView(ModelMap model, @RequestParam(value = "filter", required = false, defaultValue = "{}") String jsonFilter,
@RequestParam(value = "pick", required = false) String[] pick, @RequestParam(value = "crop", required = false) String shortName) {
doPickFilters(model, jsonFilter, pick, shortName);
return "redirect:/explore/filter";
}
@RequestMapping(value = "/filter", method = RequestMethod.GET)
public String showFilters(ModelMap model, @RequestParam(value = "filter", required = false, defaultValue = "{}") String jsonFilter,
@RequestParam(value = "pick", required = false, defaultValue = "[]") String pick, @RequestParam(value = "crop", required = false) String shortName) {
String[] selectedFilters = new String[0];
try {
selectedFilters = mapper.readValue(pick, selectedFilters.getClass());
} catch (IOException e) {
_logger.error(e.getMessage(), e);
}
model.addAttribute("selectedFilters", filterService.selectFilters(selectedFilters));
try {
JsonNode jsonTree = mapper.readTree(jsonFilter);
model.addAttribute("jsonString", jsonTree.toString());
} catch (IOException e) {
_logger.warn(e.getMessage(), e);
}
try {
JsonNode jsonTree = mapper.readTree(pick);
model.addAttribute("pick", jsonTree.toString());
} catch (IOException e) {
_logger.warn(e.getMessage(), e);
}
if (StringUtils.isNotBlank(shortName)) {
Crop crop = cropService.getCrop(shortName);
if (crop != null) {
model.addAttribute("crop", crop);
}
}
return "/filter/filter";
}
}
......@@ -310,6 +310,7 @@ filters.view=Current filters
filters.data-is-filtered=The data is filtered.
filters.modify-filters=View & Modify filters
filter.taxonomy=Taxonomy
filter.accenumb=Accession name
filter.crop=Crop
filter.countryOfOrigin=Country of Origin
filter.holdingInstitute=Holding Institute
......
<!DOCTYPE html>
<%@include file="/WEB-INF/jsp/init.jsp"%>
<html>
<head>
<title><spring:message code="filters.page.title" /></title>
</head>
<body>
<h1><spring:message code="filters.view" /></h1>
<div id="allfilters">
<c:if test="${crop ne null}">
<div class="filter-block row">
<div class="col-lg-3">
<spring:message code="filter.crop" />
</div>
<div class="col-lg-9">
<c:out value="${crop.getName(pageContext.response.locale)}" />
</div>
</div>
</c:if>
<c:forEach items="${selectedFilters}" var="filter">
<div class="clearfix filter-block" x-filtername="${filter.key}">
<div class="col-lg-3">
<c:if test="${not filter.core}">
<a href="<c:url value="/descriptors/${filter.key}" />"><c:out value="${filter.title}" /></a>
</c:if>
<c:if test="${filter.core}">
<spring:message code="filter.${filter.name}" />
</c:if>
</div>
<div class="col-lg-5 filter-new">
<c:choose>
<c:when test="${filter.dataType=='NUMERIC'}">
<div class="form-group input-group"><span class="input-group-btn"><input class="span1 form-control" type="text" /><input class="span1 form-control" type="text" /><button class="btn notimportant">+</button></span></div>
</c:when>
<c:when test="${filter.dataType=='BOOLEAN'}">
<div class=""><select><option value="true"><spring:message code="boolean.true" /></option><option value="false"><spring:message code="boolean.false" /></option><option value="null"><spring:message code="boolean.null" /></option></select><button class="notimportant">+</button></div>
</c:when>
<c:otherwise>
<div class="form-group input-group"><span class="input-group-btn"><input class="span2 form-control" type="text" /><button class="btn notimportant">+</button></span></div>
</c:otherwise>
</c:choose>
</div>
<div class="col-lg-4 filter-values" id="filter-${filter.name.replace(':', '_')}"></div>
</div>
</c:forEach>
<div class="row">
<div class="col-lg-offset-3 col-lg-9">
<a id="filtersHref" href=""><button class="btn btn-green pull-left">View!</button></a>
<c:url var="pickUrl" value="/explore/pick">
<c:param name="pick">${pick}</c:param>
<c:param name="crop"><c:out value="${crop.shortName}" /></c:param>
</c:url>
<a href="${pickUrl}"><button class="btn btn-green pull-left">Change filters</button></a>
</div>
</div>
</div>
<div id="filtersJson">${jsonObject}</div>
<content tag="javascript">
<script type="text/javascript">
jQuery(document).ready(function() {
// alert('${jsonString}');
var pick=[];
var filters={};
try {