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(thisnull);
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