You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by el...@apache.org on 2017/09/14 22:46:36 UTC

[3/4] phoenix git commit: PHOENIX-4189 Introduce a class that wraps the Map of primary key data

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/7988111d
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/7988111d
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/7988111d

Branch: refs/heads/4.x-HBase-1.1
Commit: 7988111db682dee07d870a2226fd88ab6f92930d
Parents: a561147
Author: Josh Elser <el...@apache.org>
Authored: Sat Sep 9 00:00:57 2017 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Thu Sep 14 18:35:52 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/7988111d/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/7988111d/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/7988111d/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/7988111d/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) {}
+    }
+}