Add ContentMetadata and AbstractContentMetadata
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=188041418
This commit is contained in:
parent
73048f18c1
commit
f81dc44112
151
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/AbstractContentMetadata.java
vendored
Normal file
151
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/AbstractContentMetadata.java
vendored
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* 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.android.exoplayer2.upstream.cache;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.upstream.cache.Cache.CacheException;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/** Abstract implementation of {@link ContentMetadata}. Values are stored as byte arrays. */
|
||||||
|
public abstract class AbstractContentMetadata implements ContentMetadata {
|
||||||
|
|
||||||
|
private final Map<String, byte[]> metadata;
|
||||||
|
|
||||||
|
protected AbstractContentMetadata() {
|
||||||
|
this.metadata = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param metadata Initial name value pairs. */
|
||||||
|
protected AbstractContentMetadata(Map<String, byte[]> metadata) {
|
||||||
|
this.metadata = new HashMap<>(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Editor edit() {
|
||||||
|
return new EditorImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final byte[] get(String name, byte[] defaultValue) {
|
||||||
|
synchronized (metadata) {
|
||||||
|
if (metadata.containsKey(name)) {
|
||||||
|
return metadata.get(name);
|
||||||
|
} else {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String get(String name, String defaultValue) {
|
||||||
|
synchronized (metadata) {
|
||||||
|
if (metadata.containsKey(name)) {
|
||||||
|
byte[] bytes = metadata.get(name);
|
||||||
|
return new String(bytes, Charset.forName(C.UTF8_NAME));
|
||||||
|
} else {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final long get(String name, long defaultValue) {
|
||||||
|
synchronized (metadata) {
|
||||||
|
if (metadata.containsKey(name)) {
|
||||||
|
byte[] bytes = metadata.get(name);
|
||||||
|
return ByteBuffer.wrap(bytes).getLong();
|
||||||
|
} else {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean contains(String name) {
|
||||||
|
synchronized (metadata) {
|
||||||
|
return metadata.containsKey(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when any metadata value is changed or removed. {@code metadataValues} shouldn't be
|
||||||
|
* accessed out of this method.
|
||||||
|
*
|
||||||
|
* @param metadataValues All metadata name, value pairs.
|
||||||
|
*/
|
||||||
|
protected abstract void onChange(Map<String, byte[]> metadataValues) throws CacheException;
|
||||||
|
|
||||||
|
private void apply(ArrayList<String> removedValues, Map<String, byte[]> editedValues)
|
||||||
|
throws CacheException {
|
||||||
|
synchronized (metadata) {
|
||||||
|
for (int i = 0; i < removedValues.size(); i++) {
|
||||||
|
metadata.remove(removedValues.get(i));
|
||||||
|
}
|
||||||
|
metadata.putAll(editedValues);
|
||||||
|
onChange(Collections.unmodifiableMap(metadata));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class EditorImpl implements Editor {
|
||||||
|
|
||||||
|
private final Map<String, byte[]> editedValues;
|
||||||
|
private final ArrayList<String> removedValues;
|
||||||
|
|
||||||
|
private EditorImpl() {
|
||||||
|
editedValues = new HashMap<>();
|
||||||
|
removedValues = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Editor set(String name, String value) {
|
||||||
|
set(name, value.getBytes());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Editor set(String name, long value) {
|
||||||
|
set(name, ByteBuffer.allocate(8).putLong(value).array());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Editor set(String name, byte[] value) {
|
||||||
|
editedValues.put(name, Assertions.checkNotNull(value));
|
||||||
|
removedValues.remove(name);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Editor remove(String name) {
|
||||||
|
removedValues.add(name);
|
||||||
|
editedValues.remove(name);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commit() throws CacheException {
|
||||||
|
apply(removedValues, editedValues);
|
||||||
|
removedValues.clear();
|
||||||
|
editedValues.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
104
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/ContentMetadata.java
vendored
Normal file
104
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/ContentMetadata.java
vendored
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* 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.android.exoplayer2.upstream.cache;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.upstream.cache.Cache.CacheException;
|
||||||
|
|
||||||
|
/** Interface for accessing cached content metadata which is stored as name, value pairs. */
|
||||||
|
public interface ContentMetadata {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for modifying values in a {@link ContentMetadata} object. The changes you make in an
|
||||||
|
* editor are not copied back to the original {@link ContentMetadata} until you call {@link
|
||||||
|
* #commit()}.
|
||||||
|
*/
|
||||||
|
interface Editor {
|
||||||
|
/**
|
||||||
|
* Sets a metadata value, to be committed once {@link #commit()} is called. Passing {@code null}
|
||||||
|
* as {@code value} isn't allowed. {@code value} byte array shouldn't be modified after passed
|
||||||
|
* to this method.
|
||||||
|
*
|
||||||
|
* @param name The name of the metadata value.
|
||||||
|
* @param value The value to be set.
|
||||||
|
* @return This Editor instance, for convenience.
|
||||||
|
*/
|
||||||
|
Editor set(String name, byte[] value);
|
||||||
|
/**
|
||||||
|
* Sets a metadata value, to be committed once {@link #commit()} is called. Passing {@code null}
|
||||||
|
* as value isn't allowed.
|
||||||
|
*
|
||||||
|
* @param name The name of the metadata value.
|
||||||
|
* @param value The value to be set.
|
||||||
|
* @return This Editor instance, for convenience.
|
||||||
|
*/
|
||||||
|
Editor set(String name, String value);
|
||||||
|
/**
|
||||||
|
* Sets a metadata value, to be committed once {@link #commit()} is called.
|
||||||
|
*
|
||||||
|
* @param name The name of the metadata value.
|
||||||
|
* @param value The value to be set.
|
||||||
|
* @return This Editor instance, for convenience.
|
||||||
|
*/
|
||||||
|
Editor set(String name, long value);
|
||||||
|
/**
|
||||||
|
* Sets a metadata value, to be committed once {@link #commit()} is called. Passing {@code null}
|
||||||
|
* as value isn't allowed.
|
||||||
|
*
|
||||||
|
* @param name The name of the metadata value.
|
||||||
|
* @return This Editor instance, for convenience.
|
||||||
|
*/
|
||||||
|
Editor remove(String name);
|
||||||
|
/**
|
||||||
|
* Commits changes. It can be called only once.
|
||||||
|
*
|
||||||
|
* @throws CacheException If the commit fails.
|
||||||
|
*/
|
||||||
|
void commit() throws CacheException;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns an editor to change metadata values. */
|
||||||
|
Editor edit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a metadata value.
|
||||||
|
*
|
||||||
|
* @param name Name of the metadata to be returned.
|
||||||
|
* @param defaultValue Value to return if the metadata doesn't exist.
|
||||||
|
* @return The metadata value.
|
||||||
|
*/
|
||||||
|
byte[] get(String name, byte[] defaultValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a metadata value.
|
||||||
|
*
|
||||||
|
* @param name Name of the metadata to be returned.
|
||||||
|
* @param defaultValue Value to return if the metadata doesn't exist.
|
||||||
|
* @return The metadata value.
|
||||||
|
*/
|
||||||
|
String get(String name, String defaultValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a metadata value.
|
||||||
|
*
|
||||||
|
* @param name Name of the metadata to be returned.
|
||||||
|
* @param defaultValue Value to return if the metadata doesn't exist.
|
||||||
|
* @return The metadata value.
|
||||||
|
*/
|
||||||
|
long get(String name, long defaultValue);
|
||||||
|
|
||||||
|
/** Returns whether the metadata is available. */
|
||||||
|
boolean contains(String name);
|
||||||
|
}
|
@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* 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.android.exoplayer2.upstream.cache;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.upstream.cache.Cache.CacheException;
|
||||||
|
import com.google.android.exoplayer2.upstream.cache.ContentMetadata.Editor;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
|
/** Tests {@link AbstractContentMetadata}. */
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class AbstractContentMetadataTest {
|
||||||
|
|
||||||
|
private FakeAbstractContentMetadata contentMetadata;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
contentMetadata = createAbstractContentMetadata();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContainsReturnsFalseWhenEmpty() throws Exception {
|
||||||
|
assertThat(contentMetadata.contains("test metadata")).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContainsReturnsTrueForInitialValue() throws Exception {
|
||||||
|
contentMetadata = createAbstractContentMetadata("metadata name", "value");
|
||||||
|
assertThat(contentMetadata.contains("metadata name")).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetReturnsDefaultValueWhenValueIsNotAvailable() throws Exception {
|
||||||
|
assertThat(contentMetadata.get("metadata name", "default value")).isEqualTo("default value");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetReturnsInitialValue() throws Exception {
|
||||||
|
contentMetadata = createAbstractContentMetadata("metadata name", "value");
|
||||||
|
assertThat(contentMetadata.get("metadata name", "default value")).isEqualTo("value");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEditReturnsAnEditor() throws Exception {
|
||||||
|
assertThat(contentMetadata.edit()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEditReturnsAnotherEditorEveryTime() throws Exception {
|
||||||
|
assertThat(contentMetadata.edit()).isNotEqualTo(contentMetadata.edit());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCommitWithoutEditDoesNotFail() throws Exception {
|
||||||
|
Editor editor = contentMetadata.edit();
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddNewMetadata() throws Exception {
|
||||||
|
Editor editor = contentMetadata.edit();
|
||||||
|
editor.set("metadata name", "value");
|
||||||
|
editor.commit();
|
||||||
|
assertThat(contentMetadata.get("metadata name", "default value")).isEqualTo("value");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddNewIntMetadata() throws Exception {
|
||||||
|
Editor editor = contentMetadata.edit();
|
||||||
|
editor.set("metadata name", 5);
|
||||||
|
editor.commit();
|
||||||
|
assertThat(contentMetadata.get("metadata name", 0)).isEqualTo(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddNewByteArrayMetadata() throws Exception {
|
||||||
|
Editor editor = contentMetadata.edit();
|
||||||
|
byte[] value = {1, 2, 3};
|
||||||
|
editor.set("metadata name", value);
|
||||||
|
editor.commit();
|
||||||
|
assertThat(contentMetadata.get("metadata name", new byte[] {})).isEqualTo(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewMetadataNotWrittenBeforeCommitted() throws Exception {
|
||||||
|
Editor editor = contentMetadata.edit();
|
||||||
|
editor.set("metadata name", "value");
|
||||||
|
assertThat(contentMetadata.get("metadata name", "default value")).isEqualTo("default value");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEditMetadata() throws Exception {
|
||||||
|
contentMetadata = createAbstractContentMetadata("metadata name", "value");
|
||||||
|
Editor editor = contentMetadata.edit();
|
||||||
|
editor.set("metadata name", "edited value");
|
||||||
|
editor.commit();
|
||||||
|
assertThat(contentMetadata.get("metadata name", "default value")).isEqualTo("edited value");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveMetadata() throws Exception {
|
||||||
|
contentMetadata = createAbstractContentMetadata("metadata name", "value");
|
||||||
|
Editor editor = contentMetadata.edit();
|
||||||
|
editor.remove("metadata name");
|
||||||
|
editor.commit();
|
||||||
|
assertThat(contentMetadata.get("metadata name", "default value")).isEqualTo("default value");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddAndRemoveMetadata() throws Exception {
|
||||||
|
Editor editor = contentMetadata.edit();
|
||||||
|
editor.set("metadata name", "value");
|
||||||
|
editor.remove("metadata name");
|
||||||
|
editor.commit();
|
||||||
|
assertThat(contentMetadata.get("metadata name", "default value")).isEqualTo("default value");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveAndAddMetadata() throws Exception {
|
||||||
|
Editor editor = contentMetadata.edit();
|
||||||
|
editor.remove("metadata name");
|
||||||
|
editor.set("metadata name", "value");
|
||||||
|
editor.commit();
|
||||||
|
assertThat(contentMetadata.get("metadata name", "default value")).isEqualTo("value");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnChangeIsCalledWhenMetadataEdited() throws Exception {
|
||||||
|
contentMetadata =
|
||||||
|
createAbstractContentMetadata(
|
||||||
|
"metadata name", "value", "metadata name2", "value2", "metadata name3", "value3");
|
||||||
|
Editor editor = contentMetadata.edit();
|
||||||
|
editor.set("metadata name", "edited value");
|
||||||
|
editor.remove("metadata name2");
|
||||||
|
editor.commit();
|
||||||
|
assertThat(contentMetadata.remainingValues).containsExactly("metadata name", "metadata name3");
|
||||||
|
}
|
||||||
|
|
||||||
|
private FakeAbstractContentMetadata createAbstractContentMetadata(String... pairs) {
|
||||||
|
assertThat(pairs.length % 2).isEqualTo(0);
|
||||||
|
HashMap<String, byte[]> map = new HashMap<>();
|
||||||
|
for (int i = 0; i < pairs.length; i += 2) {
|
||||||
|
map.put(pairs[i], getBytes(pairs[i + 1]));
|
||||||
|
}
|
||||||
|
return new FakeAbstractContentMetadata(Collections.unmodifiableMap(map));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] getBytes(String value) {
|
||||||
|
return value.getBytes(Charset.forName(C.UTF8_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FakeAbstractContentMetadata extends AbstractContentMetadata {
|
||||||
|
|
||||||
|
private ArrayList<String> remainingValues;
|
||||||
|
|
||||||
|
private FakeAbstractContentMetadata(Map<String, byte[]> metadataValues) {
|
||||||
|
super(metadataValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onChange(Map<String, byte[]> metadataValues) throws CacheException {
|
||||||
|
remainingValues = new ArrayList<>(metadataValues.keySet());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user