diff options
Diffstat (limited to 'java/core/src/main/java/com/google/protobuf/Protobuf.java')
-rw-r--r-- | java/core/src/main/java/com/google/protobuf/Protobuf.java | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/java/core/src/main/java/com/google/protobuf/Protobuf.java b/java/core/src/main/java/com/google/protobuf/Protobuf.java new file mode 100644 index 00000000..6c6aad24 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/Protobuf.java @@ -0,0 +1,148 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static com.google.protobuf.Internal.checkNotNull; + +import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * Main runtime interface for protobuf. Applications should interact with this interface (rather + * than directly accessing internal APIs) in order to perform operations on protobuf messages. + */ +@ExperimentalApi +public final class Protobuf { + private static final Protobuf INSTANCE = new Protobuf(); + + private final SchemaFactory schemaFactory; + + // TODO(nathanmittler): Consider using ClassValue instead. + private final ConcurrentMap<Class<?>, Schema<?>> schemaCache = + new ConcurrentHashMap<Class<?>, Schema<?>>(); + + /** Gets the singleton instance of the Protobuf runtime. */ + public static Protobuf getInstance() { + return INSTANCE; + } + + /** Writes the given message to the target {@link Writer}. */ + public <T> void writeTo(T message, Writer writer) { + schemaFor(message).writeTo(message, writer); + } + + /** Reads fields from the given {@link Reader} and merges them into the message. */ + public <T> void mergeFrom(T message, Reader reader) throws IOException { + schemaFor(message).mergeFrom(message, reader); + } + + /** Gets the schema for the given message type. */ + public <T> Schema<T> schemaFor(Class<T> messageType) { + checkNotNull(messageType, "messageType"); + @SuppressWarnings("unchecked") + Schema<T> schema = (Schema<T>) schemaCache.get(messageType); + if (schema == null) { + schema = schemaFactory.createSchema(messageType); + @SuppressWarnings("unchecked") + Schema<T> previous = (Schema<T>) registerSchema(messageType, schema); + if (previous != null) { + // A new schema was registered by another thread. + schema = previous; + } + } + return schema; + } + + /** Gets the schema for the given message. */ + @SuppressWarnings("unchecked") + public <T> Schema<T> schemaFor(T message) { + return schemaFor((Class<T>) message.getClass()); + } + + /** + * Registers the given schema for the message type only if a schema was not already registered. + * + * @param messageType the type of message on which the schema operates. + * @param schema the schema for the message type. + * @return the previously registered schema, or {@code null} if the given schema was successfully + * registered. + */ + public Schema<?> registerSchema(Class<?> messageType, Schema<?> schema) { + checkNotNull(messageType, "messageType"); + checkNotNull(schema, "schema"); + return schemaCache.putIfAbsent(messageType, schema); + } + + /** + * Visible for testing only. Registers the given schema for the message type. If a schema was + * previously registered, it will be replaced by the provided schema. + * + * @param messageType the type of message on which the schema operates. + * @param schema the schema for the message type. + * @return the previously registered schema, or {@code null} if no schema was registered + * previously. + */ + public Schema<?> registerSchemaOverride(Class<?> messageType, Schema<?> schema) { + checkNotNull(messageType, "messageType"); + checkNotNull(schema, "schema"); + return schemaCache.put(messageType, schema); + } + + private Protobuf() { + // TODO(nathanmittler): Detect the proper factory for the platform. + SchemaFactory factory = null; + for (String className : + new String[] { + "com.google.frameworks.protobuf.experimental.android.schema.AndroidProto3SchemaFactory", + // TODO(nathanmittler): Remove this once the code has been completely ported over. + "com.google.frameworks.protobuf.experimental.schema.generic.Proto3SchemaFactory", + "com.google.protobuf.Proto3SchemaFactory" + }) { + factory = newSchemaFactory(className); + if (factory != null) { + break; + } + } + if (factory == null) { + throw new IllegalStateException("Unable to locate a default SchemaFactory. Check classpath."); + } + schemaFactory = factory; + } + + private static SchemaFactory newSchemaFactory(String className) { + try { + return (SchemaFactory) Class.forName(className).getConstructor().newInstance(); + } catch (Throwable e) { + return null; + } + } +} |