Repository: phoenix Updated Branches: refs/heads/4.x-HBase-0.98 62034b0c9 -> 580b035f0 refs/heads/4.x-HBase-1.1 a56114757 -> 7988111db refs/heads/4.x-HBase-1.2 5ccf8ef3e -> 9b0c0af11 refs/heads/master 0311e4f56 -> 052490e09
PHOENIX-4189 Introduce a class that wraps the Map of primary key data Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/052490e0 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/052490e0 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/052490e0 Branch: refs/heads/master Commit: 052490e09f2271eaa84dc9ab123a62a87123a498 Parents: 0311e4f Author: Josh Elser <els...@apache.org> Authored: Sat Sep 9 00:00:57 2017 -0400 Committer: Josh Elser <els...@apache.org> Committed: Thu Sep 14 18:24:02 2017 -0400 ---------------------------------------------------------------------- .../org/apache/phoenix/hive/PhoenixRowKey.java | 17 ++-- .../org/apache/phoenix/hive/PrimaryKeyData.java | 88 ++++++++++++++++++++ .../hive/util/PhoenixStorageHandlerUtil.java | 9 +- .../apache/phoenix/hive/PrimaryKeyDataTest.java | 79 ++++++++++++++++++ 4 files changed, 175 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/052490e0/phoenix-hive/src/main/java/org/apache/phoenix/hive/PhoenixRowKey.java ---------------------------------------------------------------------- diff --git a/phoenix-hive/src/main/java/org/apache/phoenix/hive/PhoenixRowKey.java b/phoenix-hive/src/main/java/org/apache/phoenix/hive/PhoenixRowKey.java index c4cbb2c..a963fba 100644 --- a/phoenix-hive/src/main/java/org/apache/phoenix/hive/PhoenixRowKey.java +++ b/phoenix-hive/src/main/java/org/apache/phoenix/hive/PhoenixRowKey.java @@ -17,15 +17,12 @@ */ package org.apache.phoenix.hive; -import com.google.common.collect.Maps; import org.apache.hadoop.hive.ql.io.RecordIdentifier; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.io.OutputStream; import java.util.Map; @@ -35,33 +32,29 @@ import java.util.Map; public class PhoenixRowKey extends RecordIdentifier { - private Map<String, Object> rowKeyMap = Maps.newHashMap(); + private PrimaryKeyData rowKeyMap = PrimaryKeyData.EMPTY; public PhoenixRowKey() { } public void setRowKeyMap(Map<String, Object> rowKeyMap) { - this.rowKeyMap = rowKeyMap; + this.rowKeyMap = new PrimaryKeyData(rowKeyMap); } @Override public void write(DataOutput dataOutput) throws IOException { super.write(dataOutput); - try (ObjectOutputStream oos = new ObjectOutputStream((OutputStream) dataOutput)) { - oos.writeObject(rowKeyMap); - oos.flush(); - } + rowKeyMap.serialize((OutputStream) dataOutput); } - @SuppressWarnings("unchecked") @Override public void readFields(DataInput dataInput) throws IOException { super.readFields(dataInput); - try (ObjectInputStream ois = new ObjectInputStream((InputStream) dataInput)) { - rowKeyMap = (Map<String, Object>) ois.readObject(); + try { + rowKeyMap = PrimaryKeyData.deserialize((InputStream) dataInput); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/052490e0/phoenix-hive/src/main/java/org/apache/phoenix/hive/PrimaryKeyData.java ---------------------------------------------------------------------- diff --git a/phoenix-hive/src/main/java/org/apache/phoenix/hive/PrimaryKeyData.java b/phoenix-hive/src/main/java/org/apache/phoenix/hive/PrimaryKeyData.java new file mode 100644 index 0000000..b5e9dd9 --- /dev/null +++ b/phoenix-hive/src/main/java/org/apache/phoenix/hive/PrimaryKeyData.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you 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 org.apache.phoenix.hive; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * Wrapper around the primary key data for Hive. + */ +public class PrimaryKeyData implements Serializable{ + public static final PrimaryKeyData EMPTY = new PrimaryKeyData(Collections.<String,Object> emptyMap()); + private static final long serialVersionUID = 1L; + + // Based on https://www.ibm.com/developerworks/library/se-lookahead/. Prevents unexpected + // deserialization of other objects of an unexpected class. + private static class LookAheadObjectInputStream extends ObjectInputStream { + public LookAheadObjectInputStream(InputStream in) throws IOException { + super(in); + } + + @Override + protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { + if (!desc.getName().equals(PrimaryKeyData.class.getName()) && + !desc.getName().startsWith("java.lang.") && + !desc.getName().startsWith("java.util.") && + !desc.getName().startsWith("java.sql.")) { + throw new InvalidClassException(desc.getName(), "Expected an instance of PrimaryKeyData"); + } + return super.resolveClass(desc); + } + } + + private final HashMap<String,Object> data; + + public PrimaryKeyData(Map<String,Object> data) { + if (data instanceof HashMap) { + this.data = (HashMap<String,Object>) data; + } else { + this.data = new HashMap<>(Objects.requireNonNull(data)); + } + } + + public HashMap<String,Object> getData() { + return data; + } + + public void serialize(OutputStream output) throws IOException { + try (ObjectOutputStream oos = new ObjectOutputStream(output)) { + oos.writeObject(this); + oos.flush(); + } + } + + public static PrimaryKeyData deserialize(InputStream input) throws IOException, ClassNotFoundException { + try (LookAheadObjectInputStream ois = new LookAheadObjectInputStream((InputStream) input)) { + Object obj = ois.readObject(); + if (obj instanceof PrimaryKeyData) { + return (PrimaryKeyData) obj; + } + throw new InvalidClassException(obj == null ? "null" : obj.getClass().getName(), "Disallowed serialized class"); + } + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/052490e0/phoenix-hive/src/main/java/org/apache/phoenix/hive/util/PhoenixStorageHandlerUtil.java ---------------------------------------------------------------------- diff --git a/phoenix-hive/src/main/java/org/apache/phoenix/hive/util/PhoenixStorageHandlerUtil.java b/phoenix-hive/src/main/java/org/apache/phoenix/hive/util/PhoenixStorageHandlerUtil.java index 1dc8545..19c26e5 100644 --- a/phoenix-hive/src/main/java/org/apache/phoenix/hive/util/PhoenixStorageHandlerUtil.java +++ b/phoenix-hive/src/main/java/org/apache/phoenix/hive/util/PhoenixStorageHandlerUtil.java @@ -21,7 +21,6 @@ import com.google.common.base.Joiner; import com.google.common.collect.Maps; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.ObjectInputStream; import java.lang.reflect.Array; import java.math.BigDecimal; import java.net.InetAddress; @@ -51,6 +50,7 @@ import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoUtils; import org.apache.hadoop.mapred.JobConf; import org.apache.hadoop.net.DNS; +import org.apache.phoenix.hive.PrimaryKeyData; import org.apache.phoenix.hive.constants.PhoenixStorageHandlerConstants; import org.apache.phoenix.hive.ql.index.IndexSearchCondition; import org.apache.phoenix.mapreduce.util.PhoenixConfigurationUtil; @@ -256,16 +256,13 @@ public class PhoenixStorageHandlerUtil { } public static Map<?, ?> toMap(byte[] serialized) { - Map<?, ?> resultMap = null; ByteArrayInputStream bais = new ByteArrayInputStream(serialized); - try (ObjectInputStream ois = new ObjectInputStream(bais)) { - resultMap = (Map<?, ?>) ois.readObject(); + try { + return PrimaryKeyData.deserialize(bais).getData(); } catch (ClassNotFoundException | IOException e) { throw new RuntimeException(e); } - - return resultMap; } public static String getOptionsValue(Options options) { http://git-wip-us.apache.org/repos/asf/phoenix/blob/052490e0/phoenix-hive/src/test/java/org/apache/phoenix/hive/PrimaryKeyDataTest.java ---------------------------------------------------------------------- diff --git a/phoenix-hive/src/test/java/org/apache/phoenix/hive/PrimaryKeyDataTest.java b/phoenix-hive/src/test/java/org/apache/phoenix/hive/PrimaryKeyDataTest.java new file mode 100644 index 0000000..3b2634f --- /dev/null +++ b/phoenix-hive/src/test/java/org/apache/phoenix/hive/PrimaryKeyDataTest.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you 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 org.apache.phoenix.hive; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InvalidClassException; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.HashMap; + +import org.junit.Test; + +public class PrimaryKeyDataTest { + private static class Disallowed implements Serializable { + private static final long serialVersionUID = 1L; + } + + private byte[] serialize(Object o) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(o); + } + return baos.toByteArray(); + } + + @Test + public void testSerde() throws Exception { + HashMap<String,Object> data = new HashMap<>(); + data.put("one", 1); + data.put("two", "two"); + data.put("three", 3); + + PrimaryKeyData pkData = new PrimaryKeyData(data); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + pkData.serialize(baos); + + PrimaryKeyData pkCopy = PrimaryKeyData.deserialize(new ByteArrayInputStream(baos.toByteArray())); + assertEquals(data, pkCopy.getData()); + } + + @Test + public void testDisallowedDeserialization() throws Exception { + byte[] serializedMap = serialize(new HashMap<String,Object>()); + byte[] serializedClass = serialize(new Disallowed()); + byte[] serializedString = serialize("asdf"); + + try { + PrimaryKeyData.deserialize(new ByteArrayInputStream(serializedMap)); + fail("Expected an InvalidClassException"); + } catch (InvalidClassException e) {} + try { + PrimaryKeyData.deserialize(new ByteArrayInputStream(serializedClass)); + fail("Expected an InvalidClassException"); + } catch (InvalidClassException e) {} + try { + PrimaryKeyData.deserialize(new ByteArrayInputStream(serializedString)); + fail("Expected an InvalidClassException"); + } catch (InvalidClassException e) {} + } +}