From f01fe6f06188f676cf64db29eaa95946dc0de20c Mon Sep 17 00:00:00 2001 From: Googler Date: Mon, 13 Mar 2017 15:24:52 +0000 Subject: Split AndroidDataDeserializer out of AndroidDataSerializer, as the two classes do different (if similar) things and had no common code whatsoever. -- PiperOrigin-RevId: 149942714 MOS_MIGRATED_REVID=149942714 --- .../build/android/AndroidDataDeserializer.java | 117 +++++++++++++++++++++ .../devtools/build/android/AndroidDataMerger.java | 31 +++--- .../build/android/AndroidDataSerializer.java | 80 -------------- .../build/android/AndroidResourceProcessor.java | 16 +-- .../build/android/SerializedAndroidData.java | 4 +- 5 files changed, 139 insertions(+), 109 deletions(-) create mode 100644 src/tools/android/java/com/google/devtools/build/android/AndroidDataDeserializer.java (limited to 'src/tools/android/java/com') diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidDataDeserializer.java b/src/tools/android/java/com/google/devtools/build/android/AndroidDataDeserializer.java new file mode 100644 index 0000000000..3b7d64986b --- /dev/null +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidDataDeserializer.java @@ -0,0 +1,117 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// 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 com.google.devtools.build.android; + +import com.google.common.base.Stopwatch; +import com.google.common.collect.Maps; +import com.google.devtools.build.android.ParsedAndroidData.KeyValueConsumer; +import com.google.devtools.build.android.proto.SerializeFormat; +import com.google.devtools.build.android.proto.SerializeFormat.Header; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +/** Deserializes {@link DataKey}, {@link DataValue} entries from a binary file. */ +public class AndroidDataDeserializer { + private static final Logger logger = Logger.getLogger(AndroidDataDeserializer.class.getName()); + + public static AndroidDataDeserializer create() { + return new AndroidDataDeserializer(); + } + + private AndroidDataDeserializer() {} + + /** + * Reads the serialized {@link DataKey} and {@link DataValue} to the {@link KeyValueConsumers}. + * + * @param inPath The path to the serialized protocol buffer. + * @param consumers The {@link KeyValueConsumers} for the entries {@link DataKey} -> {@link + * DataValue}. + * @throws DeserializationException Raised for an IOException or when the inPath is not a valid + * proto buffer. + */ + public void read(Path inPath, KeyValueConsumers consumers) { + Stopwatch timer = Stopwatch.createStarted(); + try (InputStream in = Files.newInputStream(inPath, StandardOpenOption.READ)) { + FileSystem currentFileSystem = inPath.getFileSystem(); + Header header = Header.parseDelimitedFrom(in); + if (header == null) { + throw new DeserializationException("No Header found in " + inPath); + } + readEntriesSegment(consumers, in, currentFileSystem, header); + } catch (IOException e) { + throw new DeserializationException(e); + } finally { + logger.fine( + String.format("Deserialized in merged in %sms", timer.elapsed(TimeUnit.MILLISECONDS))); + } + } + + private void readEntriesSegment( + KeyValueConsumers consumers, + InputStream in, + FileSystem currentFileSystem, + Header header) + throws IOException { + int numberOfEntries = header.getEntryCount(); + Map> keys = + Maps.newLinkedHashMapWithExpectedSize(numberOfEntries); + for (int i = 0; i < numberOfEntries; i++) { + SerializeFormat.DataKey protoKey = SerializeFormat.DataKey.parseDelimitedFrom(in); + if (protoKey.hasResourceType()) { + FullyQualifiedName resourceName = FullyQualifiedName.fromProto(protoKey); + keys.put( + resourceName, + FullyQualifiedName.isOverwritable(resourceName) + ? consumers.overwritingConsumer + : consumers.combiningConsumer); + } else { + keys.put(RelativeAssetPath.fromProto(protoKey, currentFileSystem), consumers.assetConsumer); + } + } + + // Read back the sources table. + DataSourceTable sourceTable = DataSourceTable.read(in, currentFileSystem, header); + + // TODO(corysmith): Make this a lazy read of the values. + for (Entry> entry : keys.entrySet()) { + SerializeFormat.DataValue protoValue = SerializeFormat.DataValue.parseDelimitedFrom(in); + DataSource source = sourceTable.sourceFromId(protoValue.getSourceId()); + if (protoValue.hasXmlValue()) { + // TODO(corysmith): Figure out why the generics are wrong. + // If I use Map>, I can put + // consumers into the map, but I can't call consume. + // If I use Map>, I can consume + // but I can't put. + // Same for below. + @SuppressWarnings("unchecked") + KeyValueConsumer value = + (KeyValueConsumer) entry.getValue(); + value.consume(entry.getKey(), DataResourceXml.from(protoValue, source)); + } else { + @SuppressWarnings("unchecked") + KeyValueConsumer value = + (KeyValueConsumer) entry.getValue(); + value.consume(entry.getKey(), DataValueFile.of(source)); + } + } + } +} diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidDataMerger.java b/src/tools/android/java/com/google/devtools/build/android/AndroidDataMerger.java index 34b424b521..2e1398eabc 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AndroidDataMerger.java +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidDataMerger.java @@ -37,21 +37,17 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Logger; /** Handles the Merging of ParsedAndroidData. */ -public class AndroidDataMerger { +class AndroidDataMerger { private static final Logger logger = Logger.getLogger(AndroidDataMerger.class.getCanonicalName()); - private static final class ParseDependencyDataTask implements Callable { - - private final AndroidDataSerializer serializer; + private final class ParseDependencyDataTask implements Callable { private final SerializedAndroidData dependency; private final Builder targetBuilder; - private ParseDependencyDataTask( - AndroidDataSerializer serializer, SerializedAndroidData dependency, Builder targetBuilder) { - this.serializer = serializer; + private ParseDependencyDataTask(SerializedAndroidData dependency, Builder targetBuilder) { this.dependency = dependency; this.targetBuilder = targetBuilder; } @@ -60,7 +56,7 @@ public class AndroidDataMerger { public Boolean call() throws Exception { final Builder parsedDataBuilder = ParsedAndroidData.Builder.newBuilder(); try { - dependency.deserialize(serializer, parsedDataBuilder.consumers()); + dependency.deserialize(deserializer, parsedDataBuilder.consumers()); } catch (DeserializationException e) { if (!e.isLegacy()) { throw MergingException.wrapException(e).build(); @@ -141,25 +137,26 @@ public class AndroidDataMerger { private final SourceChecker deDuplicator; private final ListeningExecutorService executorService; + private final AndroidDataDeserializer deserializer = AndroidDataDeserializer.create(); /** Creates a merger with no path deduplication and a default {@link ExecutorService}. */ - public static AndroidDataMerger createWithDefaults() { + static AndroidDataMerger createWithDefaults() { return createWithDefaultThreadPool(NoopSourceChecker.create()); } /** Creates a merger with a custom deduplicator and a default {@link ExecutorService}. */ - public static AndroidDataMerger createWithDefaultThreadPool(SourceChecker deDuplicator) { + static AndroidDataMerger createWithDefaultThreadPool(SourceChecker deDuplicator) { return new AndroidDataMerger(deDuplicator, MoreExecutors.newDirectExecutorService()); } /** Creates a merger with a custom deduplicator and an {@link ExecutorService}. */ - public static AndroidDataMerger create( + static AndroidDataMerger create( SourceChecker deDuplicator, ListeningExecutorService executorService) { return new AndroidDataMerger(deDuplicator, executorService); } /** Creates a merger with a file contents hashing deduplicator. */ - public static AndroidDataMerger createWithPathDeduplictor( + static AndroidDataMerger createWithPathDeduplictor( ListeningExecutorService executorService) { return create(ContentComparingChecker.create(), executorService); } @@ -187,17 +184,13 @@ public class AndroidDataMerger { try { final ParsedAndroidData.Builder directBuilder = ParsedAndroidData.Builder.newBuilder(); final ParsedAndroidData.Builder transitiveBuilder = ParsedAndroidData.Builder.newBuilder(); - final AndroidDataSerializer serializer = AndroidDataSerializer.create(); final List> tasks = new ArrayList<>(); for (final SerializedAndroidData dependency : direct) { - tasks.add( - executorService.submit( - new ParseDependencyDataTask(serializer, dependency, directBuilder))); + tasks.add(executorService.submit(new ParseDependencyDataTask(dependency, directBuilder))); } for (final SerializedAndroidData dependency : transitive) { tasks.add( - executorService.submit( - new ParseDependencyDataTask(serializer, dependency, transitiveBuilder))); + executorService.submit(new ParseDependencyDataTask(dependency, transitiveBuilder))); } // Wait for all the parsing to complete. FailedFutureAggregator aggregator = @@ -314,7 +307,7 @@ public class AndroidDataMerger { final KeyValueConsumers primaryConsumers = primaryBuilder.consumers(); final Set conflicts = new HashSet<>(); - + // Find all internal conflicts. conflicts.addAll(parsedPrimary.conflicts()); for (MergeConflict conflict : Iterables.concat(direct.conflicts(), transitive.conflicts())) { diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidDataSerializer.java b/src/tools/android/java/com/google/devtools/build/android/AndroidDataSerializer.java index 132133facd..f43bc7b7ef 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AndroidDataSerializer.java +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidDataSerializer.java @@ -14,16 +14,12 @@ package com.google.devtools.build.android; import com.google.common.base.Stopwatch; -import com.google.common.collect.Maps; -import com.google.devtools.build.android.ParsedAndroidData.KeyValueConsumer; import com.google.devtools.build.android.proto.SerializeFormat; import com.google.devtools.build.android.proto.SerializeFormat.Header; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; -import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; @@ -118,82 +114,6 @@ public class AndroidDataSerializer { outStream.write(valuesOutputStream.toByteArray()); } - /** - * Reads the serialized {@link DataKey} and {@link DataValue} to the {@link KeyValueConsumers}. - * - * @param inPath The path to the serialized protocol buffer. - * @param consumers The {@link KeyValueConsumers} for the entries {@link DataKey} -> - * {@link DataValue}. - * @throws DeserializationException Raised for an IOException or when the inPath is not a valid - * proto buffer. - */ - public void read(Path inPath, KeyValueConsumers consumers) throws DeserializationException { - Stopwatch timer = Stopwatch.createStarted(); - try (InputStream in = Files.newInputStream(inPath, StandardOpenOption.READ)) { - FileSystem currentFileSystem = inPath.getFileSystem(); - Header header = Header.parseDelimitedFrom(in); - if (header == null) { - throw new DeserializationException("No Header found in " + inPath); - } - readEntriesSegment(consumers, in, currentFileSystem, header); - } catch (IOException e) { - throw new DeserializationException(e); - } finally { - logger.fine( - String.format("Deserialized in merged in %sms", timer.elapsed(TimeUnit.MILLISECONDS))); - } - } - - private void readEntriesSegment( - KeyValueConsumers consumers, - InputStream in, - FileSystem currentFileSystem, - Header header) - throws IOException { - int numberOfEntries = header.getEntryCount(); - Map> keys = - Maps.newLinkedHashMapWithExpectedSize(numberOfEntries); - for (int i = 0; i < numberOfEntries; i++) { - SerializeFormat.DataKey protoKey = SerializeFormat.DataKey.parseDelimitedFrom(in); - if (protoKey.hasResourceType()) { - FullyQualifiedName resourceName = FullyQualifiedName.fromProto(protoKey); - keys.put( - resourceName, - FullyQualifiedName.isOverwritable(resourceName) - ? consumers.overwritingConsumer - : consumers.combiningConsumer); - } else { - keys.put(RelativeAssetPath.fromProto(protoKey, currentFileSystem), consumers.assetConsumer); - } - } - - // Read back the sources table. - DataSourceTable sourceTable = DataSourceTable.read(in, currentFileSystem, header); - - // TODO(corysmith): Make this a lazy read of the values. - for (Entry> entry : keys.entrySet()) { - SerializeFormat.DataValue protoValue = SerializeFormat.DataValue.parseDelimitedFrom(in); - DataSource source = sourceTable.sourceFromId(protoValue.getSourceId()); - if (protoValue.hasXmlValue()) { - // TODO(corysmith): Figure out why the generics are wrong. - // If I use Map>, I can put - // consumers into the map, but I can't call consume. - // If I use Map>, I can consume - // but I can't put. - // Same for below. - @SuppressWarnings("unchecked") - KeyValueConsumer value = - (KeyValueConsumer) entry.getValue(); - value.consume(entry.getKey(), DataResourceXml.from(protoValue, source)); - } else { - @SuppressWarnings("unchecked") - KeyValueConsumer value = - (KeyValueConsumer) entry.getValue(); - value.consume(entry.getKey(), DataValueFile.of(source)); - } - } - } - /** Queues the key and value for serialization as a entries entry. */ public void queueForSerialization(DataKey key, DataValue value) { entries.put(key, value); diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java index e466b3d357..f1fbf03149 100644 --- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java +++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java @@ -1158,8 +1158,8 @@ public class AndroidResourceProcessor { @Nullable final AndroidResourceClassWriter rclassWriter) throws MergingException { final ParsedAndroidData.Builder primaryBuilder = ParsedAndroidData.Builder.newBuilder(); - final AndroidDataSerializer serializer = AndroidDataSerializer.create(); - primary.deserialize(serializer, primaryBuilder.consumers()); + final AndroidDataDeserializer deserializer = AndroidDataDeserializer.create(); + primary.deserialize(deserializer, primaryBuilder.consumers()); ParsedAndroidData primaryData = primaryBuilder.build(); return mergeData( primaryData, @@ -1250,7 +1250,7 @@ public class AndroidResourceProcessor { /** Deserializes a list of serialized resource paths to a {@link ParsedAndroidData}. */ public ParsedAndroidData deserializeSymbolsToData(List symbolPaths) throws IOException, MergingException { - AndroidDataSerializer serializer = AndroidDataSerializer.create(); + AndroidDataDeserializer deserializer = AndroidDataDeserializer.create(); final ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(15)); final Builder deserializedDataBuilder = ParsedAndroidData.Builder.newBuilder(); @@ -1259,7 +1259,7 @@ public class AndroidResourceProcessor { for (final Path symbolPath : symbolPaths) { deserializing.add( executorService.submit( - new Deserialize(serializer, symbolPath, deserializedDataBuilder))); + new Deserialize(deserializer, symbolPath, deserializedDataBuilder))); } FailedFutureAggregator aggregator = FailedFutureAggregator.createForMergingExceptionWithMessage( @@ -1452,11 +1452,11 @@ public class AndroidResourceProcessor { private final Path symbolPath; private final Builder finalDataBuilder; - private AndroidDataSerializer serializer; + private final AndroidDataDeserializer deserializer; private Deserialize( - AndroidDataSerializer serializer, Path symbolPath, Builder finalDataBuilder) { - this.serializer = serializer; + AndroidDataDeserializer deserializer, Path symbolPath, Builder finalDataBuilder) { + this.deserializer = deserializer; this.symbolPath = symbolPath; this.finalDataBuilder = finalDataBuilder; } @@ -1464,7 +1464,7 @@ public class AndroidResourceProcessor { @Override public Boolean call() throws Exception { final Builder parsedDataBuilder = ParsedAndroidData.Builder.newBuilder(); - serializer.read(symbolPath, parsedDataBuilder.consumers()); + deserializer.read(symbolPath, parsedDataBuilder.consumers()); // The builder isn't threadsafe, so synchronize the copyTo call. synchronized (finalDataBuilder) { // All the resources are sorted before writing, so they can be aggregated in diff --git a/src/tools/android/java/com/google/devtools/build/android/SerializedAndroidData.java b/src/tools/android/java/com/google/devtools/build/android/SerializedAndroidData.java index 08f32b9594..ea744c53e5 100644 --- a/src/tools/android/java/com/google/devtools/build/android/SerializedAndroidData.java +++ b/src/tools/android/java/com/google/devtools/build/android/SerializedAndroidData.java @@ -91,13 +91,13 @@ public class SerializedAndroidData { } } - public void deserialize(AndroidDataSerializer serializer, KeyValueConsumers consumers) + public void deserialize(AndroidDataDeserializer deserializer, KeyValueConsumers consumers) throws DeserializationException { // Missing symbols means the resources where provided via android_resources rules. if (symbols == null) { throw new DeserializationException(true); } - serializer.read(symbols, consumers); + deserializer.read(symbols, consumers); } public String getLabel() { -- cgit v1.2.3