Commit 5891e64a authored by Matija Obreza's avatar Matija Obreza

Merge branch '288-cache-reponses-to-api-queries' into 'master'

Resolve "Cache responses to API queries"

Closes #288

See merge request genesys-pgr/genesys-server!161
parents ad351f4b c0f1deab
......@@ -15,6 +15,8 @@
*/
package org.genesys.catalog.api;
import java.io.EOFException;
import javax.servlet.http.HttpServletRequest;
import org.genesys.catalog.exceptions.InvalidApiUsageException;
......@@ -53,6 +55,11 @@ public class ApiExceptionHandler {
// LOG.warn("Returning BrAPI error: " + ex.getMessage());
// return new ApiError<>(ex);
// }
@ExceptionHandler({ EOFException.class })
public void handleJettyEof(final HttpServletRequest request) {
LOG.warn("Client disconnected {} {}", request.getMethod(), request.getRequestURL());
}
/**
* Handle missing credentials.
......
......@@ -16,6 +16,7 @@
package org.genesys.catalog.service.impl;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Map;
......@@ -27,7 +28,11 @@ import org.genesys.catalog.persistence.ShortFilterRepository;
import org.genesys.catalog.service.ShortFilterService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
......@@ -149,4 +154,45 @@ public class ShortFilterServiceImpl implements ShortFilterService {
ShortFilter shortFilter = shortFilterRepository.findByCode(code);
return mapper.readValue(shortFilter.getJson(), clazz);
}
/**
* A Spring Cache key generator
*/
public static class KeyGen implements KeyGenerator, InitializingBean {
@Autowired(required = false)
private ShortFilterService sfs;
@Override
public void afterPropertiesSet() throws Exception {
if (sfs == null) {
LOG.error("ShortFilterService not set for cache key generator. This is not going to end well.");
}
}
@Override
public Object generate(Object target, Method method, Object... params) {
if (sfs == null) {
throw new RuntimeException("ShortFilterService not set for cache key generator");
}
StringBuilder sb = new StringBuilder();
for (Object p : params) {
if (p instanceof BasicModelFilter) {
BasicModelFilter filter = (BasicModelFilter) p;
sb.append(sfs.getCode(filter));
} else if (p instanceof Pageable) {
Pageable page = (Pageable) p;
sb.append("-").append(page.getOffset());
Sort sort = page.getSort();
sort.forEach(s -> {
sb.append("-").append(s.getProperty()).append("-").append(s.getDirection().ordinal());
});
}
}
// if (sb.length() > 0) {
// System.err.println("Cachekey: " + sb);
// }
return sb.length() > 0 ? sb : null;
}
}
}
......@@ -104,6 +104,7 @@ public abstract class AccessionData extends AuditedVersionedModel implements IdU
@ManyToOne(cascade = {}, optional = true)
@JoinColumn(name = "orgCtyId", nullable = true)
@JsonView({ JsonViews.Minimal.class })
private Country countryOfOrigin;
@Column(name = "sampStat", length = 3)
......@@ -125,6 +126,7 @@ public abstract class AccessionData extends AuditedVersionedModel implements IdU
private Boolean mlsStatus;
@Column(name = "storageStr", length = 100, nullable = true)
@JsonIgnore
private String storageStr;
@Column(name = "acceurl", length = 300, nullable = true)
......@@ -155,6 +157,7 @@ public abstract class AccessionData extends AuditedVersionedModel implements IdU
private String ancest;
@Column(name = "duplSiteStr", length = 100)
@JsonIgnore
private String duplSiteStr;
/**
......@@ -273,7 +276,7 @@ public abstract class AccessionData extends AuditedVersionedModel implements IdU
public void setInTrust(final Boolean inTrust) {
this.inTrust = inTrust;
}
public Boolean isAvailable() {
return available;
}
......@@ -434,9 +437,6 @@ public abstract class AccessionData extends AuditedVersionedModel implements IdU
return this.sampStat;
}
@Transient
@JsonIgnore
// For EL
public Boolean getAvailable() {
return this.available;
}
......@@ -448,9 +448,6 @@ public abstract class AccessionData extends AuditedVersionedModel implements IdU
return this.available;
}
@Transient
@JsonIgnore
// For EL
public Boolean getHistoric() {
return this.historic;
}
......
......@@ -24,6 +24,7 @@ import org.genesys2.server.persistence.AccessionRepository;
import org.genesys2.server.service.AccessionService;
import org.genesys2.server.service.filter.AccessionFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
......@@ -39,7 +40,7 @@ public class AccessionServiceImpl implements AccessionService {
/** The accession repository. */
@Autowired
private AccessionRepository accessionRepository;
private <T extends AccessionData> T lazyLoad(T accession) {
if (accession != null) {
AccessionId accessionId = accession.getAccessionId();
......@@ -96,8 +97,8 @@ public class AccessionServiceImpl implements AccessionService {
* @see org.genesys2.server.service.AccessionService#list(org.genesys2.server.service.filter.AccessionFilter, org.springframework.data.domain.Pageable)
*/
@Override
@Cacheable(value="apiResponses.accessionApi1.list", unless="#result == null", keyGenerator="shortFilterKeyGenerator")
public Page<Accession> list(AccessionFilter filter, Pageable page) {
return accessionRepository.findAll(filter.buildQuery(), page);
}
}
......@@ -27,8 +27,10 @@ import com.hazelcast.web.WebFilter;
import com.hazelcast.web.spring.SpringAwareWebFilter;
import org.genesys.blocks.security.lockout.AccountLockoutManager.AttemptStatistics;
import org.genesys.catalog.service.impl.ShortFilterServiceImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
......@@ -159,4 +161,9 @@ public class CacheConfig {
properties.setProperty("shutdown-on-destroy", "true");
return properties;
}
@Bean("shortFilterKeyGenerator")
public KeyGenerator shortFilterKeyGenerator() {
return new ShortFilterServiceImpl.KeyGen();
}
}
......@@ -175,7 +175,6 @@ public abstract class HazelcastConfig {
}
}
final JoinConfig join = network.getJoin();
if (!hasConfiguredMembers()) {
LOG.warn("Enabling Hazelcast multicast, members={}", Arrays.toString(hazelcastMembers));
......@@ -292,6 +291,19 @@ public abstract class HazelcastConfig {
jettySessionsMapConfig.setTimeToLiveSeconds(60 * 60 * 24); // 1 day
cfg.addMapConfig(jettySessionsMapConfig);
final MapConfig apiResponseConfig = new MapConfig();
apiResponseConfig.setName("apiResponses.*");
apiResponseConfig.setTimeToLiveSeconds(60 * 2); // 2min
apiResponseConfig.setMaxIdleSeconds(30);
apiResponseConfig.setEvictionPolicy(EvictionPolicy.LFU);
// {
// final MaxSizeConfig maxSizeConfig = new MaxSizeConfig();
// maxSizeConfig.setSize(50);
// maxSizeConfig.setMaxSizePolicy(MaxSizePolicy.PER_NODE);
// apiResponseConfig.setMaxSizeConfig(maxSizeConfig);
// }
cfg.addMapConfig(apiResponseConfig);
final ExecutorConfig execConfig = new ExecutorConfig();
execConfig.setName("hazel-exec");
execConfig.setPoolSize(4);
......
......@@ -28,6 +28,8 @@ import org.genesys.blocks.security.service.CustomAclService;
import org.genesys.blocks.security.service.PasswordPolicy;
import org.genesys.blocks.security.service.impl.CustomAclServiceImpl;
import org.genesys.blocks.security.service.impl.SimplePasswordPolicy;
import org.genesys.catalog.service.ShortFilterService;
import org.genesys.catalog.service.impl.ShortFilterServiceImpl;
import org.genesys2.server.aspect.AsAdminAspect;
import org.genesys2.server.persistence.ActivityPostRepository;
import org.genesys2.server.persistence.ArticleRepository;
......@@ -287,6 +289,11 @@ public abstract class AbstractServicesTest extends BaseSpringTest {
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
@Bean
public ShortFilterService shortFilterService() {
return new ShortFilterServiceImpl();
}
@Bean
public static Set<String> supportedLocales() {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment