1   package com.atlassian.plugins.rest.module;
2   
3   import com.atlassian.plugins.rest.common.error.jersey.NotFoundExceptionMapper;
4   import com.atlassian.plugins.rest.common.error.jersey.ThrowableExceptionMapper;
5   import com.atlassian.plugins.rest.common.security.jersey.SecurityExceptionMapper;
6   import com.atlassian.plugins.rest.common.security.jersey.SysadminOnlyResourceFilter;
7   import com.atlassian.plugins.rest.common.json.DefaultJsonJaxbContextFactory;
8   import com.atlassian.plugins.rest.module.json.JsonJaxbContextResolver;
9   import com.atlassian.plugins.rest.module.scanner.AnnotatedClassScanner;
10  import com.google.common.base.Preconditions;
11  import com.google.common.collect.Lists;
12  import com.google.common.collect.Sets;
13  import com.sun.jersey.api.core.DefaultResourceConfig;
14  import com.sun.jersey.api.core.ResourceConfig;
15  import com.sun.jersey.spi.container.ContainerRequestFilter;
16  import com.sun.jersey.spi.container.ContainerResponseFilter;
17  import com.sun.jersey.spi.container.ResourceFilterFactory;
18  import org.osgi.framework.Bundle;
19  
20  import java.util.Collection;
21  import java.util.Collections;
22  import java.util.HashSet;
23  import java.util.Set;
24  import javax.ws.rs.Path;
25  import javax.ws.rs.ext.Provider;
26  
27  /**
28   * An implementation of {@link ResourceConfig} that scans a given Osgi Bundle for Jersey resources ({#link Provider} and {@link Path}.
29   */
30  class OsgiResourceConfig extends DefaultResourceConfig
31  {
32      private final Bundle bundle;
33  
34      private final Set<Class<?>> classes = new HashSet<Class<?>>()
35      {{
36              add(NotFoundExceptionMapper.class);
37              add(SecurityExceptionMapper.class);
38              add(ThrowableExceptionMapper.class);
39              add(SysadminOnlyResourceFilter.class);
40          }};
41  
42      private final Set<Object> instances;
43  
44      private Set<Class<?>> scannedClasses;
45  
46      OsgiResourceConfig(Bundle bundle,
47                         Collection<? extends ContainerRequestFilter> containerRequestFilters,
48                         Collection<? extends ContainerResponseFilter> containerResponseFilters,
49                         Collection<? extends ResourceFilterFactory> resourceFilterFactories,
50                         Collection<?> providers)
51      {
52          this.bundle = Preconditions.checkNotNull(bundle);
53  
54          // adds "filters" to Jersey
55          getProperties().put(PROPERTY_CONTAINER_REQUEST_FILTERS, Lists.newLinkedList(containerRequestFilters));
56          getProperties().put(PROPERTY_CONTAINER_RESPONSE_FILTERS, Lists.newLinkedList(containerResponseFilters));
57          getProperties().put(PROPERTY_RESOURCE_FILTER_FACTORIES, Lists.newLinkedList(resourceFilterFactories));
58  
59          this.instances = Sets.newHashSet(Preconditions.checkNotNull(providers));
60          this.instances.add(new JsonJaxbContextResolver(bundle, new DefaultJsonJaxbContextFactory())); // add JSON configuration
61  
62          addInstancesClassesToClasses();
63      }
64  
65      private void addInstancesClassesToClasses()
66      {
67          for (Object o : instances)
68          {
69              classes.add(o.getClass());
70          }
71      }
72  
73      @Override
74      public synchronized Set<Class<?>> getClasses()
75      {
76          if (scannedClasses == null)
77          {
78              scannedClasses = scanForAnnotatedClasses();
79              classes.addAll(scannedClasses);
80          }
81  
82          return classes;
83      }
84  
85      private Set<Class<?>> scanForAnnotatedClasses()
86      {
87          return new AnnotatedClassScanner(bundle, Provider.class, Path.class).scan();
88      }
89  
90      public Set<?> getInstances()
91      {
92          return Collections.unmodifiableSet(instances);
93      }
94  }