This project has retired. For details please refer to its
Attic page.
BrowserBindingUtils 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.browser;
20
21 import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getBooleanParameter;
22 import static org.apache.chemistry.opencmis.server.shared.HttpUtils.getStringParameter;
23
24 import java.io.IOException;
25 import java.math.BigDecimal;
26 import java.math.BigInteger;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.GregorianCalendar;
30 import java.util.List;
31 import java.util.Map;
32
33 import javax.servlet.http.Cookie;
34 import javax.servlet.http.HttpServletRequest;
35 import javax.servlet.http.HttpServletResponse;
36
37 import org.apache.chemistry.opencmis.commons.PropertyIds;
38 import org.apache.chemistry.opencmis.commons.data.Ace;
39 import org.apache.chemistry.opencmis.commons.data.Acl;
40 import org.apache.chemistry.opencmis.commons.data.ContentStream;
41 import org.apache.chemistry.opencmis.commons.data.ObjectData;
42 import org.apache.chemistry.opencmis.commons.data.Properties;
43 import org.apache.chemistry.opencmis.commons.data.PropertyData;
44 import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
45 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
46 import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
47 import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
48 import org.apache.chemistry.opencmis.commons.impl.Base64;
49 import org.apache.chemistry.opencmis.commons.impl.Constants;
50 import org.apache.chemistry.opencmis.commons.impl.TypeCache;
51 import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
52 import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlEntryImpl;
53 import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlListImpl;
54 import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlPrincipalDataImpl;
55 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
56 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl;
57 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyBooleanImpl;
58 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDateTimeImpl;
59 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDecimalImpl;
60 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyHtmlImpl;
61 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIdImpl;
62 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIntegerImpl;
63 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyStringImpl;
64 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyUriImpl;
65 import org.apache.chemistry.opencmis.commons.impl.json.JSONObject;
66 import org.apache.chemistry.opencmis.commons.impl.json.JSONStreamAware;
67 import org.apache.chemistry.opencmis.commons.server.CallContext;
68 import org.apache.chemistry.opencmis.commons.server.CmisService;
69 import org.apache.chemistry.opencmis.server.impl.CallContextImpl;
70 import org.apache.chemistry.opencmis.server.shared.HttpUtils;
71
72 public class BrowserBindingUtils {
73
74 public static final String JSON_MIME_TYPE = "application/json";
75 public static final String HTML_MIME_TYPE = "text/html";
76
77 public static final String ROOT_PATH_FRAGMENT = "root";
78
79 public static final String CONTEXT_OBJECT_ID = "org.apache.chemistry.opencmis.browserbinding.objectId";
80 public static final String CONTEXT_OBJECT_TYPE_ID = "org.apache.chemistry.opencmis.browserbinding.objectTypeId";
81 public static final String CONTEXT_BASETYPE_ID = "org.apache.chemistry.opencmis.browserbinding.basetypeId";
82 public static final String CONTEXT_TRANSACTION = "org.apache.chemistry.opencmis.browserbinding.transaction";
83
84 public enum CallUrl {
85 SERVICE, REPOSITORY, ROOT
86 }
87
88
89 private BrowserBindingUtils() {
90 }
91
92
93
94
95 public static UrlBuilder compileBaseUrl(HttpServletRequest request) {
96 UrlBuilder url = new UrlBuilder(request.getScheme(), request.getServerName(), request.getServerPort(), null);
97
98 url.addPath(request.getContextPath());
99 url.addPath(request.getServletPath());
100
101 return url;
102 }
103
104 public static UrlBuilder compileRepositoryUrl(HttpServletRequest request, String repositoryId) {
105 return compileBaseUrl(request).addPathSegment(repositoryId);
106 }
107
108 public static UrlBuilder compileRootUrl(HttpServletRequest request, String repositoryId) {
109 return compileRepositoryUrl(request, repositoryId).addPathSegment(ROOT_PATH_FRAGMENT);
110 }
111
112
113
114
115 public static String getPath(HttpServletRequest request) {
116 String[] pathFragments = HttpUtils.splitPath(request);
117 if (pathFragments.length < 2) {
118 return null;
119 }
120 if (pathFragments.length == 2) {
121 return "/";
122 }
123
124 StringBuilder sb = new StringBuilder();
125 for (int i = 2; i < pathFragments.length; i++) {
126 if (pathFragments[i].length() == 0) {
127 continue;
128 }
129
130 sb.append("/");
131 sb.append(pathFragments[i]);
132 }
133
134 return sb.toString();
135 }
136
137
138
139
140 public static void prepareContext(CallContext context, CallUrl callUrl, CmisService service, String repositoryId,
141 String objectId, String transaction, HttpServletRequest request) {
142 CallContextImpl contextImpl = null;
143 if (context instanceof CallContextImpl) {
144 contextImpl = (CallContextImpl) context;
145 contextImpl.put(CONTEXT_TRANSACTION, transaction);
146 }
147
148 if (callUrl != CallUrl.ROOT) {
149 return;
150 }
151
152 ObjectData object = null;
153
154 if (objectId != null) {
155 object = service.getObject(repositoryId, objectId, "cmis:objectId,cmis:objectTypeId,cmis:baseTypeId",
156 false, IncludeRelationships.NONE, "cmis:none", false, false, null);
157 } else {
158 object = service.getObjectByPath(repositoryId, getPath(request),
159 "cmis:objectId,cmis:objectTypeId,cmis:baseTypeId", false, IncludeRelationships.NONE, "cmis:none",
160 false, false, null);
161 }
162
163 if (contextImpl != null) {
164 contextImpl.put(CONTEXT_OBJECT_ID, object.getId());
165 contextImpl.put(CONTEXT_OBJECT_TYPE_ID, getProperty(object, PropertyIds.OBJECT_TYPE_ID, String.class));
166 contextImpl.put(CONTEXT_BASETYPE_ID, getProperty(object, PropertyIds.BASE_TYPE_ID, String.class));
167 }
168 }
169
170
171
172
173 @SuppressWarnings("unchecked")
174 public static <T> T getProperty(ObjectData object, String name, Class<T> clazz) {
175 if (object == null) {
176 return null;
177 }
178
179 Properties propData = object.getProperties();
180 if (propData == null) {
181 return null;
182 }
183
184 Map<String, PropertyData<?>> properties = propData.getProperties();
185 if (properties == null) {
186 return null;
187 }
188
189 PropertyData<?> property = properties.get(name);
190 if (property == null) {
191 return null;
192 }
193
194 Object value = property.getFirstValue();
195 if (!clazz.isInstance(value)) {
196 return null;
197 }
198
199 return (T) value;
200 }
201
202 public static Properties createProperties(ControlParser controlParser, String typeId, TypeCache typeCache) {
203 List<String> propertyIds = controlParser.getValues(Constants.CONTROL_PROP_ID);
204 if (propertyIds == null) {
205 return null;
206 }
207
208 Map<Integer, String> singleValuePropertyMap = controlParser.getOneDimMap(Constants.CONTROL_PROP_VALUE);
209 Map<Integer, Map<Integer, String>> multiValuePropertyMap = controlParser
210 .getTwoDimMap(Constants.CONTROL_PROP_VALUE);
211
212 if (typeId == null) {
213
214 int i = 0;
215 for (String propertId : propertyIds) {
216 if (PropertyIds.OBJECT_TYPE_ID.equals(propertId)) {
217 typeId = singleValuePropertyMap.get(i);
218 break;
219 }
220
221 i++;
222 }
223
224 if (typeId == null) {
225 throw new CmisInvalidArgumentException(PropertyIds.OBJECT_TYPE_ID + " not set!");
226 }
227 }
228
229 TypeDefinition typeDef = typeCache.getTypeDefinition(typeId);
230 if (typeDef == null) {
231 throw new CmisInvalidArgumentException("Invalid type: " + typeId);
232 }
233
234 PropertiesImpl result = new PropertiesImpl();
235
236 int i = 0;
237 for (String propertyId : propertyIds) {
238 PropertyDefinition<?> propDef = typeDef.getPropertyDefinitions().get(propertyId);
239 if (propDef == null) {
240 throw new CmisInvalidArgumentException(propertyId + " is unknown!");
241 }
242
243 PropertyData<?> propertyData = null;
244
245 if (singleValuePropertyMap != null && singleValuePropertyMap.containsKey(i)) {
246 propertyData = createPropertyData(propDef, singleValuePropertyMap.get(i));
247 } else if (multiValuePropertyMap != null && multiValuePropertyMap.containsKey(i)) {
248 propertyData = createPropertyData(propDef, controlParser.getValues(Constants.CONTROL_PROP_VALUE, i));
249 } else {
250 propertyData = createPropertyData(propDef, null);
251 }
252
253 result.addProperty(propertyData);
254
255 i++;
256 }
257
258 return result;
259 }
260
261 @SuppressWarnings("unchecked")
262 private static PropertyData<?> createPropertyData(PropertyDefinition<?> propDef, Object value) {
263
264 List<String> strValues;
265 if (value == null) {
266 strValues = Collections.emptyList();
267 } else if (value instanceof String) {
268 strValues = new ArrayList<String>();
269 strValues.add((String) value);
270 } else {
271 strValues = (List<String>) value;
272 }
273
274 PropertyData<?> propertyData = null;
275 switch (propDef.getPropertyType()) {
276 case STRING:
277 propertyData = new PropertyStringImpl(propDef.getId(), strValues);
278 break;
279 case ID:
280 propertyData = new PropertyIdImpl(propDef.getId(), strValues);
281 break;
282 case BOOLEAN:
283 List<Boolean> boolValues = new ArrayList<Boolean>(strValues.size());
284 try {
285 for (String s : strValues) {
286 boolValues.add(Boolean.valueOf(s));
287 }
288 } catch (NumberFormatException e) {
289 throw new CmisInvalidArgumentException(propDef.getId() + " value is not a boolean value!");
290 }
291 propertyData = new PropertyBooleanImpl(propDef.getId(), boolValues);
292 break;
293 case INTEGER:
294 List<BigInteger> intValues = new ArrayList<BigInteger>(strValues.size());
295 try {
296 for (String s : strValues) {
297 intValues.add(new BigInteger(s));
298 }
299 } catch (NumberFormatException e) {
300 throw new CmisInvalidArgumentException(propDef.getId() + " value is not an integer value!");
301 }
302 propertyData = new PropertyIntegerImpl(propDef.getId(), intValues);
303 break;
304 case DECIMAL:
305 List<BigDecimal> decValues = new ArrayList<BigDecimal>(strValues.size());
306 try {
307 for (String s : strValues) {
308 decValues.add(new BigDecimal(s));
309 }
310 } catch (NumberFormatException e) {
311 throw new CmisInvalidArgumentException(propDef.getId() + " value is not an integer value!");
312 }
313 propertyData = new PropertyDecimalImpl(propDef.getId(), decValues);
314 break;
315 case DATETIME:
316 List<GregorianCalendar> calValues = new ArrayList<GregorianCalendar>(strValues.size());
317 try {
318 for (String s : strValues) {
319 GregorianCalendar cal = new GregorianCalendar();
320 cal.setTimeInMillis(Long.parseLong(s));
321 calValues.add(cal);
322 }
323 } catch (NumberFormatException e) {
324 throw new CmisInvalidArgumentException(propDef.getId() + " value is not an datetime value!");
325 }
326 propertyData = new PropertyDateTimeImpl(propDef.getId(), calValues);
327 break;
328 case HTML:
329 propertyData = new PropertyHtmlImpl(propDef.getId(), strValues);
330 break;
331 case URI:
332 propertyData = new PropertyUriImpl(propDef.getId(), strValues);
333 break;
334 }
335
336 return propertyData;
337 }
338
339 public static List<String> createPolicies(ControlParser controlParser) {
340 return controlParser.getValues(Constants.CONTROL_POLICY);
341 }
342
343 public static Acl createAddAcl(ControlParser controlParser) {
344 List<String> principals = controlParser.getValues(Constants.CONTROL_ADD_ACE_PRINCIPAL);
345 if (principals == null) {
346 return null;
347 }
348
349 List<Ace> aces = new ArrayList<Ace>();
350
351 int i = 0;
352 for (String principalId : principals) {
353 aces.add(new AccessControlEntryImpl(new AccessControlPrincipalDataImpl(principalId), controlParser
354 .getValues(Constants.CONTROL_ADD_ACE_PERMISSION, i)));
355 i++;
356 }
357
358 return new AccessControlListImpl(aces);
359 }
360
361 public static Acl createRemoveAcl(ControlParser controlParser) {
362 List<String> principals = controlParser.getValues(Constants.CONTROL_REMOVE_ACE_PRINCIPAL);
363 if (principals == null) {
364 return null;
365 }
366
367 List<Ace> aces = new ArrayList<Ace>();
368
369 int i = 0;
370 for (String principalId : principals) {
371 aces.add(new AccessControlEntryImpl(new AccessControlPrincipalDataImpl(principalId), controlParser
372 .getValues(Constants.CONTROL_REMOVE_ACE_PERMISSION, i)));
373 i++;
374 }
375
376 return new AccessControlListImpl(aces);
377 }
378
379 public static ContentStream createContentStream(HttpServletRequest request) {
380 ContentStreamImpl result = null;
381
382 if (request instanceof POSTHttpServletRequestWrapper) {
383 POSTHttpServletRequestWrapper post = (POSTHttpServletRequestWrapper) request;
384 if (post.getStream() != null) {
385 result = new ContentStreamImpl(post.getFilename(), post.getSize(), post.getContentType(),
386 post.getStream());
387 }
388 }
389
390 return result;
391 }
392
393 protected static ObjectData getSimpleObject(CmisService service, String repositoryId, String objectId) {
394 return service.getObject(repositoryId, objectId, null, false, IncludeRelationships.NONE, "cmis:none", false,
395 false, null);
396 }
397
398
399
400
401
402 public static void setStatus(HttpServletRequest request, HttpServletResponse response, int statusCode) {
403 if (getBooleanParameter(request, Constants.PARAM_SUPPRESS_RESPONSE_CODES, false)) {
404 statusCode = HttpServletResponse.SC_OK;
405 }
406
407 response.setStatus(statusCode);
408 }
409
410
411
412
413 public static String getCookieName(String transaction) {
414 if (transaction == null || transaction.length() == 0) {
415 return "cmis%";
416 }
417
418 return "cmis_" + Base64.encodeBytes(transaction.getBytes()).replace('=', '%');
419 }
420
421
422
423
424 public static void setCookie(HttpServletRequest request, HttpServletResponse response, String repositoryId,
425 String transaction, String value) {
426 setCookie(request, response, repositoryId, transaction, value, 3600);
427 }
428
429
430
431
432 public static void deleteCookie(HttpServletRequest request, HttpServletResponse response, String repositoryId,
433 String transaction) {
434 setCookie(request, response, repositoryId, transaction, "", 0);
435 }
436
437
438
439
440 public static void setCookie(HttpServletRequest request, HttpServletResponse response, String repositoryId,
441 String transaction, String value, int expiry) {
442 if (transaction != null && transaction.length() > 0) {
443 Cookie transactionCookie = new Cookie(getCookieName(transaction), value);
444 transactionCookie.setMaxAge(expiry);
445 transactionCookie.setPath(request.getContextPath() + request.getServletPath() + "/" + repositoryId);
446 response.addCookie(transactionCookie);
447 }
448 }
449
450 public static String createCookieValue(int code, String objectId, String ex, String message) {
451 JSONObject result = new JSONObject();
452
453 result.put("code", code);
454 result.put("objectId", objectId == null ? "" : objectId);
455 result.put("exception", ex == null ? "" : ex);
456 result.put("message", message == null ? "" : message);
457
458 return result.toJSONString();
459 }
460
461
462
463
464
465 public static void writeJSON(JSONStreamAware json, HttpServletRequest request, HttpServletResponse response)
466 throws IOException {
467 String transaction = getStringParameter(request, Constants.PARAM_TRANSACTION);
468
469 if (transaction == null) {
470 response.setContentType(JSON_MIME_TYPE);
471 response.setCharacterEncoding("UTF-8");
472
473 String callback = getStringParameter(request, Constants.PARAM_CALLBACK);
474 if (callback != null) {
475 if (!callback.matches("[A-Za-z0-9._\\[\\]]*")) {
476 throw new CmisInvalidArgumentException("Invalid callback name!");
477 }
478 response.getWriter().print(callback + "(");
479 }
480
481 json.writeJSONString(response.getWriter());
482
483 if (callback != null) {
484 response.getWriter().print(");");
485 }
486 } else {
487 response.setContentType(HTML_MIME_TYPE);
488 response.setContentLength(0);
489 }
490
491 response.getWriter().flush();
492 }
493
494 public static void writeEmpty(HttpServletRequest request, HttpServletResponse response) throws IOException {
495 response.setContentLength(0);
496 response.setContentType("text/plain");
497 response.getWriter().flush();
498 }
499 }