1 package com.fasterxml.jackson.dataformat.cbor;
2
3 import java.io.*;
4 import java.net.URL;
5
6 import com.fasterxml.jackson.core.*;
7 import com.fasterxml.jackson.core.format.InputAccessor;
8 import com.fasterxml.jackson.core.format.MatchStrength;
9 import com.fasterxml.jackson.core.io.IOContext;
10
11 /**
12 * Factory used for constructing {@link CBORParser} and {@link CBORGenerator}
13 * instances; both of which handle
14 * <a href="https://www.rfc-editor.org/info/rfc7049">CBOR</a>
15 * encoded data.
16 *<p>
17 * Extends {@link JsonFactory} mostly so that users can actually use it in place
18 * of regular non-CBOR factory instances.
19 *<p>
20 * Note on using non-byte-based sources/targets (char based, like
21 * {@link java.io.Reader} and {@link java.io.Writer}): these can not be
22 * used for CBOR documents; attempt will throw exception.
23 *
24 * @author Tatu Saloranta
25 */
26 public class CBORFactory extends JsonFactory
27 {
28 private static final long serialVersionUID = 1; // 2.6
29
30 /*
31 /**********************************************************
32 /* Constants
33 /**********************************************************
34 */
35
36 /**
37 * Name used to identify CBOR format.
38 * (and returned by {@link #getFormatName()}
39 */
40 public final static String FORMAT_NAME = "CBOR";
41
42 /**
43 * Bitfield (set of flags) of all parser features that are enabled
44 * by default.
45 */
46 final static int DEFAULT_CBOR_PARSER_FEATURE_FLAGS = CBORParser.Feature.collectDefaults();
47
48 /**
49 * Bitfield (set of flags) of all generator features that are enabled
50 * by default.
51 */
52 final static int DEFAULT_CBOR_GENERATOR_FEATURE_FLAGS = CBORGenerator.Feature.collectDefaults();
53
54 /*
55 /**********************************************************
56 /* Configuration
57 /**********************************************************
58 */
59
60 protected int _formatParserFeatures;
61 protected int _formatGeneratorFeatures;
62
63 /*
64 /**********************************************************
65 /* Factory construction, configuration
66 /**********************************************************
67 */
68
69 /**
70 * Default constructor used to create factory instances.
71 * Creation of a factory instance is a light-weight operation,
72 * but it is still a good idea to reuse limited number of
73 * factory instances (and quite often just a single instance):
74 * factories are used as context for storing some reused
75 * processing objects (such as symbol tables parsers use)
76 * and this reuse only works within context of a single
77 * factory instance.
78 */
79 public CBORFactory() { this((ObjectCodec) null); }
80
81 public CBORFactory(ObjectCodec oc) {
82 super(oc);
83 _formatParserFeatures = DEFAULT_CBOR_PARSER_FEATURE_FLAGS;
84 _formatGeneratorFeatures = DEFAULT_CBOR_GENERATOR_FEATURE_FLAGS;
85 }
86
87 /**
88 * Note: REQUIRES at least 2.2.1 -- unfortunate intra-patch dep but seems
89 * preferable to just leaving bug be as is
90 *
91 * @since 2.2.1
92 */
93 public CBORFactory(CBORFactory src, ObjectCodec oc)
94 {
95 super(src, oc);
96 _formatParserFeatures = src._formatParserFeatures;
97 _formatGeneratorFeatures = src._formatGeneratorFeatures;
98 }
99
100 /**
101 * Constructors used by {@link CBORFactoryBuilder} for instantiation.
102 *
103 * @since 3.0
104 */
105 protected CBORFactory(CBORFactoryBuilder b) {
106 super(b, false);
107 _formatParserFeatures = b.formatParserFeaturesMask();
108 _formatGeneratorFeatures = b.formatGeneratorFeaturesMask();
109 }
110
111 @Override
112 public CBORFactoryBuilder rebuild() {
113 return new CBORFactoryBuilder(this);
114 }
115
116 /**
117 * Main factory method to use for constructing {@link CBORFactory} instances with
118 * different configuration.
119 */
120 public static CBORFactoryBuilder builder() {
121 return new CBORFactoryBuilder();
122 }
123
124 @Override
125 public CBORFactory copy()
126 {
127 _checkInvalidCopy(CBORFactory.class);
128 // note: as with base class, must NOT copy mapper reference
129 return new CBORFactory(this, null);
130 }
131
132 /*
133 /**********************************************************
134 /* Serializable overrides
135 /**********************************************************
136 */
137
138 /**
139 * Method that we need to override to actually make restoration go
140 * through constructors etc.
141 * Also: must be overridden by sub-classes as well.
142 */
143 @Override
144 protected Object readResolve() {
145 return new CBORFactory(this, _objectCodec);
146 }
147
148 /*
149 /**********************************************************
150 /* Versioned
151 /**********************************************************
152 */
153
154 @Override
155 public Version version() {
156 return PackageVersion.VERSION;
157 }
158
159 /*
160 /**********************************************************
161 /* Format detection functionality
162 /**********************************************************
163 */
164
165 @Override
166 public String getFormatName() {
167 return FORMAT_NAME;
168 }
169
170 // Defaults work fine for this:
171 // public boolean canUseSchema(FormatSchema schema) { }
172
173 @Override
174 public boolean canUseCharArrays() { return false; }
175
176 @Override
177 public MatchStrength hasFormat(InputAccessor acc) throws IOException {
178 return CBORParserBootstrapper.hasCBORFormat(acc);
179 }
180
181 /*
182 /**********************************************************
183 /* Capability introspection
184 /**********************************************************
185 */
186
187 @Override
188 public boolean canHandleBinaryNatively() {
189 return true;
190 }
191
192 @Override // since 2.6
193 public Class<CBORParser.Feature> getFormatReadFeatureType() {
194 return CBORParser.Feature.class;
195 }
196
197 @Override // since 2.6
198 public Class<CBORGenerator.Feature> getFormatWriteFeatureType() {
199 return CBORGenerator.Feature.class;
200 }
201
202 /*
203 /**********************************************************
204 /* Configuration, parser settings
205 /**********************************************************
206 */
207
208 /**
209 * Method for enabling or disabling specified parser feature
210 * (check {@link CBORParser.Feature} for list of features)
211 */
212 public final CBORFactory configure(CBORParser.Feature f, boolean state)
213 {
214 if (state) {
215 enable(f);
216 } else {
217 disable(f);
218 }
219 return this;
220 }
221
222 /**
223 * Method for enabling specified parser feature
224 * (check {@link CBORParser.Feature} for list of features)
225 */
226 public CBORFactory enable(CBORParser.Feature f) {
227 _formatParserFeatures |= f.getMask();
228 return this;
229 }
230
231 /**
232 * Method for disabling specified parser features
233 * (check {@link CBORParser.Feature} for list of features)
234 */
235 public CBORFactory disable(CBORParser.Feature f) {
236 _formatParserFeatures &= ~f.getMask();
237 return this;
238 }
239
240 /**
241 * Checked whether specified parser feature is enabled.
242 */
243 public final boolean isEnabled(CBORParser.Feature f) {
244 return (_formatParserFeatures & f.getMask()) != 0;
245 }
246
247 @Override
248 public int getFormatParserFeatures() {
249 return _formatParserFeatures;
250 }
251
252 /*
253 /**********************************************************
254 /* Configuration, generator settings
255 /**********************************************************
256 */
257
258 /**
259 * Method for enabling or disabling specified generator feature
260 * (check {@link CBORGenerator.Feature} for list of features)
261 */
262 public final CBORFactory configure(CBORGenerator.Feature f, boolean state) {
263 if (state) {
264 enable(f);
265 } else {
266 disable(f);
267 }
268 return this;
269 }
270
271
272 /**
273 * Method for enabling specified generator features
274 * (check {@link CBORGenerator.Feature} for list of features)
275 */
276 public CBORFactory enable(CBORGenerator.Feature f) {
277 _formatGeneratorFeatures |= f.getMask();
278 return this;
279 }
280
281 /**
282 * Method for disabling specified generator feature
283 * (check {@link CBORGenerator.Feature} for list of features)
284 */
285 public CBORFactory disable(CBORGenerator.Feature f) {
286 _formatGeneratorFeatures &= ~f.getMask();
287 return this;
288 }
289
290 /**
291 * Check whether specified generator feature is enabled.
292 */
293 public final boolean isEnabled(CBORGenerator.Feature f) {
294 return (_formatGeneratorFeatures & f.getMask()) != 0;
295 }
296
297 @Override
298 public int getFormatGeneratorFeatures() {
299 return _formatGeneratorFeatures;
300 }
301
302 /*
303 /**********************************************************
304 /* Overridden parser factory methods, new (2.1)
305 /**********************************************************
306 */
307
308 @SuppressWarnings("resource")
309 @Override
310 public CBORParser createParser(File f) throws IOException {
311 IOContext ctxt = _createContext(f, true);
312 return _createParser(_decorate(new FileInputStream(f), ctxt), ctxt);
313 }
314
315 @Override
316 public CBORParser createParser(URL url) throws IOException {
317 IOContext ctxt = _createContext(url, true);
318 return _createParser(_decorate(_optimizedStreamFromURL(url), ctxt), ctxt);
319 }
320
321 @Override
322 public CBORParser createParser(InputStream in) throws IOException {
323 IOContext ctxt = _createContext(in, false);
324 return _createParser(_decorate(in, ctxt), ctxt);
325 }
326
327 @Override
328 public CBORParser createParser(byte[] data) throws IOException {
329 return createParser(data, 0, data.length);
330 }
331
332 @SuppressWarnings("resource")
333 @Override
334 public CBORParser createParser(byte[] data, int offset, int len) throws IOException {
335 IOContext ctxt = _createContext(data, true);
336 if (_inputDecorator != null) {
337 InputStream in = _inputDecorator.decorate(ctxt, data, 0, data.length);
338 if (in != null) {
339 return _createParser(in, ctxt);
340 }
341 }
342 return _createParser(data, offset, len, ctxt);
343 }
344
345 /*
346 /**********************************************************
347 /* Overridden generator factory methods
348 /**********************************************************
349 */
350
351 /**
352 * Method for constructing {@link JsonGenerator} for generating
353 * CBOR-encoded output.
354 *<p>
355 * Since CBOR format always uses UTF-8 internally, <code>enc</code>
356 * argument is ignored.
357 */
358 @Override
359 public CBORGenerator createGenerator(OutputStream out, JsonEncoding enc) throws IOException {
360 final IOContext ctxt = _createContext(out, false);
361 return _createCBORGenerator(ctxt,
362 _generatorFeatures, _formatGeneratorFeatures, _objectCodec,
363 _decorate(out, ctxt));
364 }
365
366 /**
367 * Method for constructing {@link JsonGenerator} for generating
368 * CBOR-encoded output.
369 *<p>
370 * Since CBOR format always uses UTF-8 internally, no encoding need
371 * to be passed to this method.
372 */
373 @Override
374 public CBORGenerator createGenerator(OutputStream out) throws IOException {
375 final IOContext ctxt = _createContext(out, false);
376 return _createCBORGenerator(ctxt,
377 _generatorFeatures, _formatGeneratorFeatures, _objectCodec,
378 _decorate(out, ctxt));
379 }
380
381 /*
382 /******************************************************
383 /* Overridden internal factory methods
384 /******************************************************
385 */
386
387 @Override
388 protected IOContext _createContext(Object srcRef, boolean resourceManaged) {
389 return super._createContext(srcRef, resourceManaged);
390 }
391
392 /**
393 * Overridable factory method that actually instantiates desired
394 * parser.
395 */
396 @Override
397 protected CBORParser _createParser(InputStream in, IOContext ctxt) throws IOException
398 {
399 return new CBORParserBootstrapper(ctxt, in).constructParser(_factoryFeatures,
400 _parserFeatures, _formatParserFeatures,
401 _objectCodec, _byteSymbolCanonicalizer);
402 }
403
404 /**
405 * Overridable factory method that actually instantiates desired
406 * parser.
407 */
408 @Override
409 protected JsonParser _createParser(Reader r, IOContext ctxt) throws IOException {
410 return _nonByteSource();
411 }
412
413 @Override
414 protected JsonParser _createParser(char[] data, int offset, int len, IOContext ctxt,
415 boolean recyclable) throws IOException {
416 return _nonByteSource();
417 }
418
419 /**
420 * Overridable factory method that actually instantiates desired
421 * parser.
422 */
423 @Override
424 protected CBORParser _createParser(byte[] data, int offset, int len, IOContext ctxt) throws IOException
425 {
426 return new CBORParserBootstrapper(ctxt, data, offset, len).constructParser(
427 _factoryFeatures, _parserFeatures, _formatParserFeatures,
428 _objectCodec, _byteSymbolCanonicalizer);
429 }
430
431 @Override
432 protected CBORGenerator _createGenerator(Writer out, IOContext ctxt) throws IOException {
433 return _nonByteTarget();
434 }
435
436 @Override
437 protected CBORGenerator _createUTF8Generator(OutputStream out, IOContext ctxt) throws IOException {
438 return _createCBORGenerator(ctxt,
439 _generatorFeatures, _formatGeneratorFeatures, _objectCodec, out);
440 }
441
442 @Override
443 protected Writer _createWriter(OutputStream out, JsonEncoding enc, IOContext ctxt) throws IOException {
444 return _nonByteTarget();
445 }
446
447 private final CBORGenerator _createCBORGenerator(IOContext ctxt,
448 int stdFeat, int formatFeat, ObjectCodec codec, OutputStream out) throws IOException
449 {
450 // false -> we won't manage the stream unless explicitly directed to
451 CBORGenerator gen = new CBORGenerator(ctxt, stdFeat, formatFeat, _objectCodec, out);
452 if (CBORGenerator.Feature.WRITE_TYPE_HEADER.enabledIn(formatFeat)) {
453 gen.writeTag(CBORConstants.TAG_ID_SELF_DESCRIBE);
454 }
455 return gen;
456 }
457
458 protected <T> T _nonByteSource() {
459 throw new UnsupportedOperationException("Can not create parser for non-byte-based source");
460 }
461
462 protected <T> T _nonByteTarget() {
463 throw new UnsupportedOperationException("Can not create generator for non-byte-based target");
464 }
465 }
466