001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.fcrepo.webapp;
020
021import java.util.Optional;
022import java.util.concurrent.ExecutorService;
023import java.util.concurrent.Executors;
024import java.util.concurrent.TimeUnit;
025
026import javax.inject.Inject;
027
028import org.fcrepo.config.FedoraPropsConfig;
029import org.fcrepo.http.api.ExternalContentHandlerFactory;
030import org.fcrepo.http.api.ExternalContentPathValidator;
031import org.fcrepo.kernel.api.auth.ACLHandle;
032import org.fcrepo.kernel.api.rdf.RdfNamespaceRegistry;
033
034import org.apache.http.conn.HttpClientConnectionManager;
035import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
036import org.slf4j.Logger;
037import org.slf4j.LoggerFactory;
038import org.springframework.context.annotation.Bean;
039import org.springframework.context.annotation.Configuration;
040import org.springframework.scheduling.annotation.EnableScheduling;
041import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
042
043import com.github.benmanes.caffeine.cache.Cache;
044import com.github.benmanes.caffeine.cache.Caffeine;
045import com.google.common.eventbus.AsyncEventBus;
046import com.google.common.eventbus.EventBus;
047
048/**
049 * Spring config for the webapp
050 *
051 * @author pwinckles
052 */
053@Configuration
054@EnableScheduling
055public class WebappConfig {
056
057    private static final Logger LOGGER = LoggerFactory.getLogger(WebappConfig.class);
058
059    @Inject
060    private FedoraPropsConfig fedoraPropsConfig;
061
062    /**
063     * Task scheduler used for cleaning up transactions
064     *
065     * @return scheduler
066     */
067    @Bean
068    public ThreadPoolTaskScheduler taskScheduler() {
069        final var scheduler = new ThreadPoolTaskScheduler();
070        scheduler.setPoolSize(1);
071        scheduler.setThreadNamePrefix("ScheduledTask");
072        return scheduler;
073    }
074
075    /**
076     * HTTP connection manager
077     *
078     * @return connection manager
079     */
080    @Bean
081    public HttpClientConnectionManager connectionManager() {
082        return new PoolingHttpClientConnectionManager();
083    }
084
085    /**
086     * Fedora's lightweight internal event bus. Currently memory-resident.
087     *
088     * @param propsConfig config
089     * @return event bus
090     */
091    @Bean
092    public EventBus eventBus(final FedoraPropsConfig propsConfig) {
093        return new AsyncEventBus(eventBusExecutor(propsConfig));
094    }
095
096    /**
097     * @param propsConfig config
098     * @return executor intended to be used by the Guava event bus
099     */
100    @Bean
101    public ExecutorService eventBusExecutor(final FedoraPropsConfig propsConfig) {
102        LOGGER.debug("Event bus threads: {}", propsConfig);
103        return Executors.newFixedThreadPool(propsConfig.getEventBusThreads());
104    }
105
106    /**
107     * Configuration of namespace prefixes
108     *
109     * @param propsConfig config properties
110     * @return rdf namespace registry
111     */
112    @Bean(initMethod = "init", destroyMethod = "shutdown")
113    public RdfNamespaceRegistry rdfNamespaceRegistry(final FedoraPropsConfig propsConfig) {
114        final var registry = new RdfNamespaceRegistry();
115        registry.setConfigPath(propsConfig.getNamespaceRegistry());
116        registry.setMonitorForChanges(true);
117        return registry;
118    }
119
120    /**
121     * External content configuration
122     *
123     * @param propsConfig config properties
124     * @return external content path validator
125     */
126    @Bean(initMethod = "init", destroyMethod = "shutdown")
127    public ExternalContentPathValidator externalContentPathValidator(final FedoraPropsConfig propsConfig) {
128        final var validator = new ExternalContentPathValidator();
129        validator.setConfigPath(propsConfig.getExternalContentAllowed());
130        validator.setMonitorForChanges(true);
131        return validator;
132    }
133
134    @Bean
135    public ExternalContentHandlerFactory externalContentHandlerFactory(final ExternalContentPathValidator validator) {
136        final var factory = new ExternalContentHandlerFactory();
137        factory.setValidator(validator);
138        return factory;
139    }
140
141    /**
142     * Used to cache the effective ACL location and authorizations for a given resource.
143     *
144     * @return the cache
145     */
146    @Bean
147    public Cache<String, Optional<ACLHandle>> authHandleCache() {
148        return Caffeine.newBuilder().weakValues()
149                .expireAfterAccess(fedoraPropsConfig.getWebacCacheTimeout(), TimeUnit.MINUTES)
150                .maximumSize(fedoraPropsConfig.getWebacCacheSize()).build();
151    }
152}