1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.chemistry.opencmis.client.util;
20
21 import java.io.BufferedWriter;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.io.OutputStream;
26 import java.io.OutputStreamWriter;
27 import java.io.Writer;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.Map;
31
32 import javax.xml.stream.XMLStreamException;
33 import javax.xml.stream.XMLStreamReader;
34 import javax.xml.stream.XMLStreamWriter;
35
36 import org.apache.chemistry.opencmis.commons.definitions.DocumentTypeDefinition;
37 import org.apache.chemistry.opencmis.commons.definitions.FolderTypeDefinition;
38 import org.apache.chemistry.opencmis.commons.definitions.ItemTypeDefinition;
39 import org.apache.chemistry.opencmis.commons.definitions.PolicyTypeDefinition;
40 import org.apache.chemistry.opencmis.commons.definitions.PropertyBooleanDefinition;
41 import org.apache.chemistry.opencmis.commons.definitions.PropertyDateTimeDefinition;
42 import org.apache.chemistry.opencmis.commons.definitions.PropertyDecimalDefinition;
43 import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
44 import org.apache.chemistry.opencmis.commons.definitions.PropertyHtmlDefinition;
45 import org.apache.chemistry.opencmis.commons.definitions.PropertyIdDefinition;
46 import org.apache.chemistry.opencmis.commons.definitions.PropertyIntegerDefinition;
47 import org.apache.chemistry.opencmis.commons.definitions.PropertyStringDefinition;
48 import org.apache.chemistry.opencmis.commons.definitions.PropertyUriDefinition;
49 import org.apache.chemistry.opencmis.commons.definitions.RelationshipTypeDefinition;
50 import org.apache.chemistry.opencmis.commons.definitions.SecondaryTypeDefinition;
51 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
52 import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
53 import org.apache.chemistry.opencmis.commons.enums.Cardinality;
54 import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
55 import org.apache.chemistry.opencmis.commons.enums.DateTimeFormat;
56 import org.apache.chemistry.opencmis.commons.enums.PropertyType;
57 import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
58 import org.apache.chemistry.opencmis.commons.impl.IOUtils;
59 import org.apache.chemistry.opencmis.commons.impl.JSONConverter;
60 import org.apache.chemistry.opencmis.commons.impl.XMLConstants;
61 import org.apache.chemistry.opencmis.commons.impl.XMLConverter;
62 import org.apache.chemistry.opencmis.commons.impl.XMLUtils;
63 import org.apache.chemistry.opencmis.commons.impl.json.parser.JSONParseException;
64 import org.apache.chemistry.opencmis.commons.impl.json.parser.JSONParser;
65
66 public final class TypeUtils {
67
68 private TypeUtils() {
69 }
70
71
72
73
74
75
76
77 public static void writeToXML(TypeDefinition type, OutputStream stream) throws XMLStreamException {
78 if (type == null) {
79 throw new IllegalArgumentException("Type must be set!");
80 }
81 if (stream == null) {
82 throw new IllegalArgumentException("Output stream must be set!");
83 }
84
85 XMLStreamWriter writer = XMLUtils.createWriter(stream);
86 XMLUtils.startXmlDocument(writer);
87 XMLConverter.writeTypeDefinition(writer, CmisVersion.CMIS_1_1, XMLConstants.NAMESPACE_CMIS, type);
88 XMLUtils.endXmlDocument(writer);
89 writer.close();
90 }
91
92
93
94
95
96
97
98 public static void writeToJSON(TypeDefinition type, OutputStream stream) throws IOException {
99 if (type == null) {
100 throw new IllegalArgumentException("Type must be set!");
101 }
102 if (stream == null) {
103 throw new IllegalArgumentException("Output stream must be set!");
104 }
105
106 Writer writer = new BufferedWriter(new OutputStreamWriter(stream, IOUtils.UTF8));
107 JSONConverter.convert(type, DateTimeFormat.SIMPLE).writeJSONString(writer);
108 writer.flush();
109 }
110
111
112
113
114
115
116 public static TypeDefinition readFromXML(InputStream stream) throws XMLStreamException {
117 if (stream == null) {
118 throw new IllegalArgumentException("Input stream must be set!");
119 }
120
121 XMLStreamReader parser = XMLUtils.createParser(stream);
122 if (!XMLUtils.findNextStartElemenet(parser)) {
123 return null;
124 }
125
126 TypeDefinition typeDef = XMLConverter.convertTypeDefinition(parser);
127
128 parser.close();
129
130 return typeDef;
131 }
132
133
134
135
136
137
138 @SuppressWarnings("unchecked")
139 public static TypeDefinition readFromJSON(InputStream stream) throws IOException, JSONParseException {
140 if (stream == null) {
141 throw new IllegalArgumentException("Input stream must be set!");
142 }
143
144 JSONParser parser = new JSONParser();
145 Object json = parser.parse(new InputStreamReader(stream, IOUtils.UTF8));
146
147 if (!(json instanceof Map)) {
148 throw new CmisRuntimeException("Invalid stream! Not a type definition!");
149 }
150
151 return JSONConverter.convertTypeDefinition((Map<String, Object>) json);
152 }
153
154
155
156
157
158
159
160
161 public static boolean checkQueryName(String queryName) {
162 return queryName != null && queryName.length() > 0 && queryName.indexOf(' ') < 0 && queryName.indexOf('\t') < 0
163 && queryName.indexOf('\n') < 0 && queryName.indexOf('\r') < 0 && queryName.indexOf('\f') < 0
164 && queryName.indexOf(',') < 0 && queryName.indexOf('"') < 0 && queryName.indexOf('\'') < 0
165 && queryName.indexOf('\\') < 0 && queryName.indexOf('.') < 0 && queryName.indexOf('(') < 0
166 && queryName.indexOf(')') < 0;
167 }
168
169
170
171
172
173
174 public static List<ValidationError> validateTypeDefinition(TypeDefinition type) {
175 if (type == null) {
176 throw new IllegalArgumentException("Type is null!");
177 }
178
179 List<ValidationError> errors = new ArrayList<TypeUtils.ValidationError>();
180
181 if (type.getId() == null || type.getId().length() == 0) {
182 errors.add(new ValidationError("id", "Type id must be set."));
183 }
184
185 if (type.getLocalName() == null || type.getLocalName().length() == 0) {
186 errors.add(new ValidationError("localName", "Local name must be set."));
187 }
188
189 if (type.getQueryName() != null) {
190 if (type.getQueryName().length() == 0) {
191 errors.add(new ValidationError("queryName", "Query name must not be empty."));
192 } else if (!checkQueryName(type.getQueryName())) {
193 errors.add(new ValidationError("queryName", "Query name contains invalid characters."));
194 }
195 }
196
197 if (type.isCreatable() == null) {
198 errors.add(new ValidationError("creatable", "Creatable flag must be set."));
199 }
200
201 if (type.isFileable() == null) {
202 errors.add(new ValidationError("fileable", "Fileable flag must be set."));
203 }
204
205 if (type.isQueryable() == null) {
206 errors.add(new ValidationError("queryable", "Queryable flag must be set."));
207 } else if (type.isQueryable().booleanValue()) {
208 if (type.getQueryName() == null || type.getQueryName().length() == 0) {
209 errors.add(new ValidationError("queryable",
210 "Queryable flag is set to TRUE, but the query name is not set."));
211 }
212 }
213
214 if (type.isControllablePolicy() == null) {
215 errors.add(new ValidationError("controllablePolicy", "ControllablePolicy flag must be set."));
216 } else if (type.getBaseTypeId() == BaseTypeId.CMIS_SECONDARY
217 && Boolean.TRUE.equals(type.isControllablePolicy())) {
218 errors.add(new ValidationError("controllablePolicy",
219 "ControllablePolicy flag must be FALSE for secondary types."));
220 }
221
222 if (type.isControllableAcl() == null) {
223 errors.add(new ValidationError("controllableACL", "ControllableACL flag must be set."));
224 } else if (type.getBaseTypeId() == BaseTypeId.CMIS_SECONDARY && Boolean.TRUE.equals(type.isControllableAcl())) {
225 errors.add(
226 new ValidationError("controllableACL", "ControllableACL flag must be FALSE for secondary types."));
227 }
228
229 if (type.isFulltextIndexed() == null) {
230 errors.add(new ValidationError("fulltextIndexed", "FulltextIndexed flag must be set."));
231 }
232
233 if (type.isIncludedInSupertypeQuery() == null) {
234 errors.add(new ValidationError("includedInSupertypeQuery", "IncludedInSupertypeQuery flag must be set."));
235 }
236
237 if (type.getBaseTypeId() == null) {
238 errors.add(new ValidationError("baseId", "Base type id must be set."));
239 } else if (!type.getBaseTypeId().value().equals(type.getParentTypeId())) {
240 if (type.getParentTypeId() == null || type.getParentTypeId().length() == 0) {
241 errors.add(new ValidationError("parentId", "Parent type id must be set."));
242 }
243 }
244
245 if (type instanceof DocumentTypeDefinition) {
246 if (type.getBaseTypeId() != BaseTypeId.CMIS_DOCUMENT) {
247 errors.add(new ValidationError("baseId", "Base type id does not match the type."));
248 }
249
250 DocumentTypeDefinition docType = (DocumentTypeDefinition) type;
251
252 if (docType.isVersionable() == null) {
253 errors.add(new ValidationError("versionable", "Versionable flag must be set."));
254 }
255
256 if (docType.getContentStreamAllowed() == null) {
257 errors.add(new ValidationError("contentStreamAllowed", "ContentStreamAllowed flag must be set."));
258 }
259
260 } else if (type instanceof FolderTypeDefinition) {
261 if (type.getBaseTypeId() != BaseTypeId.CMIS_FOLDER) {
262 errors.add(new ValidationError("baseId", "Base type id does not match the type."));
263 }
264
265 } else if (type instanceof RelationshipTypeDefinition) {
266 if (type.getBaseTypeId() != BaseTypeId.CMIS_RELATIONSHIP) {
267 errors.add(new ValidationError("baseId", "Base type id does not match the type."));
268 }
269
270 } else if (type instanceof PolicyTypeDefinition) {
271 if (type.getBaseTypeId() != BaseTypeId.CMIS_POLICY) {
272 errors.add(new ValidationError("baseId", "Base type id does not match the type."));
273 }
274
275 } else if (type instanceof ItemTypeDefinition) {
276 if (type.getBaseTypeId() != BaseTypeId.CMIS_ITEM) {
277 errors.add(new ValidationError("baseId", "Base type id does not match the type."));
278 }
279
280 } else if (type instanceof SecondaryTypeDefinition) {
281 if (type.getBaseTypeId() != BaseTypeId.CMIS_SECONDARY) {
282 errors.add(new ValidationError("baseId", "Base type id does not match the type."));
283 }
284
285 } else {
286 errors.add(new ValidationError("baseId", "Unknown base interface."));
287 }
288
289 return errors;
290 }
291
292
293
294
295
296
297 public static List<ValidationError> validatePropertyDefinition(PropertyDefinition<?> propDef) {
298 if (propDef == null) {
299 throw new IllegalArgumentException("Type is null!");
300 }
301
302 List<ValidationError> errors = new ArrayList<TypeUtils.ValidationError>();
303
304 if (propDef.getId() == null || propDef.getId().length() == 0) {
305 errors.add(new ValidationError("id", "Type id must be set."));
306 }
307
308 if (propDef.getQueryName() != null) {
309 if (propDef.getQueryName().length() == 0) {
310 errors.add(new ValidationError("queryName", "Query name must not be empty."));
311 } else if (!checkQueryName(propDef.getQueryName())) {
312 errors.add(new ValidationError("queryName", "Query name contains invalid characters."));
313 }
314 }
315
316 if (propDef.getCardinality() == null) {
317 errors.add(new ValidationError("cardinality", "Cardinality must be set."));
318 }
319
320 if (propDef.getUpdatability() == null) {
321 errors.add(new ValidationError("updatability", "Updatability must be set."));
322 }
323
324 if (propDef.isInherited() == null) {
325 errors.add(new ValidationError("inherited", "Inherited flag must be set."));
326 }
327
328 if (propDef.isRequired() == null) {
329 errors.add(new ValidationError("required", "Required flag must be set."));
330 }
331
332 if (propDef.isQueryable() == null) {
333 errors.add(new ValidationError("queryable", "Queryable flag must be set."));
334 } else if (propDef.isQueryable().booleanValue()) {
335 if (propDef.getQueryName() == null || propDef.getQueryName().length() == 0) {
336 errors.add(new ValidationError("queryable",
337 "Queryable flag is set to TRUE, but the query name is not set."));
338 }
339 }
340
341 if (propDef.isOrderable() == null) {
342 errors.add(new ValidationError("orderable", "Orderable flag must be set."));
343 } else if (propDef.isOrderable().booleanValue()) {
344 if (propDef.getCardinality() == Cardinality.MULTI) {
345 errors.add(
346 new ValidationError("orderable", "Orderable flag is set to TRUE for a multi-value property."));
347 }
348 }
349
350 if (propDef.getPropertyType() == null) {
351 errors.add(new ValidationError("propertyType", "Property type id must be set."));
352 }
353
354 if (propDef instanceof PropertyIdDefinition) {
355 if (propDef.getPropertyType() != PropertyType.ID) {
356 errors.add(
357 new ValidationError("propertyType", "Property type does not match the property definition."));
358 }
359 } else if (propDef instanceof PropertyStringDefinition) {
360 if (propDef.getPropertyType() != PropertyType.STRING) {
361 errors.add(
362 new ValidationError("propertyType", "Property type does not match the property definition."));
363 }
364 } else if (propDef instanceof PropertyIntegerDefinition) {
365 if (propDef.getPropertyType() != PropertyType.INTEGER) {
366 errors.add(
367 new ValidationError("propertyType", "Property type does not match the property definition."));
368 }
369 } else if (propDef instanceof PropertyDecimalDefinition) {
370 if (propDef.getPropertyType() != PropertyType.DECIMAL) {
371 errors.add(
372 new ValidationError("propertyType", "Property type does not match the property definition."));
373 }
374 } else if (propDef instanceof PropertyBooleanDefinition) {
375 if (propDef.getPropertyType() != PropertyType.BOOLEAN) {
376 errors.add(
377 new ValidationError("propertyType", "Property type does not match the property definition."));
378 }
379 } else if (propDef instanceof PropertyDateTimeDefinition) {
380 if (propDef.getPropertyType() != PropertyType.DATETIME) {
381 errors.add(
382 new ValidationError("propertyType", "Property type does not match the property definition."));
383 }
384 } else if (propDef instanceof PropertyHtmlDefinition) {
385 if (propDef.getPropertyType() != PropertyType.HTML) {
386 errors.add(
387 new ValidationError("propertyType", "Property type does not match the property definition."));
388 }
389 } else if (propDef instanceof PropertyUriDefinition) {
390 if (propDef.getPropertyType() != PropertyType.URI) {
391 errors.add(
392 new ValidationError("propertyType", "Property type does not match the property definition."));
393 }
394 }
395
396 return errors;
397 }
398
399 public static class ValidationError {
400 private final String attribute;
401 private final String error;
402
403 public ValidationError(String attribute, String error) {
404 this.attribute = attribute;
405 this.error = error;
406 }
407
408 public String getAttribute() {
409 return attribute;
410 }
411
412 public String getError() {
413 return error;
414 }
415
416 @Override
417 public String toString() {
418 return attribute + ": " + error;
419 }
420 }
421 }