1 package com.atlassian.plugins.rest.module;
2
3 import com.atlassian.plugin.module.ContainerManagedPlugin;
4 import com.atlassian.plugins.rest.common.expand.AdditionalExpandsProvider;
5 import com.atlassian.plugins.rest.common.expand.SelfExpandingExpander;
6 import com.atlassian.plugins.rest.common.expand.interceptor.ExpandInterceptor;
7 import com.atlassian.plugins.rest.common.expand.resolver.ChainingEntityExpanderResolver;
8 import com.atlassian.plugins.rest.common.expand.resolver.CollectionEntityExpanderResolver;
9 import com.atlassian.plugins.rest.common.expand.resolver.EntityExpanderResolver;
10 import com.atlassian.plugins.rest.common.expand.resolver.ExpandConstraintEntityExpanderResolver;
11 import com.atlassian.plugins.rest.common.expand.resolver.IdentityEntityExpanderResolver;
12 import com.atlassian.plugins.rest.common.expand.resolver.ListWrapperEntityExpanderResolver;
13 import com.atlassian.plugins.rest.common.filter.ExtensionJerseyFilter;
14 import com.atlassian.plugins.rest.common.interceptor.impl.InterceptorChainBuilderProvider;
15 import com.atlassian.plugins.rest.common.security.jersey.AntiSniffingResponseFilter;
16 import com.atlassian.plugins.rest.module.expand.resolver.PluginEntityExpanderResolver;
17 import com.atlassian.plugins.rest.module.filter.AcceptHeaderJerseyMvcFilter;
18 import com.atlassian.plugins.rest.module.filter.AcceptLanguageFilter;
19 import com.atlassian.plugins.rest.module.filter.CorsAcceptOptionsPreflightFilter;
20 import com.atlassian.plugins.rest.module.json.JsonWithPaddingResponseFilter;
21 import com.google.common.collect.ImmutableList;
22 import com.google.common.collect.Lists;
23 import com.sun.jersey.api.core.DefaultResourceConfig;
24 import com.sun.jersey.spi.container.ContainerRequestFilter;
25 import com.sun.jersey.spi.container.ContainerResponseFilter;
26 import com.sun.jersey.spi.container.ResourceFilterFactory;
27 import com.sun.jersey.spi.container.ResourceMethodDispatchProvider;
28 import com.sun.jersey.spi.inject.InjectableProvider;
29 import com.sun.jersey.spi.template.TemplateProcessor;
30
31 import org.codehaus.jackson.map.Module;
32 import org.osgi.framework.Bundle;
33 import org.osgi.framework.BundleContext;
34 import org.osgi.framework.ServiceReference;
35
36 import javax.ws.rs.ext.MessageBodyReader;
37
38 import java.util.Arrays;
39 import java.util.Collection;
40 import java.util.Collections;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Set;
44
45 import static com.atlassian.plugins.rest.module.json.JsonWithPaddingResponseFilter.ATLASSIAN_ALLOW_JSONP;
46 import static com.google.common.collect.Lists.newArrayList;
47
48 public class ResourceConfigManager {
49 private final OsgiServiceAccessor<ResourceFilterFactory> resourceFilterFactories;
50 private final OsgiServiceAccessor<InjectableProvider> injectableProviders;
51 private final OsgiServiceAccessor<TemplateProcessor> templateProcessors;
52 private final OsgiServiceAccessor<MessageBodyReader> messageBodyReaders;
53 private final OsgiServiceAccessor<ResourceMethodDispatchProvider> dispatchProviders;
54 private final OsgiServiceAccessor<Module> modules;
55 private final OsgiServiceAccessor<AdditionalExpandsProvider> additionalExpandsProvider;
56 private final ContainerManagedPlugin plugin;
57 private final Bundle bundle;
58
59 public ResourceConfigManager(ContainerManagedPlugin plugin, Bundle bundle) {
60 this.plugin = plugin;
61 this.bundle = bundle;
62 BundleContext bundleContext = bundle.getBundleContext();
63
64
65 resourceFilterFactories = new OsgiServiceAccessor<ResourceFilterFactory>(ResourceFilterFactory.class, bundleContext, new OsgiFactory<ResourceFilterFactory>() {
66 public ResourceFilterFactory getInstance(BundleContext bundleContext, ServiceReference serviceReference) {
67 return new OsgiServiceReferenceResourceFilterFactory(bundleContext, serviceReference);
68 }
69 });
70
71
72 injectableProviders = new OsgiServiceAccessor<InjectableProvider>(InjectableProvider.class, bundleContext, new OsgiFactory<InjectableProvider>() {
73 public InjectableProvider getInstance(BundleContext bundleContext, ServiceReference serviceReference) {
74 return (InjectableProvider) bundleContext.getService(serviceReference);
75 }
76 });
77
78 templateProcessors = new OsgiServiceAccessor<TemplateProcessor>(TemplateProcessor.class, bundleContext, new OsgiFactory<TemplateProcessor>() {
79 public TemplateProcessor getInstance(BundleContext bundleContext, ServiceReference serviceReference) {
80 return (TemplateProcessor) bundleContext.getService(serviceReference);
81 }
82 });
83
84 messageBodyReaders = new OsgiServiceAccessor<MessageBodyReader>(MessageBodyReader.class, bundleContext, new OsgiFactory<MessageBodyReader>() {
85 public MessageBodyReader getInstance(final BundleContext bundleContext, final ServiceReference serviceReference) {
86 return (MessageBodyReader) bundleContext.getService(serviceReference);
87 }
88 });
89
90 dispatchProviders = new OsgiServiceAccessor<ResourceMethodDispatchProvider>(ResourceMethodDispatchProvider.class, bundleContext, new OsgiFactory<ResourceMethodDispatchProvider>() {
91 public ResourceMethodDispatchProvider getInstance(final BundleContext bundleContext, final ServiceReference serviceReference) {
92 return (ResourceMethodDispatchProvider) bundleContext.getService(serviceReference);
93 }
94 });
95
96 modules = new OsgiServiceAccessor<Module>(Module.class, bundleContext, new OsgiFactory<Module>() {
97 public Module getInstance(final BundleContext bundleContext, final ServiceReference serviceReference) {
98 return (Module) bundleContext.getService(serviceReference);
99 }
100 });
101
102 additionalExpandsProvider = new OsgiServiceAccessor<>(AdditionalExpandsProvider.class, bundleContext, (bundleContext1, serviceReference) -> (AdditionalExpandsProvider) bundleContext1.getService(serviceReference));
103 }
104
105 public DefaultResourceConfig createResourceConfig(Map<String, Object> props, String[] excludes, Set<String> packages) {
106
107 final Collection<String> excludesCollection = excludes != null ? Arrays.asList(excludes) : Collections.<String>emptyList();
108
109 final EntityExpanderResolver expanderResolver = new ChainingEntityExpanderResolver(Lists.<EntityExpanderResolver>newArrayList(
110 new PluginEntityExpanderResolver(plugin),
111 new CollectionEntityExpanderResolver(),
112 new ListWrapperEntityExpanderResolver(),
113 new ExpandConstraintEntityExpanderResolver(),
114 new SelfExpandingExpander.Resolver(),
115 new IdentityEntityExpanderResolver()
116 ));
117
118 final Collection<Object> providers = Lists.newLinkedList();
119 providers.addAll(injectableProviders.get());
120 providers.addAll(templateProcessors.get());
121 providers.addAll(messageBodyReaders.get());
122 providers.addAll(dispatchProviders.get());
123
124 providers.add(new InterceptorChainBuilderProvider(plugin, new ExpandInterceptor(expanderResolver, additionalExpandsProvider.get())));
125
126 List<ContainerRequestFilter> containerRequestFilters = newArrayList(
127 new ExtensionJerseyFilter(excludesCollection),
128 new AcceptHeaderJerseyMvcFilter(),
129 new AcceptLanguageFilter(),
130 new CorsAcceptOptionsPreflightFilter()
131 );
132
133 ImmutableList.Builder containerResponseFilters =
134 new ImmutableList.Builder<ContainerResponseFilter>();
135 containerResponseFilters.add(new AntiSniffingResponseFilter());
136
137 if ("true".equals(System.getProperty(ATLASSIAN_ALLOW_JSONP))) {
138 containerResponseFilters.add(new JsonWithPaddingResponseFilter());
139 }
140
141 final OsgiResourceConfig osgiResourceConfig = new OsgiResourceConfig(bundle, packages,
142 containerRequestFilters,
143 containerResponseFilters.build(),
144 resourceFilterFactories.get(),
145 modules.get(),
146 providers);
147
148 return osgiResourceConfig;
149 }
150
151 public void destroy() {
152 resourceFilterFactories.release();
153 injectableProviders.release();
154 templateProcessors.release();
155 messageBodyReaders.release();
156 dispatchProviders.release();
157 modules.release();
158 additionalExpandsProvider.release();
159 }
160
161
162 }