/* * Copyright 2015 GoDataDriven B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.divolte.server.mincode; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.format.InputAccessor; import com.fasterxml.jackson.core.format.MatchStrength; import com.fasterxml.jackson.core.io.IOContext; import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; import java.io.*; import java.net.URL; import java.nio.charset.StandardCharsets; @ParametersAreNonnullByDefault public class MincodeFactory extends JsonFactory { private static final long serialVersionUID = 1L; public final static String FORMAT_NAME_MINCODING = "Mincoding"; public final static Version FORMAT_VERSION = Version.unknownVersion(); public MincodeFactory() { this(null); } public MincodeFactory(@Nullable final ObjectCodec oc) { super(oc); } public MincodeFactory(final MincodeFactory src, @Nullable final ObjectCodec codec) { super(src, codec); } @Override public JsonFactory copy() { return new MincodeFactory(this, null); } @Override protected Object readResolve() { // Force deserialization to go via constructor. return new MincodeFactory(this, _objectCodec); } @Override public String getFormatName() { return FORMAT_NAME_MINCODING; } @Override public Version version() { return FORMAT_VERSION; } @Override public MatchStrength hasFormat(final InputAccessor acc) throws IOException { final MatchStrength matchStrength; if (acc.hasMoreBytes()) { final byte b = acc.nextByte(); // First byte has to be one of the record types, possibly capital denoting a root object. // (Only '.' cannot appear at the start of Mincode.) switch (b) { case '(': case 'a': case 's': case 't': case 'f': case 'n': case 'd': case 'j': matchStrength = MatchStrength.SOLID_MATCH; break; default: matchStrength = MatchStrength.NO_MATCH; } } else { // Zero-length isn't supported. matchStrength = MatchStrength.NO_MATCH; } return matchStrength; } @Override public MincodeParser createParser(final File f) throws IOException { final IOContext ctxt = _createContext(f, true); return _createParser(_decorate(new FileInputStream(f), ctxt), ctxt); } @Override public MincodeParser createParser(final URL url) throws IOException { final IOContext ctxt = _createContext(url, true); return _createParser(_decorate(_optimizedStreamFromURL(url), ctxt), ctxt); } @Override public MincodeParser createParser(final InputStream in) throws IOException { final IOContext ctxt = _createContext(in, false); return _createParser(_decorate(in, ctxt), ctxt); } @Override public MincodeParser createParser(final Reader r) throws IOException { final IOContext ctxt = _createContext(r, false); return _createParser(_decorate(r, ctxt), ctxt); } @Override public MincodeParser createParser(final byte[] data) throws IOException { return createParser(data, 0, data.length); } @Override public MincodeParser createParser(byte[] data, int offset, int len) throws IOException { final IOContext ctxt = _createContext(data, true); if (null != _inputDecorator) { final InputStream in = _inputDecorator.decorate(ctxt, data, offset, len); if (null != in) { return _createParser(in, ctxt); } } return _createParser(data, offset, len, ctxt); } @Override public MincodeParser createParser(final String content) throws IOException { return createParser(new StringReader(content)); } @Override public MincodeParser createParser(final char[] content) throws IOException { return createParser(content, 0, content.length); } @Override public MincodeParser createParser(final char[] content, final int offset, final int len) throws IOException { return null != _inputDecorator ? createParser(new CharArrayReader(content, offset, len)) : _createParser(content, offset, len, _createContext(content, true), false); } @Override protected MincodeParser _createParser(final InputStream in, final IOContext ctxt) throws IOException { return _createParser(new InputStreamReader(in, StandardCharsets.UTF_8), ctxt); } @Override protected MincodeParser _createParser(final Reader r, final IOContext ctxt) throws IOException { return new MincodeParser(ctxt, _parserFeatures, _objectCodec, r); } @Override protected MincodeParser _createParser(final char[] data, final int offset, final int len, final IOContext ctxt, final boolean recyclable) throws IOException { return _createParser(new CharArrayReader(data, offset, len), ctxt); } @Override protected MincodeParser _createParser(final byte[] data, final int offset, final int len, final IOContext ctxt) throws IOException { final ByteArrayInputStream in = new ByteArrayInputStream(data, offset, len); return _createParser(new InputStreamReader(in, StandardCharsets.UTF_8), ctxt); } }