View Javadoc

1   package com.atlassian.plugins.rest.common.multipart.jersey;
2   
3   import com.atlassian.plugins.rest.common.interceptor.impl.DispatchProviderHelper;
4   import com.atlassian.plugins.rest.common.interceptor.impl.InterceptorChainBuilder;
5   import com.atlassian.plugins.rest.common.multipart.FilePart;
6   import com.atlassian.plugins.rest.common.multipart.MultipartForm;
7   import com.atlassian.plugins.rest.common.multipart.MultipartFormParam;
8   import com.sun.jersey.api.core.HttpContext;
9   import com.sun.jersey.api.model.AbstractResourceMethod;
10  import com.sun.jersey.api.model.Parameter;
11  import com.sun.jersey.core.spi.component.ComponentScope;
12  import com.sun.jersey.server.impl.inject.AbstractHttpContextInjectable;
13  import com.sun.jersey.server.impl.inject.InjectableValuesProvider;
14  import com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider;
15  import com.sun.jersey.spi.dispatch.RequestDispatcher;
16  import com.sun.jersey.spi.inject.Injectable;
17  
18  import java.lang.annotation.Annotation;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Set;
24  import javax.ws.rs.core.Context;
25  import javax.ws.rs.ext.Provider;
26  
27  /**
28   * Dispatchs requests to methods with MultipartFormParam parameters
29   *
30   * @since 2.4
31   */
32  @Provider
33  public class MultipartFormDispatchProvider extends AbstractResourceMethodDispatchProvider {
34      private static final String MULTIPART_FORM_PROPERTY = "com.atlassian.rest.multipart.form";
35  
36      private
37      @Context
38      InterceptorChainBuilder interceptorChainBuilder;
39  
40      @Override
41      public RequestDispatcher create(AbstractResourceMethod abstractResourceMethod) {
42          DispatchProviderHelper helper = new DispatchProviderHelper(interceptorChainBuilder);
43          return helper.create(abstractResourceMethod, getInjectableValuesProvider(abstractResourceMethod));
44      }
45  
46      @Override
47      protected InjectableValuesProvider getInjectableValuesProvider(final AbstractResourceMethod method) {
48          // We only return one if we find a MultipartFormParam annotated parameter
49          for (Parameter param : method.getParameters()) {
50              for (Annotation annotation : param.getAnnotations()) {
51                  if (annotation instanceof MultipartFormParam) {
52                      // Here we return an object that will parse the form (done by MultipartFormMessageBodyReader when getEntity() is called)
53                      return new InjectableValuesProvider(getInjectables(method)) {
54                          @Override
55                          public Object[] getInjectableValues(final HttpContext context) {
56                              if (!context.getProperties().containsKey(MULTIPART_FORM_PROPERTY)) {
57                                  context.getProperties().put(MULTIPART_FORM_PROPERTY, context.getRequest().getEntity(
58                                          MultipartForm.class, MultipartForm.class, method.getAnnotations()));
59                              }
60                              return super.getInjectableValues(context);
61                          }
62                      };
63                  }
64              }
65          }
66          return null;
67      }
68  
69      private List<Injectable> getInjectables(AbstractResourceMethod method) {
70          List<Injectable> is = new ArrayList<Injectable>(method.getParameters().size());
71          for (int i = 0; i < method.getParameters().size(); i++) {
72              Parameter parameter = method.getParameters().get(i);
73              Injectable<?> injectable = null;
74              // We don't support entities
75              if (Parameter.Source.ENTITY == parameter.getSource()) {
76                  return null;
77              }
78              for (Annotation annotation : parameter.getAnnotations()) {
79                  if (annotation instanceof MultipartFormParam) {
80                      // It's a multipart parameter, we get the injectable for it
81                      injectable = getMultipartFormInjectable(parameter, (MultipartFormParam) annotation);
82                  }
83              }
84              if (injectable == null) {
85                  // This defaults back so that everything else, eg @HeaderParam, @Context etc can get injected
86                  injectable = getInjectableProviderContext().getInjectable(parameter, ComponentScope.PerRequest);
87              }
88              if (injectable == null) {
89                  return null;
90              }
91              is.add(injectable);
92          }
93          return is;
94      }
95  
96      private Injectable<?> getMultipartFormInjectable(final Parameter parameter, final MultipartFormParam annotation) {
97          // FilePart
98          if (parameter.getParameterClass().equals(FilePart.class)) {
99              return new AbstractHttpContextInjectable<FilePart>() {
100                 public FilePart getValue(final HttpContext context) {
101                     return ((MultipartForm) context.getProperties().get(MULTIPART_FORM_PROPERTY)).getFilePart(annotation.value());
102                 }
103             };
104         }
105         // Collection of file parts
106         if (Collection.class.isAssignableFrom(parameter.getParameterClass())) {
107             return new AbstractHttpContextInjectable<Collection<FilePart>>() {
108                 public Collection<FilePart> getValue(final HttpContext context) {
109                     Collection<FilePart> parts = ((MultipartForm) context.getProperties().get(MULTIPART_FORM_PROPERTY)).getFileParts(annotation.value());
110                     if (parameter.getParameterClass().isAssignableFrom(Collection.class)) {
111                         return parts;
112                     } else if (parameter.getParameterClass().isAssignableFrom(List.class)) {
113                         return new ArrayList<FilePart>(parts);
114                     } else if (parameter.getParameterClass().isAssignableFrom(Set.class)) {
115                         return new HashSet<FilePart>(parts);
116                     }
117                     return null;
118                 }
119             };
120         }
121         return null;
122     }
123 }