001/*
002 * The contents of this file are subject to the license and copyright
003 * detailed in the LICENSE and NOTICE files at the root of the source
004 * tree.
005 */
006
007package org.fcrepo.webapp;
008
009import java.util.Optional;
010import java.util.concurrent.ExecutorService;
011import java.util.concurrent.Executors;
012import java.util.concurrent.TimeUnit;
013
014import javax.inject.Inject;
015import javax.servlet.Filter;
016
017import org.fcrepo.config.FedoraPropsConfig;
018import org.fcrepo.http.api.ExternalContentHandlerFactory;
019import org.fcrepo.http.api.ExternalContentPathValidator;
020import org.fcrepo.kernel.api.auth.ACLHandle;
021import org.fcrepo.kernel.api.rdf.RdfNamespaceRegistry;
022
023import org.apache.http.conn.HttpClientConnectionManager;
024import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
025import org.fcrepo.persistence.ocfl.RepositoryInitializationFilter;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028import org.springframework.context.annotation.Bean;
029import org.springframework.context.annotation.Configuration;
030import org.springframework.scheduling.annotation.EnableAsync;
031import org.springframework.scheduling.annotation.EnableScheduling;
032import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
033
034import com.github.benmanes.caffeine.cache.Cache;
035import com.github.benmanes.caffeine.cache.Caffeine;
036import com.google.common.eventbus.AsyncEventBus;
037import com.google.common.eventbus.EventBus;
038
039/**
040 * Spring config for the webapp
041 *
042 * @author pwinckles
043 */
044@Configuration
045@EnableAsync
046@EnableScheduling
047public class WebappConfig {
048
049    private static final Logger LOGGER = LoggerFactory.getLogger(WebappConfig.class);
050
051    @Inject
052    private FedoraPropsConfig fedoraPropsConfig;
053
054    /**
055     * Task scheduler used for cleaning up transactions
056     *
057     * @return scheduler
058     */
059    @Bean
060    public ThreadPoolTaskScheduler taskScheduler() {
061        final var scheduler = new ThreadPoolTaskScheduler();
062        scheduler.setPoolSize(1);
063        scheduler.setThreadNamePrefix("ScheduledTask");
064        return scheduler;
065    }
066
067    /**
068     * HTTP connection manager
069     *
070     * @return connection manager
071     */
072    @Bean
073    public HttpClientConnectionManager connectionManager() {
074        return new PoolingHttpClientConnectionManager();
075    }
076
077    /**
078     * Fedora's lightweight internal event bus. Currently memory-resident.
079     *
080     * @param propsConfig config
081     * @return event bus
082     */
083    @Bean
084    public EventBus eventBus(final FedoraPropsConfig propsConfig) {
085        return new AsyncEventBus(eventBusExecutor(propsConfig));
086    }
087
088    /**
089     * @param propsConfig config
090     * @return executor intended to be used by the Guava event bus
091     */
092    @Bean
093    public ExecutorService eventBusExecutor(final FedoraPropsConfig propsConfig) {
094        LOGGER.debug("Event bus threads: {}", propsConfig);
095        return Executors.newFixedThreadPool(propsConfig.getEventBusThreads());
096    }
097
098    /**
099     * Configuration of namespace prefixes
100     *
101     * @param propsConfig config properties
102     * @return rdf namespace registry
103     */
104    @Bean(initMethod = "init", destroyMethod = "shutdown")
105    public RdfNamespaceRegistry rdfNamespaceRegistry(final FedoraPropsConfig propsConfig) {
106        final var registry = new RdfNamespaceRegistry();
107        registry.setConfigPath(propsConfig.getNamespaceRegistry());
108        registry.setMonitorForChanges(true);
109        return registry;
110    }
111
112    /**
113     * External content configuration
114     *
115     * @param propsConfig config properties
116     * @return external content path validator
117     */
118    @Bean(initMethod = "init", destroyMethod = "shutdown")
119    public ExternalContentPathValidator externalContentPathValidator(final FedoraPropsConfig propsConfig) {
120        final var validator = new ExternalContentPathValidator();
121        validator.setConfigPath(propsConfig.getExternalContentAllowed());
122        validator.setMonitorForChanges(true);
123        return validator;
124    }
125
126    @Bean
127    public ExternalContentHandlerFactory externalContentHandlerFactory(final ExternalContentPathValidator validator) {
128        final var factory = new ExternalContentHandlerFactory();
129        factory.setValidator(validator);
130        return factory;
131    }
132
133    /**
134     * Used to cache the effective ACL location and authorizations for a given resource.
135     *
136     * @return the cache
137     */
138    @Bean
139    public Cache<String, Optional<ACLHandle>> authHandleCache() {
140        return Caffeine.newBuilder().weakValues()
141                .expireAfterAccess(fedoraPropsConfig.getWebacCacheTimeout(), TimeUnit.MINUTES)
142                .maximumSize(fedoraPropsConfig.getWebacCacheSize()).build();
143    }
144
145    /**
146     * Filter to prevent http requests during repo init
147     *
148     * @return the filter
149     */
150    @Bean
151    public Filter repositoryInitializationFilter() {
152        return new RepositoryInitializationFilter();
153    }
154
155}