View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations under the License.
17   */
18  package org.apache.shindig.social.opensocial.service;
19  
20  import org.apache.shindig.auth.AuthInfo;
21  import org.apache.shindig.auth.SecurityToken;
22  import org.apache.shindig.common.servlet.InjectedServlet;
23  import org.apache.shindig.common.util.ImmediateFuture;
24  import org.apache.shindig.social.ResponseError;
25  import org.apache.shindig.social.core.util.BeanJsonConverter;
26  import org.apache.shindig.social.opensocial.spi.SocialSpiException;
27  
28  import com.google.inject.Inject;
29  import com.google.inject.name.Named;
30  
31  import java.io.IOException;
32  import java.util.Collections;
33  import java.util.concurrent.ExecutionException;
34  import java.util.concurrent.Future;
35  import javax.servlet.http.HttpServletRequest;
36  import javax.servlet.http.HttpServletResponse;
37  
38  /***
39   * Common base class for API servlets.
40   */
41  public abstract class ApiServlet extends InjectedServlet {
42    protected static final String DEFAULT_ENCODING = "UTF-8";
43  
44    private HandlerDispatcher dispatcher;
45    protected BeanJsonConverter jsonConverter;
46    protected BeanConverter xmlConverter;
47    protected BeanConverter atomConverter;
48  
49    @Inject
50    public void setHandlerDispatcher(HandlerDispatcher dispatcher) {
51      this.dispatcher = dispatcher;
52    }
53  
54    @Inject
55    public void setBeanConverters(
56        @Named("shindig.bean.converter.json") BeanConverter jsonConverter,
57        @Named("shindig.bean.converter.xml") BeanConverter xmlConverter,
58        @Named("shindig.bean.converter.atom") BeanConverter atomConverter) {
59      // fix this
60      this.jsonConverter = (BeanJsonConverter) jsonConverter;
61      this.xmlConverter = xmlConverter;
62      this.atomConverter = atomConverter;
63    }
64  
65    protected SecurityToken getSecurityToken(HttpServletRequest servletRequest) {
66      return new AuthInfo(servletRequest).getSecurityToken();
67    }
68  
69    protected abstract void sendError(HttpServletResponse servletResponse, ResponseItem responseItem)
70        throws IOException;
71  
72    protected void sendSecurityError(HttpServletResponse servletResponse) throws IOException {
73      sendError(servletResponse, new ResponseItem(ResponseError.UNAUTHORIZED,
74          "The request did not have a proper security token nor oauth message and unauthenticated "
75              + "requests are not allowed"));
76    }
77  
78    /***
79     * Delivers a request item to the appropriate DataRequestHandler.
80     */
81    protected Future<?> handleRequestItem(RequestItem requestItem,
82        HttpServletRequest servletRequest) {
83      DataRequestHandler handler = dispatcher.getHandler(requestItem.getService());
84  
85      if (handler == null) {
86        return ImmediateFuture.errorInstance(new SocialSpiException(ResponseError.NOT_IMPLEMENTED,
87            "The service " + requestItem.getService() + " is not implemented"));
88      }
89  
90      return handler.handleItem(requestItem);
91    }
92  
93    protected ResponseItem getResponseItem(Future<?> future) {
94      ResponseItem response;
95      try {
96        // TODO: use timeout methods?
97        Object result = future != null ? future.get() : null;
98        // TODO: null is now a supported return value for post/delete, but
99        // is bad for get().
100       response = new ResponseItem(result != null ? result : Collections.emptyMap());
101     } catch (InterruptedException ie) {
102       response = responseItemFromException(ie);
103     } catch (ExecutionException ee) {
104       response = responseItemFromException(ee.getCause());
105     }
106 
107     return response;
108   }
109 
110   protected ResponseItem responseItemFromException(Throwable t) {
111     if (t instanceof SocialSpiException) {
112       SocialSpiException spe = (SocialSpiException) t;
113       return new ResponseItem(spe.getError(), spe.getMessage());
114     }
115 
116     return new ResponseItem(ResponseError.INTERNAL_ERROR, t.getMessage());
117   }
118 
119   protected void setCharacterEncodings(HttpServletRequest servletRequest,
120       HttpServletResponse servletResponse) throws IOException {
121     if (servletRequest.getCharacterEncoding() == null) {
122       servletRequest.setCharacterEncoding(DEFAULT_ENCODING);
123     }
124     servletResponse.setCharacterEncoding(DEFAULT_ENCODING);
125   }
126 }