This project has retired. For details please refer to its
Attic page.
CmisAtomPubServlet xref
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.chemistry.opencmis.server.impl.atompub;
20
21 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_ACL;
22 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_ALLOWABLEACIONS;
23 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_CHANGES;
24 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_CHECKEDOUT;
25 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_CHILDREN;
26 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_CONTENT;
27 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_DESCENDANTS;
28 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_ENTRY;
29 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_FOLDERTREE;
30 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_OBJECTBYID;
31 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_OBJECTBYPATH;
32 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_PARENTS;
33 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_POLICIES;
34 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_QUERY;
35 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_RELATIONSHIPS;
36 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_TYPE;
37 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_TYPES;
38 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_TYPESDESC;
39 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_UNFILED;
40 import static org.apache.chemistry.opencmis.server.impl.atompub.AtomPubUtils.RESOURCE_VERSIONS;
41 import static org.apache.chemistry.opencmis.server.shared.Dispatcher.METHOD_DELETE;
42 import static org.apache.chemistry.opencmis.server.shared.Dispatcher.METHOD_GET;
43 import static org.apache.chemistry.opencmis.server.shared.Dispatcher.METHOD_POST;
44 import static org.apache.chemistry.opencmis.server.shared.Dispatcher.METHOD_PUT;
45
46 import java.io.File;
47 import java.io.IOException;
48 import java.io.PrintWriter;
49
50 import javax.servlet.ServletConfig;
51 import javax.servlet.ServletException;
52 import javax.servlet.http.HttpServlet;
53 import javax.servlet.http.HttpServletRequest;
54 import javax.servlet.http.HttpServletResponse;
55
56 import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException;
57 import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
58 import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException;
59 import org.apache.chemistry.opencmis.commons.exceptions.CmisFilterNotValidException;
60 import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
61 import org.apache.chemistry.opencmis.commons.exceptions.CmisNameConstraintViolationException;
62 import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
63 import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
64 import org.apache.chemistry.opencmis.commons.exceptions.CmisPermissionDeniedException;
65 import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
66 import org.apache.chemistry.opencmis.commons.exceptions.CmisStorageException;
67 import org.apache.chemistry.opencmis.commons.exceptions.CmisStreamNotSupportedException;
68 import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException;
69 import org.apache.chemistry.opencmis.commons.exceptions.CmisVersioningException;
70 import org.apache.chemistry.opencmis.commons.server.CallContext;
71 import org.apache.chemistry.opencmis.commons.server.CmisService;
72 import org.apache.chemistry.opencmis.commons.server.CmisServiceFactory;
73 import org.apache.chemistry.opencmis.server.impl.CmisRepositoryContextListener;
74 import org.apache.chemistry.opencmis.server.impl.ServerVersion;
75 import org.apache.chemistry.opencmis.server.shared.CallContextHandler;
76 import org.apache.chemistry.opencmis.server.shared.Dispatcher;
77 import org.apache.chemistry.opencmis.server.shared.ExceptionHelper;
78 import org.apache.chemistry.opencmis.server.shared.HttpUtils;
79 import org.apache.commons.lang.StringEscapeUtils;
80 import org.apache.commons.logging.Log;
81 import org.apache.commons.logging.LogFactory;
82
83
84
85
86 public class CmisAtomPubServlet extends HttpServlet {
87
88 public static final String PARAM_CALL_CONTEXT_HANDLER = "callContextHandler";
89 public static final String PARAM_TRUSTED_PROXIES = "trustedProxies";
90
91 private static final Log LOG = LogFactory.getLog(CmisAtomPubServlet.class.getName());
92
93 private static final long serialVersionUID = 1L;
94
95 private File tempDir;
96 private int memoryThreshold;
97
98 private Dispatcher dispatcher;
99 private CallContextHandler callContextHandler;
100
101 @Override
102 public void init(ServletConfig config) throws ServletException {
103 super.init(config);
104
105
106 callContextHandler = null;
107 String callContextHandlerClass = config.getInitParameter(PARAM_CALL_CONTEXT_HANDLER);
108 if (callContextHandlerClass != null) {
109 try {
110 callContextHandler = (CallContextHandler) Class.forName(callContextHandlerClass).newInstance();
111 } catch (Exception e) {
112 throw new ServletException("Could not load call context handler: " + e, e);
113 }
114 }
115
116
117 CmisServiceFactory factory = (CmisServiceFactory) config.getServletContext().getAttribute(
118 CmisRepositoryContextListener.SERVICES_FACTORY);
119
120 tempDir = factory.getTempDirectory();
121 memoryThreshold = factory.getMemoryThreshold();
122
123
124 dispatcher = new Dispatcher();
125
126 try {
127 dispatcher.addResource(RESOURCE_TYPES, METHOD_GET, RepositoryService.class, "getTypeChildren");
128 dispatcher.addResource(RESOURCE_TYPESDESC, METHOD_GET, RepositoryService.class, "getTypeDescendants");
129 dispatcher.addResource(RESOURCE_TYPE, METHOD_GET, RepositoryService.class, "getTypeDefinition");
130 dispatcher.addResource(RESOURCE_CHILDREN, METHOD_GET, NavigationService.class, "getChildren");
131 dispatcher.addResource(RESOURCE_DESCENDANTS, METHOD_GET, NavigationService.class, "getDescendants");
132 dispatcher.addResource(RESOURCE_FOLDERTREE, METHOD_GET, NavigationService.class, "getFolderTree");
133 dispatcher.addResource(RESOURCE_PARENTS, METHOD_GET, NavigationService.class, "getObjectParents");
134 dispatcher.addResource(RESOURCE_CHECKEDOUT, METHOD_GET, NavigationService.class, "getCheckedOutDocs");
135 dispatcher.addResource(RESOURCE_ENTRY, METHOD_GET, ObjectService.class, "getObject");
136 dispatcher.addResource(RESOURCE_OBJECTBYID, METHOD_GET, ObjectService.class, "getObject");
137 dispatcher.addResource(RESOURCE_OBJECTBYPATH, METHOD_GET, ObjectService.class, "getObjectByPath");
138 dispatcher.addResource(RESOURCE_ALLOWABLEACIONS, METHOD_GET, ObjectService.class, "getAllowableActions");
139 dispatcher.addResource(RESOURCE_CONTENT, METHOD_GET, ObjectService.class, "getContentStream");
140 dispatcher.addResource(RESOURCE_CONTENT, METHOD_PUT, ObjectService.class, "setContentStream");
141 dispatcher.addResource(RESOURCE_CONTENT, METHOD_DELETE, ObjectService.class, "deleteContentStream");
142 dispatcher.addResource(RESOURCE_CHILDREN, METHOD_POST, ObjectService.class, "create");
143 dispatcher.addResource(RESOURCE_RELATIONSHIPS, METHOD_POST, ObjectService.class, "createRelationship");
144 dispatcher.addResource(RESOURCE_ENTRY, METHOD_PUT, ObjectService.class, "updateProperties");
145 dispatcher.addResource(RESOURCE_ENTRY, METHOD_DELETE, ObjectService.class, "deleteObject");
146 dispatcher.addResource(RESOURCE_DESCENDANTS, METHOD_DELETE, ObjectService.class, "deleteTree");
147 dispatcher.addResource(RESOURCE_CHECKEDOUT, METHOD_POST, VersioningService.class, "checkOut");
148 dispatcher.addResource(RESOURCE_VERSIONS, METHOD_GET, VersioningService.class, "getAllVersions");
149 dispatcher.addResource(RESOURCE_VERSIONS, METHOD_DELETE, VersioningService.class, "deleteAllVersions");
150 dispatcher.addResource(RESOURCE_QUERY, METHOD_GET, DiscoveryService.class, "query");
151 dispatcher.addResource(RESOURCE_QUERY, METHOD_POST, DiscoveryService.class, "query");
152 dispatcher.addResource(RESOURCE_CHANGES, METHOD_GET, DiscoveryService.class, "getContentChanges");
153 dispatcher.addResource(RESOURCE_RELATIONSHIPS, METHOD_GET, RelationshipService.class,
154 "getObjectRelationships");
155 dispatcher.addResource(RESOURCE_UNFILED, METHOD_POST, MultiFilingService.class, "removeObjectFromFolder");
156 dispatcher.addResource(RESOURCE_ACL, METHOD_GET, AclService.class, "getAcl");
157 dispatcher.addResource(RESOURCE_ACL, METHOD_PUT, AclService.class, "applyAcl");
158 dispatcher.addResource(RESOURCE_POLICIES, METHOD_GET, PolicyService.class, "getAppliedPolicies");
159 dispatcher.addResource(RESOURCE_POLICIES, METHOD_POST, PolicyService.class, "applyPolicy");
160 dispatcher.addResource(RESOURCE_POLICIES, METHOD_DELETE, PolicyService.class, "removePolicy");
161 } catch (NoSuchMethodException e) {
162 LOG.error("Cannot initialize dispatcher!", e);
163 }
164 }
165
166 @Override
167 protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException,
168 IOException {
169
170 response.addHeader("Cache-Control", "private, max-age=0");
171 response.addHeader("Server", ServerVersion.OPENCMIS_SERVER);
172
173
174 CallContext context = null;
175 try {
176 context = HttpUtils.createContext(request, response, getServletContext(), CallContext.BINDING_ATOMPUB,
177 callContextHandler, tempDir, memoryThreshold);
178 dispatch(context, request, response);
179 } catch (Exception e) {
180 if (e instanceof CmisPermissionDeniedException) {
181 if ((context == null) || (context.getUsername() == null)) {
182 response.setHeader("WWW-Authenticate", "Basic realm=\"CMIS\"");
183 response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization Required");
184 } else {
185 response.sendError(getErrorCode((CmisPermissionDeniedException) e), e.getMessage());
186 }
187 } else {
188 printError(e, response);
189 }
190 }
191
192
193 response.flushBuffer();
194 }
195
196
197
198
199 private void dispatch(CallContext context, HttpServletRequest request, HttpServletResponse response)
200 throws Exception {
201
202 CmisService service = null;
203 try {
204
205 CmisServiceFactory factory = (CmisServiceFactory) getServletContext().getAttribute(
206 CmisRepositoryContextListener.SERVICES_FACTORY);
207
208 if (factory == null) {
209 throw new CmisRuntimeException("Service factory not available! Configuration problem?");
210 }
211
212
213 service = factory.getService(context);
214
215
216 String[] pathFragments = HttpUtils.splitPath(request);
217
218 if (pathFragments.length < 2) {
219
220 RepositoryService.getRepositories(context, service, request, response);
221 return;
222 }
223
224 String method = request.getMethod();
225 String repositoryId = pathFragments[0];
226 String resource = pathFragments[1];
227
228
229 boolean methodFound = dispatcher.dispatch(resource, method, context, service, repositoryId, request,
230 response);
231
232
233
234 if (!methodFound) {
235 response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Unknown operation");
236 }
237 } finally {
238 if (service != null) {
239 service.close();
240 }
241 }
242 }
243
244
245
246
247 private static int getErrorCode(CmisBaseException ex) {
248 if (ex instanceof CmisConstraintException) {
249 return 409;
250 } else if (ex instanceof CmisContentAlreadyExistsException) {
251 return 409;
252 } else if (ex instanceof CmisFilterNotValidException) {
253 return 400;
254 } else if (ex instanceof CmisInvalidArgumentException) {
255 return 400;
256 } else if (ex instanceof CmisNameConstraintViolationException) {
257 return 409;
258 } else if (ex instanceof CmisNotSupportedException) {
259 return 405;
260 } else if (ex instanceof CmisObjectNotFoundException) {
261 return 404;
262 } else if (ex instanceof CmisPermissionDeniedException) {
263 return 403;
264 } else if (ex instanceof CmisStorageException) {
265 return 500;
266 } else if (ex instanceof CmisStreamNotSupportedException) {
267 return 403;
268 } else if (ex instanceof CmisUpdateConflictException) {
269 return 409;
270 } else if (ex instanceof CmisVersioningException) {
271 return 409;
272 }
273
274 return 500;
275 }
276
277
278
279
280 private static void printError(Exception ex, HttpServletResponse response) {
281 int statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
282 String exceptionName = "runtime";
283
284 if (ex instanceof CmisRuntimeException) {
285 LOG.error(ex.getMessage(), ex);
286 } else if (ex instanceof CmisBaseException) {
287 statusCode = getErrorCode((CmisBaseException) ex);
288 exceptionName = ((CmisBaseException) ex).getExceptionName();
289 } else {
290 LOG.error(ex.getMessage(), ex);
291 }
292
293 try {
294 PrintWriter pw = response.getWriter();
295 response.setStatus(statusCode);
296 response.setContentType("text/html");
297
298 pw.print("<html><head><title>Apache Chemistry OpenCMIS - "
299 + exceptionName
300 + " error</title>"
301 + "<style><!--H1 {font-size:24px;line-height:normal;font-weight:bold;background-color:#f0f0f0;color:#003366;border-bottom:1px solid #3c78b5;padding:2px;} "
302 + "BODY {font-family:Verdana,arial,sans-serif;color:black;font-size:14px;} "
303 + "HR {color:#3c78b5;height:1px;}--></style></head><body>");
304 pw.print("<h1>HTTP Status " + statusCode + " - <!--exception-->" + exceptionName + "<!--/exception--></h1>");
305 pw.print("<p><!--message-->" + StringEscapeUtils.escapeHtml(ex.getMessage()) + "<!--/message--></p>");
306
307 String st = ExceptionHelper.getStacktraceAsString(ex);
308 if (st != null) {
309 pw.print("<hr noshade='noshade'/><!--stacktrace--><pre>\n" + st
310 + "\n</pre><!--/stacktrace--><hr noshade='noshade'/>");
311 }
312
313 pw.print("</body></html>");
314 } catch (Exception e) {
315 LOG.error(e.getMessage(), e);
316 try {
317 response.sendError(statusCode, ex.getMessage());
318 } catch (Exception en) {
319 }
320 }
321 }
322 }