activating the swagger rest service documentation by reverting the revertion of the...
[cdmlib.git] / cdmlib-remote-webapp / src / main / java / eu / etaxonomy / cdm / remote / config / CdmSpringMVCConfig.java
1 // $Id$
2 /**
3 * Copyright (C) 2014 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
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.
9 */
10 package eu.etaxonomy.cdm.remote.config;
11
12
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.List;
16
17 import javax.persistence.Entity;
18 import javax.servlet.ServletContext;
19
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;
41
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;
48
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;
55
56 /**
57 * @author a.kohlbecker
58 * @date Jul 1, 2014
59 *
60 */
61 //@EnableWebMvc do not add this since we are overriding WebMvcConfigurationSupport directly, see requestMappingHandlerMapping()
62 @EnableSwagger
63 @Configuration
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",
70 }
71 )
72 public class CdmSpringMVCConfig extends WebMvcConfigurationSupport {
73
74 /**
75 * turn caching off FOR DEBUGING ONLY !!!!
76 */
77 private static final boolean XML_VIEW_CACHING = true;
78
79 public static final Logger logger = Logger.getLogger(CdmSpringMVCConfig.class);
80
81
82 @Autowired
83 protected ServletContext servletContext;
84
85 @Autowired // is initialized in PreloadedBeans.class
86 private LocaleContextHandlerInterceptor localeContextHandlerInterceptor;
87
88
89 private SpringSwaggerConfig springSwaggerConfig;
90
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/";
94 //
95 // public static final String WEB_JAR_VIEW_RESOLVER_PREFIX = "/WEB-INF/jsp/";
96 // public static final String WEB_JAR_VIEW_RESOLVER_SUFFIX = ".jsp";
97 // @Override
98 // public void addResourceHandlers(ResourceHandlerRegistry registry) {
99 // registry.addResourceHandler(WEB_JAR_RESOURCE_PATTERNS)
100 // .addResourceLocations("/")
101 // .addResourceLocations(WEB_JAR_RESOURCE_LOCATION).setCachePeriod(0);
102 // }
103
104 // @Bean
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[]{...});
112 // return resolver;
113 // }
114 // ======================================================================
115
116 public CdmSpringMVCConfig() {
117 super();
118 logger.debug("contructor");
119
120 }
121
122 @Bean
123 public PathMatcher pathMatcher(){
124 return new CdmAntPathMatcher();
125 }
126
127 @Override
128 @Bean
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.
136 */
137 RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
138 handlerMapping.setPathMatcher(pathMatcher());
139
140 logger.debug("requestMappingHandlerMapping");
141 return handlerMapping;
142 }
143
144 @Bean
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);
151 return resolver;
152 }
153
154
155 /* (non-Javadoc)
156 * @see org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration#addInterceptors(org.springframework.web.servlet.config.annotation.InterceptorRegistry)
157 */
158 @Override
159 protected void addInterceptors(InterceptorRegistry registry) {
160 // TODO does it work?
161 registry.addInterceptor(localeContextHandlerInterceptor);
162 logger.debug("addInterceptors");
163 }
164
165
166 @Override
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
171 configurer.enable();
172 logger.debug("configureDefaultServletHandling");
173 }
174
175 @Override
176 public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
177 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);
186
187 logger.debug("configureContentNegotiation");
188 }
189
190 /**
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).
193 */
194 @Bean
195 @DependsOn({"swaggerSpringMvcPlugin"})
196 public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
197
198 List<ViewResolver> resolvers = new ArrayList<ViewResolver>();
199
200 resolvers.add(getPatternViewResolver("xml"));
201 resolvers.add(getPatternViewResolver("json"));
202 resolvers.add(getPatternViewResolver("rdf"));
203
204 ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
205 resolver.setOrder(2);
206 resolver.setContentNegotiationManager(manager);
207 resolver.setViewResolvers(resolvers);
208 logger.debug("contentNegotiatingViewResolver");
209 return resolver;
210 }
211
212
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);
217 return resolver;
218 }
219
220 // -------- Swagger configuration ------------ //
221
222 /**
223 * Required to autowire SpringSwaggerConfig
224 */
225 @Autowired
226 public void setSpringSwaggerConfig(SpringSwaggerConfig springSwaggerConfig) {
227 this.springSwaggerConfig = springSwaggerConfig;
228 logger.debug("setSpringSwaggerConfig");
229 }
230
231 /**
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.
234 */
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.
240
241 String emptyJSON = "{}";
242 OverrideConverter sessionConverter = new OverrideConverter();
243
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);
248
249 ModelConverters.addConverter(sessionConverter, true);
250
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);
255
256 return new SwaggerSpringMvcPlugin(this.springSwaggerConfig)
257 .apiInfo(apiInfo())
258 .includePatterns(".*?") // matches all RequestMappings
259 .ignoredParameterTypes(allCdmTypes.toArray(new Class[allCdmTypes.size()])); // is internally merged with the defaultIgnorableParameterTypes of the
260 }
261
262 /**
263 * @return
264 */
265 private Collection<Class<? extends Object>> allCdmTypes() {
266 boolean includeAbstract = true;
267 boolean includeInterfaces = false;
268 Collection<Class<? extends Object>> classes = null;
269
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");
274
275 return classes;
276 }
277
278 private ApiInfo apiInfo() {
279 ApiInfo apiInfo = new ApiInfo(
280 "CDM Remote REST services",
281 "",
282 null, // terms of service
283 "EditSupport@bgbm.org",
284 "Mozilla Public License 2.0",
285 "http://www.mozilla.org/MPL/2.0/"
286 );
287 return apiInfo;
288 }
289
290
291 }