3 * Copyright (C) 2014 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.cdm
.remote
.config
;
13 import java
.util
.ArrayList
;
14 import java
.util
.Collection
;
15 import java
.util
.List
;
17 import javax
.persistence
.Entity
;
18 import javax
.servlet
.ServletContext
;
20 import org
.apache
.log4j
.Logger
;
21 import org
.hibernate
.Session
;
22 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
23 import org
.springframework
.context
.annotation
.Bean
;
24 import org
.springframework
.context
.annotation
.ComponentScan
;
25 import org
.springframework
.context
.annotation
.Configuration
;
26 import org
.springframework
.context
.annotation
.DependsOn
;
27 import org
.springframework
.context
.annotation
.Import
;
28 import org
.springframework
.core
.type
.filter
.AnnotationTypeFilter
;
29 import org
.springframework
.http
.MediaType
;
30 import org
.springframework
.util
.PathMatcher
;
31 import org
.springframework
.web
.accept
.ContentNegotiationManager
;
32 import org
.springframework
.web
.context
.support
.ServletContextResource
;
33 import org
.springframework
.web
.servlet
.ViewResolver
;
34 import org
.springframework
.web
.servlet
.config
.annotation
.ContentNegotiationConfigurer
;
35 import org
.springframework
.web
.servlet
.config
.annotation
.DefaultServletHandlerConfigurer
;
36 import org
.springframework
.web
.servlet
.config
.annotation
.InterceptorRegistry
;
37 import org
.springframework
.web
.servlet
.config
.annotation
.WebMvcConfigurationSupport
;
38 import org
.springframework
.web
.servlet
.mvc
.method
.annotation
.RequestMappingHandlerMapping
;
39 import org
.springframework
.web
.servlet
.view
.ContentNegotiatingViewResolver
;
40 import org
.springframework
.web
.servlet
.view
.XmlViewResolver
;
42 import com
.mangofactory
.swagger
.configuration
.SpringSwaggerConfig
;
43 import com
.mangofactory
.swagger
.plugin
.EnableSwagger
;
44 import com
.mangofactory
.swagger
.plugin
.SwaggerSpringMvcPlugin
;
45 import com
.wordnik
.swagger
.converter
.ModelConverters
;
46 import com
.wordnik
.swagger
.converter
.OverrideConverter
;
47 import com
.wordnik
.swagger
.model
.ApiInfo
;
49 import eu
.etaxonomy
.cdm
.model
.CdmAssignableTypeFilter
;
50 import eu
.etaxonomy
.cdm
.model
.CdmTypeScanner
;
51 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
52 import eu
.etaxonomy
.cdm
.remote
.controller
.interceptor
.LocaleContextHandlerInterceptor
;
53 import eu
.etaxonomy
.cdm
.remote
.controller
.util
.CdmAntPathMatcher
;
54 import eu
.etaxonomy
.cdm
.remote
.view
.PatternViewResolver
;
57 * @author a.kohlbecker
61 //@EnableWebMvc do not add this since we are overriding WebMvcConfigurationSupport directly, see requestMappingHandlerMapping()
64 @Import(value
={PreloadedBeans
.class})
65 @ComponentScan(basePackages
= {
66 "eu.etaxonomy.cdm.remote.l10n",
67 "eu.etaxonomy.cdm.remote.controller",
68 "eu.etaxonomy.cdm.remote.service",
69 "eu.etaxonomy.cdm.remote.config",
72 public class CdmSpringMVCConfig
extends WebMvcConfigurationSupport
{
75 * turn caching off FOR DEBUGING ONLY !!!!
77 private static final boolean XML_VIEW_CACHING
= true;
79 public static final Logger logger
= Logger
.getLogger(CdmSpringMVCConfig
.class);
83 protected ServletContext servletContext
;
85 @Autowired // is initialized in PreloadedBeans.class
86 private LocaleContextHandlerInterceptor localeContextHandlerInterceptor
;
89 private SpringSwaggerConfig springSwaggerConfig
;
91 // ========================== JSP =================================
92 // public static final String[] WEB_JAR_RESOURCE_PATTERNS = {"css/", "images/", "lib/", "swagger-ui.js"};
93 // public static final String WEB_JAR_RESOURCE_LOCATION = "classpath:META-INF/resources/";
95 // public static final String WEB_JAR_VIEW_RESOLVER_PREFIX = "/WEB-INF/jsp/";
96 // public static final String WEB_JAR_VIEW_RESOLVER_SUFFIX = ".jsp";
98 // public void addResourceHandlers(ResourceHandlerRegistry registry) {
99 // registry.addResourceHandler(WEB_JAR_RESOURCE_PATTERNS)
100 // .addResourceLocations("/")
101 // .addResourceLocations(WEB_JAR_RESOURCE_LOCATION).setCachePeriod(0);
105 // public InternalResourceViewResolver getInternalResourceViewResolverJsp() {
106 // InternalResourceViewResolver resolver = new InternalResourceViewResolver();
107 // resolver.setOrder(0);
108 // resolver.setPrefix(WEB_JAR_VIEW_RESOLVER_PREFIX);
109 // resolver.setSuffix(WEB_JAR_VIEW_RESOLVER_SUFFIX);
110 // // view names (or name patterns) that can be handled
111 // resolver.setViewNames(new String[]{...});
114 // ======================================================================
116 public CdmSpringMVCConfig() {
118 logger
.debug("contructor");
123 public PathMatcher
pathMatcher(){
124 return new CdmAntPathMatcher();
129 @DependsOn({"swaggerSpringMvcPlugin"})
130 public RequestMappingHandlerMapping
requestMappingHandlerMapping() {
131 /* NOTE: this override is the only reason why this class
132 * needs to extends WebMvcConfigurationSupport. We may be able to
133 * remove this method once we no longer need
134 * CdmAntPathMatcher. this is only needed since the contollers need
135 * absolute method level RequestMapping values in some few cases.
137 RequestMappingHandlerMapping handlerMapping
= super.requestMappingHandlerMapping();
138 handlerMapping
.setPathMatcher(pathMatcher());
140 logger
.debug("requestMappingHandlerMapping");
141 return handlerMapping
;
145 @DependsOn({"swaggerSpringMvcPlugin"}) // swaggerSpringMvcPlugin and swaggerGlobalSettings must be loaded earlier
146 public XmlViewResolver
getOaiXmlViewResolver() {
147 XmlViewResolver resolver
= new XmlViewResolver();
148 resolver
.setOrder(1);
149 resolver
.setLocation(new ServletContextResource(servletContext
,"/WEB-INF/oai-views.xml"));
150 resolver
.setCache(XML_VIEW_CACHING
);
156 * @see org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration#addInterceptors(org.springframework.web.servlet.config.annotation.InterceptorRegistry)
159 protected void addInterceptors(InterceptorRegistry registry
) {
160 // TODO does it work?
161 registry
.addInterceptor(localeContextHandlerInterceptor
);
162 logger
.debug("addInterceptors");
167 protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer
) {
168 // DefaultServletHandlerConfigurer: delegates unhandled requests by forwarding to
169 // the Servlet container's "default" servlet, since the DispatcherServlet is mapped to "/"
170 // so static content ad welcome files are handled by the default servlet
172 logger
.debug("configureDefaultServletHandling");
176 public void configureContentNegotiation(ContentNegotiationConfigurer configurer
) {
178 .favorPathExtension(true)
179 .favorParameter(false)
180 .defaultContentType(MediaType
.APPLICATION_JSON
)
181 .mediaType("xml", MediaType
.APPLICATION_XML
)
182 .mediaType("dc", MediaType
.APPLICATION_XML
)
183 .mediaType("rdf", MediaType
.APPLICATION_XML
)
184 .mediaType("rdfxml", MediaType
.APPLICATION_XML
)
185 .mediaType("json", MediaType
.APPLICATION_JSON
);
187 logger
.debug("configureContentNegotiation");
191 * Create the CNVR. Specify the view resolvers to use explicitly. Get Spring to inject
192 * the ContentNegotiationManager created by the configurer (see previous method).
195 @DependsOn({"swaggerSpringMvcPlugin"})
196 public ViewResolver
contentNegotiatingViewResolver(ContentNegotiationManager manager
) {
198 List
<ViewResolver
> resolvers
= new ArrayList
<ViewResolver
>();
200 resolvers
.add(getPatternViewResolver("xml"));
201 resolvers
.add(getPatternViewResolver("json"));
202 resolvers
.add(getPatternViewResolver("rdf"));
204 ContentNegotiatingViewResolver resolver
= new ContentNegotiatingViewResolver();
205 resolver
.setOrder(2);
206 resolver
.setContentNegotiationManager(manager
);
207 resolver
.setViewResolvers(resolvers
);
208 logger
.debug("contentNegotiatingViewResolver");
213 private ViewResolver
getPatternViewResolver(String type
) {
214 PatternViewResolver resolver
= new PatternViewResolver();
215 resolver
.setLocation(new ServletContextResource(servletContext
, "/WEB-INF/"+ type
+ "-views.xml"));
216 resolver
.setCache(XML_VIEW_CACHING
);
220 // -------- Swagger configuration ------------ //
223 * Required to autowire SpringSwaggerConfig
226 public void setSpringSwaggerConfig(SpringSwaggerConfig springSwaggerConfig
) {
227 this.springSwaggerConfig
= springSwaggerConfig
;
228 logger
.debug("setSpringSwaggerConfig");
232 * Every SwaggerSpringMvcPlugin bean is picked up by the swagger-mvc framework - allowing for multiple
233 * swagger groups i.e. same code base multiple swagger resource listings.
235 @Bean(name
="swaggerSpringMvcPlugin")
236 public SwaggerSpringMvcPlugin
swaggerSpringMvcPlugin(){
237 // fully skip the creation of cdm model documentation
238 // since it will be too excessive to scan the huge cdm model
239 // which in fact has cycles.
241 String emptyJSON
= "{}";
242 OverrideConverter sessionConverter
= new OverrideConverter();
244 //TODO failes to convert json to model
245 // "org.json4s.package$MappingException: Did not find value
246 // which can be converted into java.lang.String"
247 sessionConverter
.add(Session
.class.getName(), emptyJSON
);
249 ModelConverters
.addConverter(sessionConverter
, true);
251 logger
.debug("swaggerSpringMvcPlugin");
252 Collection
<Class
<?
extends Object
>> allCdmTypes
= allCdmTypes();
253 allCdmTypes
.add(eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
.class);
254 allCdmTypes
.add(eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacade
.class);
256 return new SwaggerSpringMvcPlugin(this.springSwaggerConfig
)
258 .includePatterns(".*?") // matches all RequestMappings
259 .ignoredParameterTypes(allCdmTypes
.toArray(new Class
[allCdmTypes
.size()])); // is internally merged with the defaultIgnorableParameterTypes of the
265 private Collection
<Class
<?
extends Object
>> allCdmTypes() {
266 boolean includeAbstract
= true;
267 boolean includeInterfaces
= false;
268 Collection
<Class
<?
extends Object
>> classes
= null;
270 CdmTypeScanner
<Object
> scanner
= new CdmTypeScanner
<Object
>(includeAbstract
, includeInterfaces
);
271 scanner
.addIncludeFilter(new AnnotationTypeFilter(Entity
.class));
272 scanner
.addIncludeFilter(new CdmAssignableTypeFilter(CdmBase
.class, includeAbstract
, includeInterfaces
));
273 classes
= scanner
.scanTypesIn("eu/etaxonomy/cdm/model");
278 private ApiInfo
apiInfo() {
279 ApiInfo apiInfo
= new ApiInfo(
280 "CDM Remote REST services",
282 null, // terms of service
283 "EditSupport@bgbm.org",
284 "Mozilla Public License 2.0",
285 "http://www.mozilla.org/MPL/2.0/"