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