aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-core
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2015-07-22 14:17:06 +0200
committerSimon Brandhof <simon.brandhof@sonarsource.com>2015-07-22 14:17:16 +0200
commitc98aca6054048d0293fdb713910b4fa98beaa524 (patch)
tree2335acba0b9ecab3115dc6a49e67db4431dcd53b /sonar-core
parent5539cfffd327697a49278361901335e2d4d6e075 (diff)
downloadsonarqube-c98aca6054048d0293fdb713910b4fa98beaa524.tar.gz
sonarqube-c98aca6054048d0293fdb713910b4fa98beaa524.zip
Improve utility org.sonar.core.util.Protobuf
Diffstat (limited to 'sonar-core')
-rw-r--r--sonar-core/pom.xml23
-rw-r--r--sonar-core/src/main/java/org/sonar/core/util/Protobuf.java162
-rw-r--r--sonar-core/src/test/gen-java/org/sonar/core/test/Test.java603
-rw-r--r--sonar-core/src/test/java/org/sonar/core/util/ProtobufTest.java120
-rw-r--r--sonar-core/src/test/protobuf/test.proto28
5 files changed, 936 insertions, 0 deletions
diff --git a/sonar-core/pom.xml b/sonar-core/pom.xml
index 2f9a09ab9d8..010524b4614 100644
--- a/sonar-core/pom.xml
+++ b/sonar-core/pom.xml
@@ -28,6 +28,10 @@
<artifactId>picocontainer</artifactId>
</dependency>
<dependency>
+ <groupId>com.google.protobuf</groupId>
+ <artifactId>protobuf-java</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-classloader</artifactId>
</dependency>
@@ -107,6 +111,25 @@
<build>
<plugins>
<plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>add-test-source</id>
+ <phase>generate-test-sources</phase>
+ <goals>
+ <goal>add-test-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>src/test/gen-java</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
diff --git a/sonar-core/src/main/java/org/sonar/core/util/Protobuf.java b/sonar-core/src/main/java/org/sonar/core/util/Protobuf.java
new file mode 100644
index 00000000000..7b8b25c6e73
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/util/Protobuf.java
@@ -0,0 +1,162 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.core.util;
+
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.Message;
+import com.google.protobuf.Parser;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import org.apache.commons.io.IOUtils;
+
+/**
+ * Utility to read and write Protocol Buffers messages
+ */
+public class Protobuf {
+ private Protobuf() {
+ // only static stuff
+ }
+
+ /**
+ * Returns the message contained in {@code file}. Throws an unchecked exception
+ * if the file does not exist, is empty or does not contain message with the
+ * expected type.
+ */
+ public static <MSG extends Message> MSG read(File file, Parser<MSG> parser) {
+ InputStream input = null;
+ try {
+ input = new BufferedInputStream(new FileInputStream(file));
+ return parser.parseFrom(input);
+ } catch (Exception e) {
+ throw ContextException.of("Unable to read message", e).addContext("file", file);
+ } finally {
+ IOUtils.closeQuietly(input);
+ }
+ }
+
+ /**
+ * Writes a single message to {@code file}. Existing content is replaced, the message is not
+ * appended.
+ */
+ public static void write(Message message, File toFile) {
+ OutputStream out = null;
+ try {
+ out = new BufferedOutputStream(new FileOutputStream(toFile, false));
+ message.writeTo(out);
+ } catch (Exception e) {
+ throw ContextException.of("Unable to write message", e).addContext("file", toFile);
+ } finally {
+ IOUtils.closeQuietly(out);
+ }
+ }
+
+ /**
+ * Streams multiple messages to {@code file}. Reading the messages back requires to
+ * call methods {@code readStream(...)}.
+ * <p>
+ * See https://developers.google.com/protocol-buffers/docs/techniques#streaming
+ * </p>
+ */
+ public static <MSG extends Message> void writeStream(Iterable<MSG> messages, File toFile, boolean append) {
+ OutputStream out = null;
+ try {
+ out = new BufferedOutputStream(new FileOutputStream(toFile, append));
+ writeStream(messages, out);
+ } catch (Exception e) {
+ throw ContextException.of("Unable to write messages", e).addContext("file", toFile);
+ } finally {
+ IOUtils.closeQuietly(out);
+ }
+ }
+
+ /**
+ * Streams multiple messages to {@code output}. Reading the messages back requires to
+ * call methods {@code readStream(...)}.
+ * <p>
+ * See https://developers.google.com/protocol-buffers/docs/techniques#streaming
+ * </p>
+ */
+ public static <MSG extends Message> void writeStream(Iterable<MSG> messages, OutputStream output) {
+ try {
+ for (Message message : messages) {
+ message.writeDelimitedTo(output);
+ }
+ } catch (Exception e) {
+ throw ContextException.of("Unable to write messages", e);
+ }
+ }
+
+ /**
+ * Reads a stream of messages. This method returns an empty iterator if there are no messages. An
+ * exception is raised on IO error, if file does not exist or if messages have a
+ * different type than {@code parser}.
+ */
+ public static <MSG extends Message> CloseableIterator<MSG> readStream(File file, Parser<MSG> parser) {
+ try {
+ // the input stream is closed by the CloseableIterator
+ BufferedInputStream input = new BufferedInputStream(new FileInputStream(file));
+ return readStream(input, parser);
+ } catch (Exception e) {
+ throw ContextException.of("Unable to read messages", e).addContext("file", file);
+ }
+ }
+
+ /**
+ * Reads a stream of messages. This method returns an empty iterator if there are no messages. An
+ * exception is raised on IO error or if messages have a different type than {@code parser}.
+ * <p>
+ * The stream is not closed by this method. It is closed when {@link CloseableIterator} traverses
+ * all messages or when {@link CloseableIterator#close()} is called.
+ * </p>
+ */
+ public static <MSG extends Message> CloseableIterator<MSG> readStream(InputStream input, Parser<MSG> parser) {
+ // the stream is closed by the CloseableIterator
+ return new StreamIterator<>(parser, input);
+ }
+
+ private static class StreamIterator<MSG extends Message> extends CloseableIterator<MSG> {
+ private final Parser<MSG> parser;
+ private final InputStream input;
+
+ private StreamIterator(Parser<MSG> parser, InputStream input) {
+ this.parser = parser;
+ this.input = input;
+ }
+
+ @Override
+ protected MSG doNext() {
+ try {
+ return parser.parsePartialDelimitedFrom(input);
+ } catch (InvalidProtocolBufferException e) {
+ throw ContextException.of(e);
+ }
+ }
+
+ @Override
+ protected void doClose() {
+ IOUtils.closeQuietly(input);
+ }
+ }
+}
diff --git a/sonar-core/src/test/gen-java/org/sonar/core/test/Test.java b/sonar-core/src/test/gen-java/org/sonar/core/test/Test.java
new file mode 100644
index 00000000000..9797ed15898
--- /dev/null
+++ b/sonar-core/src/test/gen-java/org/sonar/core/test/Test.java
@@ -0,0 +1,603 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: test.proto
+
+package org.sonar.core.test;
+
+public final class Test {
+ private Test() {}
+ public static void registerAllExtensions(
+ com.google.protobuf.ExtensionRegistry registry) {
+ }
+ public interface FakeOrBuilder extends
+ // @@protoc_insertion_point(interface_extends:Fake)
+ com.google.protobuf.MessageOrBuilder {
+
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ boolean hasKey();
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ java.lang.String getKey();
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ com.google.protobuf.ByteString
+ getKeyBytes();
+
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ boolean hasLine();
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ int getLine();
+ }
+ /**
+ * Protobuf type {@code Fake}
+ */
+ public static final class Fake extends
+ com.google.protobuf.GeneratedMessage implements
+ // @@protoc_insertion_point(message_implements:Fake)
+ FakeOrBuilder {
+ // Use Fake.newBuilder() to construct.
+ private Fake(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
+ super(builder);
+ this.unknownFields = builder.getUnknownFields();
+ }
+ private Fake(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+
+ private static final Fake defaultInstance;
+ public static Fake getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public Fake getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ private final com.google.protobuf.UnknownFieldSet unknownFields;
+ @java.lang.Override
+ public final com.google.protobuf.UnknownFieldSet
+ getUnknownFields() {
+ return this.unknownFields;
+ }
+ private Fake(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ initFields();
+ int mutable_bitField0_ = 0;
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder();
+ try {
+ boolean done = false;
+ while (!done) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ done = true;
+ break;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ done = true;
+ }
+ break;
+ }
+ case 10: {
+ com.google.protobuf.ByteString bs = input.readBytes();
+ bitField0_ |= 0x00000001;
+ key_ = bs;
+ break;
+ }
+ case 16: {
+ bitField0_ |= 0x00000002;
+ line_ = input.readInt32();
+ break;
+ }
+ }
+ }
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(this);
+ } catch (java.io.IOException e) {
+ throw new com.google.protobuf.InvalidProtocolBufferException(
+ e.getMessage()).setUnfinishedMessage(this);
+ } finally {
+ this.unknownFields = unknownFields.build();
+ makeExtensionsImmutable();
+ }
+ }
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.sonar.core.test.Test.internal_static_Fake_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.sonar.core.test.Test.internal_static_Fake_fieldAccessorTable
+ .ensureFieldAccessorsInitialized(
+ org.sonar.core.test.Test.Fake.class, org.sonar.core.test.Test.Fake.Builder.class);
+ }
+
+ public static com.google.protobuf.Parser<Fake> PARSER =
+ new com.google.protobuf.AbstractParser<Fake>() {
+ public Fake parsePartialFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return new Fake(input, extensionRegistry);
+ }
+ };
+
+ @java.lang.Override
+ public com.google.protobuf.Parser<Fake> getParserForType() {
+ return PARSER;
+ }
+
+ private int bitField0_;
+ public static final int KEY_FIELD_NUMBER = 1;
+ private java.lang.Object key_;
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public boolean hasKey() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public java.lang.String getKey() {
+ java.lang.Object ref = key_;
+ if (ref instanceof java.lang.String) {
+ return (java.lang.String) ref;
+ } else {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ key_ = s;
+ }
+ return s;
+ }
+ }
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public com.google.protobuf.ByteString
+ getKeyBytes() {
+ java.lang.Object ref = key_;
+ if (ref instanceof java.lang.String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ key_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+
+ public static final int LINE_FIELD_NUMBER = 2;
+ private int line_;
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ public boolean hasLine() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ public int getLine() {
+ return line_;
+ }
+
+ private void initFields() {
+ key_ = "";
+ line_ = 0;
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized == 1) return true;
+ if (isInitialized == 0) return false;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeBytes(1, getKeyBytes());
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeInt32(2, line_);
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(1, getKeyBytes());
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeInt32Size(2, line_);
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.sonar.core.test.Test.Fake parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static org.sonar.core.test.Test.Fake parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static org.sonar.core.test.Test.Fake parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static org.sonar.core.test.Test.Fake parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static org.sonar.core.test.Test.Fake parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input);
+ }
+ public static org.sonar.core.test.Test.Fake parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input, extensionRegistry);
+ }
+ public static org.sonar.core.test.Test.Fake parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return PARSER.parseDelimitedFrom(input);
+ }
+ public static org.sonar.core.test.Test.Fake parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseDelimitedFrom(input, extensionRegistry);
+ }
+ public static org.sonar.core.test.Test.Fake parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input);
+ }
+ public static org.sonar.core.test.Test.Fake parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input, extensionRegistry);
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.sonar.core.test.Test.Fake prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ /**
+ * Protobuf type {@code Fake}
+ */
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+ // @@protoc_insertion_point(builder_implements:Fake)
+ org.sonar.core.test.Test.FakeOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.sonar.core.test.Test.internal_static_Fake_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.sonar.core.test.Test.internal_static_Fake_fieldAccessorTable
+ .ensureFieldAccessorsInitialized(
+ org.sonar.core.test.Test.Fake.class, org.sonar.core.test.Test.Fake.Builder.class);
+ }
+
+ // Construct using org.sonar.core.test.Test.Fake.newBuilder()
+ private Builder() {
+ maybeForceBuilderInitialization();
+ }
+
+ private Builder(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ super(parent);
+ maybeForceBuilderInitialization();
+ }
+ private void maybeForceBuilderInitialization() {
+ if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ }
+ }
+ private static Builder create() {
+ return new Builder();
+ }
+
+ public Builder clear() {
+ super.clear();
+ key_ = "";
+ bitField0_ = (bitField0_ & ~0x00000001);
+ line_ = 0;
+ bitField0_ = (bitField0_ & ~0x00000002);
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(buildPartial());
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return org.sonar.core.test.Test.internal_static_Fake_descriptor;
+ }
+
+ public org.sonar.core.test.Test.Fake getDefaultInstanceForType() {
+ return org.sonar.core.test.Test.Fake.getDefaultInstance();
+ }
+
+ public org.sonar.core.test.Test.Fake build() {
+ org.sonar.core.test.Test.Fake result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ public org.sonar.core.test.Test.Fake buildPartial() {
+ org.sonar.core.test.Test.Fake result = new org.sonar.core.test.Test.Fake(this);
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+ to_bitField0_ |= 0x00000001;
+ }
+ result.key_ = key_;
+ if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+ to_bitField0_ |= 0x00000002;
+ }
+ result.line_ = line_;
+ result.bitField0_ = to_bitField0_;
+ onBuilt();
+ return result;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof org.sonar.core.test.Test.Fake) {
+ return mergeFrom((org.sonar.core.test.Test.Fake)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(org.sonar.core.test.Test.Fake other) {
+ if (other == org.sonar.core.test.Test.Fake.getDefaultInstance()) return this;
+ if (other.hasKey()) {
+ bitField0_ |= 0x00000001;
+ key_ = other.key_;
+ onChanged();
+ }
+ if (other.hasLine()) {
+ setLine(other.getLine());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public final boolean isInitialized() {
+ return true;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ org.sonar.core.test.Test.Fake parsedMessage = null;
+ try {
+ parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ parsedMessage = (org.sonar.core.test.Test.Fake) e.getUnfinishedMessage();
+ throw e;
+ } finally {
+ if (parsedMessage != null) {
+ mergeFrom(parsedMessage);
+ }
+ }
+ return this;
+ }
+ private int bitField0_;
+
+ private java.lang.Object key_ = "";
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public boolean hasKey() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public java.lang.String getKey() {
+ java.lang.Object ref = key_;
+ if (!(ref instanceof java.lang.String)) {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ key_ = s;
+ }
+ return s;
+ } else {
+ return (java.lang.String) ref;
+ }
+ }
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public com.google.protobuf.ByteString
+ getKeyBytes() {
+ java.lang.Object ref = key_;
+ if (ref instanceof String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ key_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public Builder setKey(
+ java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ key_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public Builder clearKey() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ key_ = getDefaultInstance().getKey();
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public Builder setKeyBytes(
+ com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ key_ = value;
+ onChanged();
+ return this;
+ }
+
+ private int line_ ;
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ public boolean hasLine() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ public int getLine() {
+ return line_;
+ }
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ public Builder setLine(int value) {
+ bitField0_ |= 0x00000002;
+ line_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ public Builder clearLine() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ line_ = 0;
+ onChanged();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:Fake)
+ }
+
+ static {
+ defaultInstance = new Fake(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:Fake)
+ }
+
+ private static final com.google.protobuf.Descriptors.Descriptor
+ internal_static_Fake_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_Fake_fieldAccessorTable;
+
+ public static com.google.protobuf.Descriptors.FileDescriptor
+ getDescriptor() {
+ return descriptor;
+ }
+ private static com.google.protobuf.Descriptors.FileDescriptor
+ descriptor;
+ static {
+ java.lang.String[] descriptorData = {
+ "\n\ntest.proto\"!\n\004Fake\022\013\n\003key\030\001 \001(\t\022\014\n\004lin" +
+ "e\030\002 \001(\005B\027\n\023org.sonar.core.testH\001"
+ };
+ com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
+ new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
+ public com.google.protobuf.ExtensionRegistry assignDescriptors(
+ com.google.protobuf.Descriptors.FileDescriptor root) {
+ descriptor = root;
+ return null;
+ }
+ };
+ com.google.protobuf.Descriptors.FileDescriptor
+ .internalBuildGeneratedFileFrom(descriptorData,
+ new com.google.protobuf.Descriptors.FileDescriptor[] {
+ }, assigner);
+ internal_static_Fake_descriptor =
+ getDescriptor().getMessageTypes().get(0);
+ internal_static_Fake_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_Fake_descriptor,
+ new java.lang.String[] { "Key", "Line", });
+ }
+
+ // @@protoc_insertion_point(outer_class_scope)
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/util/ProtobufTest.java b/sonar-core/src/test/java/org/sonar/core/util/ProtobufTest.java
new file mode 100644
index 00000000000..5b30c2b9a7c
--- /dev/null
+++ b/sonar-core/src/test/java/org/sonar/core/util/ProtobufTest.java
@@ -0,0 +1,120 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.core.util;
+
+import java.io.File;
+import java.util.Arrays;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.test.TestUtils;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.core.test.Test.Fake;
+
+public class ProtobufTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Test
+ public void only_utils() {
+ assertThat(TestUtils.hasOnlyPrivateConstructors(Protobuf.class));
+ }
+
+ @Test
+ public void read_file_fails_if_file_does_not_exist() throws Exception {
+ thrown.expect(ContextException.class);
+ thrown.expectMessage("Unable to read message");
+
+ File file = temp.newFile();
+ FileUtils.forceDelete(file);
+ Protobuf.read(file, Fake.PARSER);
+ }
+
+ @Test
+ public void read_file_returns_empty_message_if_file_is_empty() throws Exception {
+ File file = temp.newFile();
+ Fake msg = Protobuf.read(file, Fake.PARSER);
+ assertThat(msg).isNotNull();
+ assertThat(msg.isInitialized()).isTrue();
+ }
+
+ @Test
+ public void read_file_returns_message() throws Exception {
+ File file = temp.newFile();
+ Protobuf.write(Fake.getDefaultInstance(), file);
+ Fake message = Protobuf.read(file, Fake.PARSER);
+ assertThat(message).isNotNull();
+ assertThat(message.isInitialized()).isTrue();
+ }
+
+ @Test
+ public void fail_to_write_single_message() throws Exception {
+ thrown.expect(ContextException.class);
+ thrown.expectMessage("Unable to write message");
+
+ File dir = temp.newFolder();
+ Protobuf.write(Fake.getDefaultInstance(), dir);
+ }
+
+ @Test
+ public void write_and_read_streams() throws Exception {
+ File file = temp.newFile();
+
+ Fake item1 = Fake.newBuilder().setKey("one").setLine(1).build();
+ Fake item2 = Fake.newBuilder().setKey("two").build();
+ Protobuf.writeStream(asList(item1, item2), file, false);
+
+ CloseableIterator<Fake> it = Protobuf.readStream(file, Fake.PARSER);
+ Fake read = it.next();
+ assertThat(read.getKey()).isEqualTo("one");
+ assertThat(read.getLine()).isEqualTo(1);
+ read = it.next();
+ assertThat(read.getKey()).isEqualTo("two");
+ assertThat(read.hasLine()).isFalse();
+ assertThat(it.hasNext()).isFalse();
+ }
+
+ @Test
+ public void fail_to_read_stream() throws Exception {
+ thrown.expect(ContextException.class);
+ thrown.expectMessage("Unable to read messages");
+
+ File dir = temp.newFolder();
+ Protobuf.readStream(dir, Fake.PARSER);
+ }
+
+ @Test
+ public void read_empty_stream() throws Exception {
+ File file = temp.newFile();
+ CloseableIterator<Fake> it = Protobuf.readStream(file, Fake.PARSER);
+ assertThat(it).isNotNull();
+ assertThat(it.hasNext()).isFalse();
+ }
+
+ // TODO test in-moemry file
+}
diff --git a/sonar-core/src/test/protobuf/test.proto b/sonar-core/src/test/protobuf/test.proto
new file mode 100644
index 00000000000..c449a6a0596
--- /dev/null
+++ b/sonar-core/src/test/protobuf/test.proto
@@ -0,0 +1,28 @@
+/*
+ SonarQube, open source software quality management tool.
+ Copyright (C) 2008-2015 SonarSource
+ mailto:contact AT sonarsource DOT com
+
+ SonarQube is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ SonarQube is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+
+option java_package = "org.sonar.core.test";
+option optimize_for = SPEED;
+
+message Fake {
+ optional string key = 1;
+ optional int32 line = 2;
+}