This is an automated email from the ASF dual-hosted git repository.

ayushtkn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git


The following commit(s) were added to refs/heads/master by this push:
     new c28607ae27d HIVE-29713: Maintain properties package, update JEXL 
dependency to JEXL 3.7.0 (#6592)
c28607ae27d is described below

commit c28607ae27db096adc024cca37e18444e0831db6
Author: Henrib <[email protected]>
AuthorDate: Tue Jul 28 21:11:50 2026 +0200

    HIVE-29713: Maintain properties package, update JEXL dependency to JEXL 
3.7.0 (#6592)
---
 .../metastore/properties/HMSPropertyManager.java   | 38 ++++-----
 .../hive/metastore/properties/PropertyManager.java |  8 +-
 .../hive/metastore/properties/PropertyMap.java     |  2 +-
 .../hive/metastore/properties/PropertyStore.java   |  2 +-
 .../hive/metastore/properties/PropertyType.java    | 24 +++---
 .../metastore/properties/SerializationProxy.java   |  2 +
 .../hive/metastore/properties/package-info.java    | 83 +++++++++++++++++++
 .../hadoop/hive/metastore/PropertyServlet.java     | 95 +++++++++++++++++++++-
 standalone-metastore/pom.xml                       |  2 +-
 9 files changed, 217 insertions(+), 39 deletions(-)

diff --git 
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/HMSPropertyManager.java
 
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/HMSPropertyManager.java
index c1166bd28ed..3f2e2e63475 100644
--- 
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/HMSPropertyManager.java
+++ 
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/HMSPropertyManager.java
@@ -25,7 +25,7 @@
 import java.util.TreeMap;
 
 /**
- * A property manager tailored for the HiveMetaStore.
+ * A property manager tailored for the HiveMetaStore operating on Iceberg 
tables.
  * It describes properties for cluster, database and table based on declared 
schemas.
  * A property is of the form:
  * <ul>
@@ -101,14 +101,14 @@ public static MaintenanceOpStatus findOpStatus(int 
ordinal) {
    */
   public static final PropertyType<MaintenanceOpType> MAINTENANCE_OPERATION = 
new PropertyType<MaintenanceOpType>("MaintenanceOperation"){
     @Override public MaintenanceOpType cast(Object value) {
-      if (value instanceof MaintenanceOpType) {
-        return (MaintenanceOpType) value;
+      if (value instanceof MaintenanceOpType op) {
+        return op;
       }
       if (value == null) {
         return null;
       }
-      if (value instanceof Number) {
-        return findOpType(((Number) value).intValue());
+      if (value instanceof Number n) {
+        return findOpType(n.intValue());
       }
       return parse(value.toString());
     }
@@ -121,8 +121,8 @@ public static MaintenanceOpStatus findOpStatus(int ordinal) 
{
     }
 
     @Override public String format(Object value) {
-      if (value instanceof MaintenanceOpType) {
-        return value.toString();
+      if (value instanceof MaintenanceOpType op) {
+        return op.toString();
       }
       return null;
     }
@@ -133,14 +133,14 @@ public static MaintenanceOpStatus findOpStatus(int 
ordinal) {
    */
   public static final PropertyType<MaintenanceOpStatus> MAINTENANCE_STATUS = 
new PropertyType<MaintenanceOpStatus>("MaintenanceStatus"){
     @Override public MaintenanceOpStatus cast(Object value) {
-      if (value instanceof MaintenanceOpStatus) {
-        return (MaintenanceOpStatus) value;
+      if (value instanceof MaintenanceOpStatus op) {
+        return op;
       }
       if (value == null) {
         return null;
       }
-      if (value instanceof Number) {
-        return findOpStatus(((Number) value).intValue());
+      if (value instanceof Number n) {
+        return findOpStatus(n.intValue());
       }
       return parse(value.toString());
     }
@@ -153,8 +153,8 @@ public static MaintenanceOpStatus findOpStatus(int ordinal) 
{
     }
 
     @Override public String format(Object value) {
-      if (value instanceof MaintenanceOpStatus) {
-        return value.toString();
+      if (value instanceof MaintenanceOpStatus op) {
+        return op.toString();
       }
       return null;
     }
@@ -247,12 +247,12 @@ public static void declareTableProperty(String name, 
PropertyType<?> type, Objec
    */
   @Override
   public PropertySchema getSchema(String schemaName) {
-    switch(schemaName) {
-      case CLUSTER_PREFIX: return CLUSTER_SCHEMA;
-      case DATABASE_PREFIX: return DATABASE_SCHEMA;
-      case TABLE_PREFIX: return TABLE_SCHEMA;
-      default: return null;
-    }
+    return switch (schemaName) {
+      case CLUSTER_PREFIX -> CLUSTER_SCHEMA;
+      case DATABASE_PREFIX -> DATABASE_SCHEMA;
+      case TABLE_PREFIX -> TABLE_SCHEMA;
+      default -> null;
+    };
   }
 
   /**
diff --git 
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyManager.java
 
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyManager.java
index c1244533945..869eca9b07a 100644
--- 
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyManager.java
+++ 
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyManager.java
@@ -75,14 +75,14 @@ public abstract class PropertyManager {
   /** A Jexl engine for convenience. */
   static final JexlEngine JEXL;
   static {
-    JexlFeatures features = new JexlFeatures()
+    JexlFeatures features = JexlFeatures.createDefault()
         .sideEffect(false)
         .sideEffectGlobal(false);
-    JexlPermissions p = JexlPermissions.RESTRICTED
-        .compose("org.apache.hadoop.hive.metastore.properties.*");
+    JexlPermissions permissions = JexlPermissions.RESTRICTED
+        .compose("org.apache.hadoop.hive.metastore.properties.*", 
"com.google.gson.internal.*");
     JEXL = new JexlBuilder()
         .features(features)
-        .permissions(p)
+        .permissions(permissions)
         .create();
   }
 
diff --git 
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyMap.java
 
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyMap.java
index 06a7f7aa31b..5918bc1c582 100644
--- 
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyMap.java
+++ 
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyMap.java
@@ -135,7 +135,7 @@ public PropertyMap(PropertyMap src, Map<String, Object> 
input) {
 
   /**
    * Deserialization ctor.
-   * <p>Used through deserializtion through reflection by the serialization 
proxy.</p>
+   * <p>Used through deserialization through reflection by the serialization 
proxy.</p>
    * @param input the input stream
    * @throws IOException if IO fail
    */
diff --git 
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyStore.java
 
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyStore.java
index 0bc6beabf6c..911575d1793 100644
--- 
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyStore.java
+++ 
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyStore.java
@@ -25,7 +25,7 @@
 
 /**
  * The PropertyStore is the persistent container of property maps.
- * Maps are addressed in the store by their key -  their name prepended by 
their manager&quot;s namespace.
+ * Maps are addressed in the store by their key - their name prepended by 
their manager&quot;s namespace.
  */
 
 public abstract class PropertyStore {
diff --git 
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyType.java
 
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyType.java
index 930b625f593..89a1b0c0baa 100644
--- 
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyType.java
+++ 
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/PropertyType.java
@@ -182,8 +182,8 @@ public String parse(String str) {
 
     @Nullable
     @Override public String format(Object value) {
-      if (value instanceof Boolean) {
-        return ((Boolean) value) ? "true" : "false";
+      if (value instanceof Boolean b) {
+        return b.toString();
       }
       return null;
     }
@@ -201,8 +201,8 @@ public Boolean read(DataInput in) throws IOException {
 
   public static final PropertyType<Integer> INTEGER = new 
PropertyType<Integer>("integer") {
     @Override public Integer cast(Object value) {
-      if (value instanceof Number) {
-        return ((Number) value).intValue();
+      if (value instanceof Number n) {
+        return n.intValue();
       }
       if (value == null) {
         return null;
@@ -241,8 +241,8 @@ public Integer read(DataInput in) throws IOException {
 
   public static final PropertyType<Long> LONG = new PropertyType<Long>("long"){
     @Override public Long cast(Object value) {
-      if (value instanceof Number) {
-        return ((Number) value).longValue();
+      if (value instanceof Number n) {
+        return n.longValue();
       }
       if (value == null) {
         return null;
@@ -281,11 +281,11 @@ public Long read(DataInput in) throws IOException {
 
   public static final PropertyType<Date> DATETIME = new 
PropertyType<Date>("date"){
     @Override public Date cast(Object value) {
-      if (value instanceof Number) {
-        return new Date(((Number) value).longValue());
+      if (value instanceof Number n) {
+        return new Date(n.longValue());
       }
-      if (value instanceof Date) {
-        return (Date) value;
+      if (value instanceof Date d) {
+        return d;
       }
       if (value == null) {
         return null;
@@ -322,8 +322,8 @@ public Long read(DataInput in) throws IOException {
 
   public static final PropertyType<Double> DOUBLE = new 
PropertyType<Double>("double"){
     @Override public Double cast(Object value) {
-      if (value instanceof Number) {
-        return ((Number) value).doubleValue();
+      if (value instanceof Number n) {
+        return n.doubleValue();
       }
       if (value == null) {
         return null;
diff --git 
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/SerializationProxy.java
 
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/SerializationProxy.java
index 8321d0ee276..9a90f223cb5 100644
--- 
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/SerializationProxy.java
+++ 
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/SerializationProxy.java
@@ -33,6 +33,7 @@
 import java.io.ObjectOutput;
 import java.io.ObjectOutputStream;
 import java.io.OutputStream;
+import java.io.Serial;
 import java.io.Serializable;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Executable;
@@ -75,6 +76,7 @@
  */
 public class SerializationProxy<T extends Serializable> implements 
Externalizable {
   /** Serial version. */
+  @Serial
   private static final long serialVersionUID = 202212281757L;
   /** The logger. */
   public static final Logger LOGGER = 
LoggerFactory.getLogger(SerializationProxy.class);
diff --git 
a/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/package-info.java
 
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/package-info.java
new file mode 100644
index 00000000000..4f237331a11
--- /dev/null
+++ 
b/standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/properties/package-info.java
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+/**
+ * Type-safe, schema-driven property management for Hive metastore objects 
(clusters, databases, tables).
+ *
+ * <p>This package allows declaring, validating, and persisting custom 
properties with runtime type
+ * checking and serialization support.</p>
+ *
+ * <h2>Core Components</h2>
+ *
+ * <h3>{@link org.apache.hadoop.hive.metastore.properties.PropertySchema}</h3>
+ * <p>Defines the blueprint for what properties can be set on a metastore 
object.</p>
+ * <ul>
+ *   <li>Declares allowed properties and their types (STRING, INTEGER, 
BOOLEAN, DATE, JSON, etc.)</li>
+ *   <li>Manages default values for properties</li>
+ *   <li>Tracks schema version — incremented when properties are added or 
removed</li>
+ *   <li>Generates a digest (UUID) for schema identity and caching</li>
+ * </ul>
+ *
+ * <h3>{@link org.apache.hadoop.hive.metastore.properties.PropertyType}</h3>
+ * <p>Abstract type system for property values with parsing, formatting, and 
binary serialization.
+ * Built-in types: {@code STRING}, {@code BOOLEAN}, {@code INTEGER}, {@code 
LONG}, {@code DOUBLE},
+ * {@code DATETIME} (ISO8601/UTC), {@code JSON} (Gson-backed). Custom types 
can be registered via
+ * {@link 
org.apache.hadoop.hive.metastore.properties.PropertyType#register(PropertyType)}.</p>
+ *
+ * <h3>{@link org.apache.hadoop.hive.metastore.properties.PropertyMap}</h3>
+ * <p>Holds the actual property values for a specific metastore object 
instance, validated against
+ * a {@code PropertySchema}. Uses copy-on-write semantics gated by a dirty 
flag for thread-safe,
+ * efficient sharing.</p>
+ *
+ * <h3>{@link org.apache.hadoop.hive.metastore.properties.PropertyManager}</h3>
+ * <p>High-level per-session manager that ties schemas into one namespace and 
drives transactional
+ * reads and writes. Tracks dirty maps to batch persistence store updates. 
Integrates with JEXL
+ * for dynamic property expressions.</p>
+ *
+ * <h3>{@link org.apache.hadoop.hive.metastore.properties.PropertyStore}</h3>
+ * <p>Persistence layer for loading and saving property maps to the metastore 
database.
+ * Can be wrapped by {@link 
org.apache.hadoop.hive.metastore.properties.CachingPropertyStore}
+ * for performance.</p>
+ *
+ * <h2>Workflow Example</h2>
+ * <pre>{@code
+ * // Define a schema (typically done at startup)
+ * PropertySchema tableSchema = new PropertySchema("table-schema", 1, new 
TreeMap<>());
+ * tableSchema.declareProperty("owner", PropertyType.STRING, "admin");
+ * tableSchema.declareProperty("is_external", PropertyType.BOOLEAN, false);
+ * tableSchema.declareProperty("created_time", PropertyType.DATETIME);
+ *
+ * // Create a property map for an object, set values, and persist
+ * PropertyMap tableProps = manager.newPropertyMap(tableSchema);
+ * tableProps.put("owner", "alice");
+ * tableProps.put("is_external", true);
+ * manager.persistProperties(tableProps);
+ * }</pre>
+ *
+ * <h2>Design Patterns</h2>
+ * <ul>
+ *   <li><b>Thread safety</b>: schemas use {@code AtomicInteger} version 
counters; maps use
+ *       copy-on-write with dirty flags; digest computation is double-checked 
locked.</li>
+ *   <li><b>Serialization</b>: a custom {@link 
org.apache.hadoop.hive.metastore.properties.SerializationProxy}
+ *       handles transient fields safely; both {@code DataInput}/{@code 
DataOutput} and Java object
+ *       serialization are supported.</li>
+ *   <li><b>Schema versioning</b>: version and digest UUID allow detecting 
schema changes and
+ *       support schema evolution without breaking existing data.</li>
+ * </ul>
+ */
+package org.apache.hadoop.hive.metastore.properties;
diff --git 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/PropertyServlet.java
 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/PropertyServlet.java
index adea578f239..fd3caea34cf 100644
--- 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/PropertyServlet.java
+++ 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/PropertyServlet.java
@@ -52,7 +52,100 @@
 import java.util.TreeMap;
 
 /**
- * The property-maps servlet.
+ * HTTP servlet exposing the {@link 
org.apache.hadoop.hive.metastore.properties.PropertyManager}
+ * API over JSON.
+ *
+ * <p>The servlet is mounted at a configurable path and port (see
+ * {@code MetastoreConf.ConfVars.PROPERTIES_SERVLET_PORT} and
+ * {@code MetastoreConf.ConfVars.PROPERTIES_SERVLET_PATH}). The last segment 
of the request URI is
+ * used as the property manager <em>namespace</em>, so the same servlet 
instance can serve multiple
+ * independent namespaces.</p>
+ *
+ * <h2>Namespace and Schema resolution</h2>
+ * <p>The last URI segment is the <em>namespace</em>. Each namespace must be 
registered in advance
+ * by calling {@link 
org.apache.hadoop.hive.metastore.properties.PropertyManager#declare(String, 
Class)}
+ * with a concrete {@link 
org.apache.hadoop.hive.metastore.properties.PropertyManager} subclass.
+ * That subclass is instantiated per request via its {@code (String, 
PropertyStore)} constructor.</p>
+ *
+ * <p>Within a namespace, the {@link 
org.apache.hadoop.hive.metastore.properties.PropertySchema} is
+ * <em>not</em> fixed — it is resolved dynamically by the manager from the 
number of dot-separated
+ * key fragments. For example, {@link 
org.apache.hadoop.hive.metastore.properties.HMSPropertyManager}
+ * (registered under {@code "hms"}) uses:</p>
+ * <table border="1">
+ *   <caption>HMSPropertyManager key-to-schema mapping</caption>
+ *   <tr><th>Fragments</th><th>Example key</th><th>Schema</th></tr>
+ *   <tr><td>1</td><td>{@code name}</td><td>CLUSTER_SCHEMA</td></tr>
+ *   <tr><td>2</td><td>{@code db.name}</td><td>DATABASE_SCHEMA</td></tr>
+ *   <tr><td>3+</td><td>{@code db.table.name}</td><td>TABLE_SCHEMA</td></tr>
+ * </table>
+ * <p>A namespace with no registered manager throws {@code 
NoSuchObjectException} (HTTP 400).</p>
+ *
+ * <h2>HTTP Methods</h2>
+ *
+ * <h3>GET — fetch properties by key</h3>
+ * <p>One or more {@code key} query parameters select individual property 
values.
+ * Returns a JSON object mapping each found key to its string value.</p>
+ * <pre>{@code
+ * GET /properties/mynamespace?key=db1.table1.owner&key=db1.table1.created_time
+ * → { "db1.table1.owner": "alice", "db1.table1.created_time": 
"2024-01-15T08:00:00.00Z" }
+ * }</pre>
+ *
+ * <h3>PUT — set properties</h3>
+ * <p>Request body must be a JSON object mapping qualified keys to values. All 
updates are
+ * committed atomically; any error triggers a rollback.</p>
+ * <pre>{@code
+ * PUT /properties/mynamespace
+ * { "db1.table1.owner": "bob", "db1.table1.is_external": "true" }
+ * }</pre>
+ *
+ * <h3>POST — query or script</h3>
+ * <p>The request body is a single JSON action object or a JSON array of 
action objects.
+ * Each action must have a {@code "method"} field (defaults to {@code 
"selectProperties"} if absent).
+ * Returns a single result object, or an array when multiple actions are 
submitted.
+ * All actions in one request share a transaction; any failure rolls back the 
entire batch.</p>
+ *
+ * <p>Supported methods:</p>
+ * <dl>
+ *   <dt>{@code fetchProperties}</dt>
+ *   <dd>Fetches exact values for a list of fully-qualified keys.
+ *   <pre>{@code
+ * { "method": "fetchProperties", "keys": ["db1.table1.owner", 
"db1.table1.tags"] }
+ * → { "db1.table1.owner": "alice" }
+ *   }</pre></dd>
+ *
+ *   <dt>{@code selectProperties}</dt>
+ *   <dd>Selects property maps whose key starts with {@code prefix}, 
optionally filtered by a
+ *   JEXL {@code predicate} expression and projected to a subset of property 
names via
+ *   {@code selection}.
+ *   <pre>{@code
+ * { "method": "selectProperties",
+ *   "prefix": "db1.",
+ *   "predicate": "owner == 'alice'",
+ *   "selection": ["owner", "is_external"] }
+ * → { "db1.table1": { "owner": "alice", "is_external": "true" } }
+ *   }</pre></dd>
+ *
+ *   <dt>{@code script}</dt>
+ *   <dd>Executes a JEXL script via {@link 
org.apache.hadoop.hive.metastore.properties.PropertyManager#runScript}.
+ *   <pre>{@code
+ * { "method": "script", "source": "select('db1.', null, null)" }
+ *   }</pre></dd>
+ *
+ *   <dt>{@code echo}</dt>
+ *   <dd>Returns the action object unchanged. Useful for health checks and 
round-trip testing.</dd>
+ * </dl>
+ *
+ * <h2>Error handling</h2>
+ * <p>{@link org.apache.hadoop.hive.metastore.properties.PropertyException} and
+ * {@code NoSuchObjectException} map to HTTP 400 (Bad Request);
+ * all other exceptions map to HTTP 500 (Internal Server Error).</p>
+ *
+ * <h2>Configuration</h2>
+ * <ul>
+ *   <li>{@code MetastoreConf.ConfVars.PROPERTIES_SERVLET_PORT} — listening 
port (negative disables the servlet)</li>
+ *   <li>{@code MetastoreConf.ConfVars.PROPERTIES_SERVLET_PATH} — URL path 
prefix</li>
+ *   <li>{@code MetastoreConf.ConfVars.PROPERTIES_SERVLET_AUTH} — 
authentication type</li>
+ * </ul>
  */
 public class PropertyServlet extends HttpServlet {
   /** The common prefix for errors. */
diff --git a/standalone-metastore/pom.xml b/standalone-metastore/pom.xml
index 5e52e03e1d3..806a00bb300 100644
--- a/standalone-metastore/pom.xml
+++ b/standalone-metastore/pom.xml
@@ -89,7 +89,7 @@
     <hikaricp.version>4.0.3</hikaricp.version>
     <iceberg.version>1.11.0</iceberg.version>
     <jackson.version>2.18.6</jackson.version>
-    <jexl.version>3.3</jexl.version>
+    <jexl.version>3.7.0</jexl.version>
     <javolution.version>5.5.1</javolution.version>
     <junit.version>4.13.2</junit.version>
     <junit.jupiter.version>5.13.3</junit.jupiter.version>

Reply via email to