Merge pull request #1843 from atmire/DS-3697_Autowire-DSpace-service-in-Spring-REST-webapp

DS-3697: Enable autowiring of DSpace Services in the Spring REST webapp
This commit is contained in:
Andrea Bollini
2017-10-11 13:47:49 +02:00
committed by GitHub
16 changed files with 164 additions and 84 deletions

View File

@@ -10,6 +10,8 @@ package org.dspace.kernel;
import java.util.List;
import java.util.Map;
import org.springframework.context.ConfigurableApplicationContext;
/**
* Allows for non-specific access to the core services.
* No dependency on the underlying mechanism is exposed.
@@ -18,6 +20,11 @@ import java.util.Map;
*/
public interface ServiceManager {
/**
* Get the application context
*/
public ConfigurableApplicationContext getApplicationContext();
/**
* Allows developers to get the desired service singleton by the provided type. <br>
* This should return all instantiated objects of the type specified

View File

@@ -7,7 +7,13 @@
*/
package org.dspace.servicemanager;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang.ArrayUtils;
@@ -24,6 +30,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.context.ConfigurableApplicationContext;
/**
* This is the core service manager which ties together the other
@@ -301,6 +308,11 @@ public final class DSpaceServiceManager implements ServiceManagerSystem {
return service;
}
@Override
public ConfigurableApplicationContext getApplicationContext() {
return primaryServiceManager.getApplicationContext();
}
public <T> List<T> getServicesByType(Class<T> type) {
checkRunning();
if (type == null) {

View File

@@ -42,6 +42,7 @@ public final class SpringServiceManager implements ServiceManagerSystem {
/**
* @return the parent core Spring {@link ApplicationContext}
*/
@Override
public ClassPathXmlApplicationContext getApplicationContext() {
return applicationContext;
}

View File

@@ -10,6 +10,8 @@ package org.dspace.servicemanager;
import java.util.List;
import java.util.Map;
import org.springframework.context.ConfigurableApplicationContext;
/**
* This Mock allows us to pretend that a SMS is its own parent,
@@ -59,9 +61,13 @@ public class MockServiceManagerSystem implements ServiceManagerSystem {
return this.sms.getServiceByName(name, type);
}
public ConfigurableApplicationContext getApplicationContext() {
return sms.getApplicationContext();
}
/* (non-Javadoc)
* @see org.dspace.kernel.ServiceManager#getServicesByType(java.lang.Class)
*/
* @see org.dspace.kernel.ServiceManager#getServicesByType(java.lang.Class)
*/
public <T> List<T> getServicesByType(Class<T> type) {
return this.sms.getServicesByType(type);
}

View File

@@ -17,7 +17,7 @@ import java.util.Map;
import org.dspace.kernel.ServiceManager;
import org.dspace.kernel.mixins.OrderedService;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
/**
* Tests the usage of the provider stack
@@ -60,6 +60,11 @@ public class ProviderStackTest {
public <T> T getServiceByName(String name, Class<T> type) {
return null;
}
public ConfigurableApplicationContext getApplicationContext() {
return null;
}
public <T> List<T> getServicesByType(Class<T> type) {
return new ArrayList<T>();
}

View File

@@ -30,7 +30,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.core.annotation.Order;
import org.springframework.hateoas.RelProvider;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
@@ -38,9 +41,9 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* Define the Spring Boot Application settings itself. This class takes the place
* Define the Spring Boot Application settings itself. This class takes the place
* of a web.xml file, and configures all Filters/Listeners as methods (see below).
* <P>
* <p>
* NOTE: Requires a Servlet 3.0 container, e.g. Tomcat 7.0 or above.
* <p>
* NOTE: This extends SpringBootServletInitializer in order to allow us to build
@@ -51,21 +54,26 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
* @author Tim Donohue
*/
@SpringBootApplication
public class Application extends SpringBootServletInitializer
{
public class Application extends SpringBootServletInitializer {
private static final Logger log = LoggerFactory.getLogger(Application.class);
@Autowired
private ApplicationConfig configuration;
@Autowired
private ConfigurableApplicationContext springBootApplicationContext;
/**
* Override the default SpringBootServletInitializer.configure() method,
* passing it this Application class.
* <P>
* <p>
* This is necessary to allow us to build a deployable WAR, rather than
* always relying on embedded Tomcat.
* <P>
* <p>
* <p>
* See: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-create-a-deployable-war-file
*
* @param application
* @return
*/
@@ -78,57 +86,64 @@ public class Application extends SpringBootServletInitializer
public ServletContextInitializer contextInitializer() {
return new ServletContextInitializer() {
private transient DSpaceKernelImpl kernelImpl;
private transient DSpaceKernelImpl kernelImpl;
@Override
public void onStartup(ServletContext servletContext)
throws ServletException {
servletContext.setInitParameter("dspace.dir",configuration.getDspaceHome());
// start the kernel when the webapp starts
try {
this.kernelImpl = DSpaceKernelInit.getKernel(null);
if (! this.kernelImpl.isRunning()) {
this.kernelImpl.start(getProvidedHome(configuration.getDspaceHome())); // init the kernel
}
} catch (Exception e) {
// failed to start so destroy it and log and throw an exception
try {
this.kernelImpl.destroy();
} catch (Exception e1) {
// nothing
}
String message = "Failure during filter init: " + e.getMessage();
System.err.println(message + ":" + e);
throw new RuntimeException(message, e);
servletContext.setInitParameter("dspace.dir", configuration.getDspaceHome());
// start the kernel when the webapp starts
try {
this.kernelImpl = DSpaceKernelInit.getKernel(null);
if (!this.kernelImpl.isRunning()) {
this.kernelImpl.start(getProvidedHome(configuration.getDspaceHome())); // init the kernel
}
//Set the DSpace Kernel Application context as a parent of the Spring Boot context so that
//we can auto-wire all DSpace Kernel services
springBootApplicationContext.setParent(kernelImpl.getServiceManager().getApplicationContext());
//Add a listener for Spring Boot application shutdown so that we can nicely cleanup the DSpace kernel.
springBootApplicationContext.addApplicationListener(new DSpaceKernelDestroyer(kernelImpl));
} catch (Exception e) {
// failed to start so destroy it and log and throw an exception
try {
this.kernelImpl.destroy();
} catch (Exception e1) {
// nothing
}
String message = "Failure during ServletContext initialisation: " + e.getMessage();
log.error(message + ":" + e.getMessage(), e);
throw new RuntimeException(message, e);
}
}
/*
/**
* Find DSpace's "home" directory.
* Initially look for JNDI Resource called "java:/comp/env/dspace.dir".
* If not found, look for "dspace.dir" initial context parameter.
*/
private String getProvidedHome(String dspaceHome){
String providedHome = null;
try {
Context ctx = new InitialContext();
providedHome = (String) ctx.lookup("java:/comp/env/" + DSpaceConfigurationService.DSPACE_HOME);
} catch (Exception e) {
// do nothing
}
if (providedHome == null)
{
if(dspaceHome != null && !dspaceHome.equals("") &&
!dspaceHome.equals("${" + DSpaceConfigurationService.DSPACE_HOME + "}")){
File test = new File(dspaceHome);
if(test.exists() && new File(test,DSpaceConfigurationService.DSPACE_CONFIG_PATH).exists()) {
providedHome = dspaceHome;
private String getProvidedHome(String dspaceHome) {
String providedHome = null;
try {
Context ctx = new InitialContext();
providedHome = (String) ctx.lookup("java:/comp/env/" + DSpaceConfigurationService.DSPACE_HOME);
} catch (Exception e) {
// do nothing
}
if (providedHome == null) {
if (dspaceHome != null && !dspaceHome.equals("") &&
!dspaceHome.equals("${" + DSpaceConfigurationService.DSPACE_HOME + "}")) {
File test = new File(dspaceHome);
if (test.exists() && new File(test, DSpaceConfigurationService.DSPACE_CONFIG_PATH).exists()) {
providedHome = dspaceHome;
}
}
}
return providedHome;
}
}
return providedHome;
}
};
@@ -137,6 +152,7 @@ public class Application extends SpringBootServletInitializer
/**
* Register the "DSpaceContextListener" so that it is loaded
* for this Application.
*
* @return DSpaceContextListener
*/
@Bean
@@ -146,11 +162,11 @@ public class Application extends SpringBootServletInitializer
// (and loads all DSpace configs)
return new DSpaceContextListener();
}
/**
* Register the DSpaceWebappServletFilter, which initializes the
* DSpace RequestService / SessionService
*
*
* @return DSpaceWebappServletFilter
*/
@Bean
@@ -158,7 +174,7 @@ public class Application extends SpringBootServletInitializer
protected Filter dspaceWebappServletFilter() {
return new DSpaceWebappServletFilter();
}
/**
* Register the DSpaceRequestContextFilter, a Filter which checks for open
* Context objects *after* a request has been fully processed, and closes them
@@ -170,12 +186,12 @@ public class Application extends SpringBootServletInitializer
protected Filter dspaceRequestContextFilter() {
return new DSpaceRequestContextFilter();
}
@Bean
protected RelProvider dspaceRelProvider() {
return new DSpaceRelProvider();
return new DSpaceRelProvider();
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@@ -183,9 +199,25 @@ public class Application extends SpringBootServletInitializer
public void addCorsMappings(CorsRegistry registry) {
String[] corsAllowedOrigins = configuration.getCorsAllowedOrigins();
if (corsAllowedOrigins != null) {
registry.addMapping("/api/**").allowedOrigins(corsAllowedOrigins);
registry.addMapping("/api/**").allowedOrigins(corsAllowedOrigins);
}
}
};
}
/** Utility class that will destory the DSpace Kernel on Spring Boot shutdown */
private class DSpaceKernelDestroyer implements ApplicationListener<ContextClosedEvent> {
private DSpaceKernelImpl kernelImpl;
public DSpaceKernelDestroyer(DSpaceKernelImpl kernelImpl) {
this.kernelImpl = kernelImpl;
}
public void onApplicationEvent(final ContextClosedEvent event) {
if (this.kernelImpl != null) {
this.kernelImpl.destroy();
this.kernelImpl = null;
}
}
}
}

View File

@@ -14,7 +14,6 @@ import org.dspace.app.rest.converter.BitstreamFormatConverter;
import org.dspace.app.rest.model.BitstreamFormatRest;
import org.dspace.app.rest.model.hateoas.BitstreamFormatResource;
import org.dspace.content.BitstreamFormat;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamFormatService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
@@ -22,6 +21,7 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
/**
* This is the repository responsible to manage BitstreamFormat Rest object
*
@@ -30,7 +30,10 @@ import org.springframework.stereotype.Component;
*/
@Component(BitstreamFormatRest.CATEGORY + "." + BitstreamFormatRest.NAME)
public class BitstreamFormatRestRepository extends DSpaceRestRepository<BitstreamFormatRest, Integer> {
BitstreamFormatService bfs = ContentServiceFactory.getInstance().getBitstreamFormatService();
@Autowired
BitstreamFormatService bfs;
@Autowired
BitstreamFormatConverter converter;

View File

@@ -20,7 +20,6 @@ import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.hateoas.BitstreamResource;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
@@ -38,7 +37,10 @@ import org.springframework.stereotype.Component;
@Component(BitstreamRest.CATEGORY + "." + BitstreamRest.NAME)
public class BitstreamRestRepository extends DSpaceRestRepository<BitstreamRest, UUID> {
BitstreamService bs = ContentServiceFactory.getInstance().getBitstreamService();
@Autowired
BitstreamService bs;
@Autowired
BitstreamConverter converter;

View File

@@ -12,7 +12,6 @@ import java.util.Arrays;
import java.util.Iterator;
import java.util.UUID;
import java.util.function.Consumer;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
@@ -27,7 +26,6 @@ import org.dspace.browse.BrowseIndex;
import org.dspace.browse.BrowseInfo;
import org.dspace.browse.BrowserScope;
import org.dspace.content.DSpaceObject;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.core.Context;
@@ -56,9 +54,11 @@ public class BrowseEntryLinkRepository extends AbstractDSpaceRestRepository
@Autowired
BrowseIndexConverter bixConverter;
CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
@Autowired
CollectionService collectionService;
CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
@Autowired
CommunityService communityService;
// FIXME It will be nice to drive arguments binding by annotation as in normal spring controller methods
public Page<BrowseEntryRest> listBrowseEntries(HttpServletRequest request, String browseName,
@@ -67,7 +67,7 @@ public class BrowseEntryLinkRepository extends AbstractDSpaceRestRepository
// argument
String scope = null;
if (request != null) {
request.getParameter("scope");
scope = request.getParameter("scope");
}
Context context = obtainContext();

View File

@@ -10,7 +10,6 @@ package org.dspace.app.rest.repository;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
@@ -25,7 +24,6 @@ import org.dspace.browse.BrowseInfo;
import org.dspace.browse.BrowserScope;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.core.Context;
@@ -56,9 +54,11 @@ public class BrowseItemLinkRepository extends AbstractDSpaceRestRepository
@Autowired
ItemRestRepository itemRestRepository;
CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
@Autowired
CollectionService collectionService;
@Autowired
CommunityService communityService;
public Page<ItemRest> listBrowseItems(HttpServletRequest request, String browseName, Pageable pageable, String projection)
throws BrowseException, SQLException {

View File

@@ -16,7 +16,6 @@ import org.dspace.app.rest.converter.CollectionConverter;
import org.dspace.app.rest.model.CollectionRest;
import org.dspace.app.rest.model.hateoas.CollectionResource;
import org.dspace.content.Collection;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
@@ -34,7 +33,10 @@ import org.springframework.stereotype.Component;
@Component(CollectionRest.CATEGORY + "." + CollectionRest.NAME)
public class CollectionRestRepository extends DSpaceRestRepository<CollectionRest, UUID> {
CollectionService cs = ContentServiceFactory.getInstance().getCollectionService();
@Autowired
CollectionService cs;
@Autowired
CollectionConverter converter;

View File

@@ -17,7 +17,6 @@ import org.dspace.app.rest.converter.CommunityConverter;
import org.dspace.app.rest.model.CommunityRest;
import org.dspace.app.rest.model.hateoas.CommunityResource;
import org.dspace.content.Community;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CommunityService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
@@ -37,7 +36,10 @@ import org.springframework.stereotype.Component;
@Component(CommunityRest.CATEGORY + "." + CommunityRest.NAME)
public class CommunityRestRepository extends DSpaceRestRepository<CommunityRest, UUID> {
CommunityService cs = ContentServiceFactory.getInstance().getCommunityService();
@Autowired
CommunityService cs;
@Autowired
CommunityConverter converter;

View File

@@ -17,7 +17,6 @@ import org.dspace.app.rest.converter.ItemConverter;
import org.dspace.app.rest.model.ItemRest;
import org.dspace.app.rest.model.hateoas.ItemResource;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
@@ -35,7 +34,10 @@ import org.springframework.stereotype.Component;
@Component(ItemRest.CATEGORY + "." + ItemRest.NAME)
public class ItemRestRepository extends DSpaceRestRepository<ItemRest, UUID> {
ItemService is = ContentServiceFactory.getInstance().getItemService();
@Autowired
ItemService is;
@Autowired
ItemConverter converter;

View File

@@ -14,7 +14,6 @@ import org.dspace.app.rest.converter.MetadataFieldConverter;
import org.dspace.app.rest.model.MetadataFieldRest;
import org.dspace.app.rest.model.hateoas.MetadataFieldResource;
import org.dspace.content.MetadataField;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
@@ -30,7 +29,10 @@ import org.springframework.stereotype.Component;
*/
@Component(MetadataFieldRest.CATEGORY + "." + MetadataFieldRest.NAME)
public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFieldRest, Integer> {
MetadataFieldService metaFieldService = ContentServiceFactory.getInstance().getMetadataFieldService();
@Autowired
MetadataFieldService metaFieldService;
@Autowired
MetadataFieldConverter converter;

View File

@@ -14,7 +14,6 @@ import org.dspace.app.rest.converter.MetadataSchemaConverter;
import org.dspace.app.rest.model.MetadataSchemaRest;
import org.dspace.app.rest.model.hateoas.MetadataSchemaResource;
import org.dspace.content.MetadataSchema;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
@@ -30,7 +29,10 @@ import org.springframework.stereotype.Component;
*/
@Component(MetadataSchemaRest.CATEGORY + "." + MetadataSchemaRest.NAME)
public class MetadataSchemaRestRepository extends DSpaceRestRepository<MetadataSchemaRest, Integer> {
MetadataSchemaService metaScemaService = ContentServiceFactory.getInstance().getMetadataSchemaService();
@Autowired
MetadataSchemaService metaScemaService;
@Autowired
MetadataSchemaConverter converter;

View File

@@ -16,7 +16,6 @@ import org.dspace.app.rest.converter.SiteConverter;
import org.dspace.app.rest.model.SiteRest;
import org.dspace.app.rest.model.hateoas.SiteResource;
import org.dspace.content.Site;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.SiteService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
@@ -34,7 +33,10 @@ import org.springframework.stereotype.Component;
@Component(SiteRest.CATEGORY + "." + SiteRest.NAME)
public class SiteRestRepository extends DSpaceRestRepository<SiteRest, UUID> {
SiteService sitesv = ContentServiceFactory.getInstance().getSiteService();
@Autowired
SiteService sitesv;
@Autowired
SiteConverter converter;