diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..b9e59549e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,69 @@
+# Compiled source #
+###################
+*.com
+*.class
+*.dll
+*.exe
+*.o
+*.so
+
+# Packages #
+############
+# it's better to unpack these files and commit the raw source
+# git has its own built in compression methods
+*.7z
+*.dmg
+*.gz
+*.iso
+*.jar
+*.rar
+*.tar
+*.zip
+
+# Logs and databases #
+######################
+*.log
+
+# OS generated files #
+######################
+.DS_Store*
+ehthumbs.db
+Icon?
+Thumbs.db
+
+# Editor Files #
+################
+*~
+*.swp
+
+# Gradle Files #
+################
+.gradle
+.m2
+gradle
+
+# Build output directies
+/target
+*/target
+/build
+*/build
+
+# IntelliJ specific files/directories
+out
+.idea
+*.ipr
+*.iws
+*.iml
+atlassian-ide-plugin.xml
+
+# Eclipse specific files/directories
+.classpath
+.project
+.settings
+.metadata
+
+# NetBeans specific files/directories
+.nbattrs
+
+# Data created by elastic search tests
+metacat-main/data/
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..7f8ced0d1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2012 Netflix, Inc.
+
+ 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.
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..c05bef049
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+
+Metacat -- TODO
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 000000000..ed4b324e3
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2014 Netflix, Inc.
+ *
+ * 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.
+ */
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+}
+
+plugins {
+ id 'nebula.netflixoss' version '3.2.3'
+}
+
+ext.githubProjectName = rootProject.name
+
+allprojects {
+ repositories {
+ jcenter()
+ }
+}
+
+subprojects {
+ apply plugin: 'nebula.netflixoss'
+ apply plugin: 'nebula.source-jar'
+ apply plugin: 'java'
+ apply plugin: 'groovy'
+ apply plugin: 'checkstyle'
+ apply plugin: 'findbugs'
+ apply plugin: 'pmd'
+
+ group = "com.netflix.${githubProjectName}"
+
+ sourceCompatibility = 1.8
+ targetCompatibility = 1.8
+
+ dependencies {
+ testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
+ testCompile 'org.spockframework:spock-guice:1.0-groovy-2.4'
+ testCompile 'org.codehaus.gpars:gpars:1.2.1'
+ testCompile 'org.objenesis:objenesis:2.2' // Required by spock to mock classes
+ }
+
+ checkstyle {
+ toolVersion = '6.11'
+ configFile = new File(project.parent.projectDir, "codequality/checkstyle/checkstyle.xml")
+ }
+
+ findbugs {
+ ignoreFailures = true
+ excludeFilter = new File(project.parent.projectDir, "codequality/findbugs/excludeFilter.xml")
+ }
+
+ tasks.withType(Pmd) {
+ reports.html.enabled true
+ }
+}
diff --git a/codequality/HEADER b/codequality/HEADER
new file mode 100644
index 000000000..3102e4b44
--- /dev/null
+++ b/codequality/HEADER
@@ -0,0 +1,13 @@
+Copyright ${year} Netflix, Inc.
+
+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.
diff --git a/codequality/checkstyle.xml b/codequality/checkstyle.xml
new file mode 100644
index 000000000..ca1412bb7
--- /dev/null
+++ b/codequality/checkstyle.xml
@@ -0,0 +1,190 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 000000000..4a8070da5
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,24 @@
+#
+# Copyright 2014 Netflix, Inc.
+#
+# 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.
+#
+airlift_version=0.116
+commons_dbcp_version=2.1
+guava_version=18.0
+guice_version=4.0-beta5
+jackson_version=2.5.4
+jersey_version=2.19
+presto_version=0.118
+slf4j_version=1.7.12
+swagger_version=1.3.12
diff --git a/gradlew b/gradlew
new file mode 100755
index 000000000..9d82f7891
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 000000000..aec99730b
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/metacat-client/build.gradle b/metacat-client/build.gradle
new file mode 100644
index 000000000..fc1345cbc
--- /dev/null
+++ b/metacat-client/build.gradle
@@ -0,0 +1,24 @@
+apply plugin: 'java'
+
+compileJava {
+ sourceCompatibility = '1.7'
+ targetCompatibility = '1.7'
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compile project(':metacat-common')
+
+ compile 'com.netflix.feign:feign-core:8.6.0'
+ compile 'com.netflix.feign:feign-jaxrs:8.6.0'
+ compile 'com.netflix.feign:feign-slf4j:8.6.0'
+ compile 'com.fasterxml.jackson.datatype:jackson-datatype-guava:latest.release'
+ compile 'com.fasterxml.jackson.module:jackson-module-jaxb-annotations:latest.release'
+ compile "org.slf4j:slf4j-api:${slf4j_version}"
+ compile 'org.glassfish.jersey.core:jersey-server:2.15'
+
+ testCompile project(':metacat-common').sourceSets.test.output
+}
diff --git a/metacat-client/src/main/java/com/netflix/metacat/client/Client.java b/metacat-client/src/main/java/com/netflix/metacat/client/Client.java
new file mode 100644
index 000000000..85f54928f
--- /dev/null
+++ b/metacat-client/src/main/java/com/netflix/metacat/client/Client.java
@@ -0,0 +1,200 @@
+package com.netflix.metacat.client;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.guava.GuavaModule;
+import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
+import com.netflix.metacat.client.module.JacksonDecoder;
+import com.netflix.metacat.client.module.JacksonEncoder;
+import com.netflix.metacat.client.module.MetacatErrorDecoder;
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.api.MetacatV1;
+import com.netflix.metacat.common.api.MetadataV1;
+import com.netflix.metacat.common.api.PartitionV1;
+import com.netflix.metacat.common.json.MetacatJsonLocator;
+import feign.Feign;
+import feign.Request;
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+import feign.Retryer;
+import feign.jaxrs.JAXRSContract;
+import feign.slf4j.Slf4jLogger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nonnull;
+import java.util.concurrent.TimeUnit;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Client to communicate with Metacat. This version depends on the Feign library.
+ */
+public class Client {
+ private static final Logger log = LoggerFactory.getLogger(Client.class);
+ private final MetacatV1 api;
+ private final Feign.Builder feignBuilder;
+ private final String host;
+ private final PartitionV1 partitionApi;
+ private final MetadataV1 metadataApi;
+
+ private Client(
+ @Nonnull String host,
+ @Nonnull feign.Logger.Level logLevel,
+ @Nonnull RequestInterceptor requestInterceptor,
+ @Nonnull Retryer retryer,
+ @Nonnull Request.Options options
+ ) {
+ ObjectMapper mapper = MetacatJsonLocator.INSTANCE
+ .getPrettyObjectMapper()
+ .copy()
+ .registerModule(new GuavaModule())
+ .registerModule(new JaxbAnnotationModule());
+
+ log.info("Connecting to {}", host);
+ this.host = host;
+
+ feignBuilder = Feign.builder()
+ .logger(new Slf4jLogger())
+ .logLevel(logLevel)
+ .contract(new JAXRSContract())
+ .encoder(new JacksonEncoder(mapper))
+ .decoder(new JacksonDecoder(mapper))
+ .errorDecoder(new MetacatErrorDecoder())
+ .requestInterceptor(requestInterceptor)
+ .retryer(retryer)
+ .options(options);
+
+ api = getApiClient(MetacatV1.class);
+ partitionApi = getApiClient(PartitionV1.class);
+ metadataApi = getApiClient(MetadataV1.class);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private String host;
+ private String userName;
+ private String clientAppName;
+ private String jobId;
+ private String dataTypeContext;
+ private feign.Logger.Level logLevel;
+ private Retryer retryer;
+ private RequestInterceptor requestInterceptor;
+ private Request.Options requestOptions;
+
+ public Builder withLogLevel(feign.Logger.Level logLevel) {
+ this.logLevel = logLevel;
+ return this;
+ }
+
+ public Builder withHost(String host) {
+ this.host = host;
+ return this;
+ }
+
+ public Builder withRetryer(Retryer retryer) {
+ this.retryer = retryer;
+ return this;
+ }
+
+ public Builder withUserName(String userName) {
+ this.userName = userName;
+ return this;
+ }
+
+ public Builder withClientAppName(String appName) {
+ this.clientAppName = appName;
+ return this;
+ }
+
+ public Builder withJobId(String jobId) {
+ this.jobId = jobId;
+ return this;
+ }
+
+ public Builder withDataTypeContext(String dataTypeContext) {
+ this.dataTypeContext = dataTypeContext;
+ return this;
+ }
+
+ public Builder withRequestInterceptor(RequestInterceptor requestInterceptor) {
+ this.requestInterceptor = requestInterceptor;
+ return this;
+ }
+
+
+ public Builder withRequestOptions(Request.Options requestOptions) {
+ this.requestOptions = requestOptions;
+ return this;
+ }
+
+ public Client build() {
+ checkArgument(userName != null, "User name cannot be null");
+ checkArgument(clientAppName != null, "Client application name cannot be null");
+ if(host == null){
+ host = System.getProperty("netflix.metacat.host", System.getenv("NETFLIX_METACAT_HOST"));
+ }
+ checkArgument(host != null, "Host cannot be null");
+ if( retryer == null){
+ retryer = new Retryer.Default(TimeUnit.MINUTES.toMillis(30), TimeUnit.MINUTES.toMillis(30), 0);
+ }
+ RequestInterceptor interceptor = new RequestInterceptor() {
+ @Override
+ public void apply(RequestTemplate template) {
+ if( requestInterceptor != null) {
+ requestInterceptor.apply(template);
+ }
+ template.header(MetacatContext.HEADER_KEY_USER_NAME, userName);
+ template.header(MetacatContext.HEADER_KEY_CLIENT_APP_NAME, clientAppName);
+ template.header(MetacatContext.HEADER_KEY_JOB_ID, jobId);
+ template.header(MetacatContext.HEADER_KEY_DATA_TYPE_CONTEXT, dataTypeContext);
+ }
+ };
+ if( requestOptions == null){
+ requestOptions = new Request.Options((int)TimeUnit.MINUTES.toMillis(10), (int)TimeUnit.MINUTES.toMillis(30));
+ }
+ if( logLevel == null){
+ logLevel = feign.Logger.Level.NONE;
+ }
+ return new Client( host, logLevel, interceptor, retryer, requestOptions);
+ }
+ }
+
+ /**
+ * Returns an API instance that conforms to the given API Type that can communicate with the Metacat server
+ *
+ * @param apiType A JAX-RS annotated Metacat interface
+ * @return An instance that implements the given interface and is wired up to communicate with the Metacat server.
+ */
+ public T getApiClient(@Nonnull Class apiType) {
+ checkArgument(apiType.isInterface(), "apiType must be an interface");
+
+ return feignBuilder.target(apiType, host);
+ }
+
+ /**
+ * Return an API instance that can be used to interact with the metacat server
+ * @return An instance api conforming to MetacatV1 interface
+ */
+ public MetacatV1 getApi(){
+ return api;
+ }
+
+ /**
+ * Return an API instance that can be used to interact with the metacat server for partitions
+ * @return An instance api conforming to PartitionV1 interface
+ */
+ public PartitionV1 getPartitionApi(){
+ return partitionApi;
+ }
+
+ /**
+ * Return an API instance that can be used to interact with the metacat server for only user metadata
+ * @return An instance api conforming to MetadataV1 interface
+ */
+ public MetadataV1 getMetadataApi(){
+ return metadataApi;
+ }
+}
diff --git a/metacat-client/src/main/java/com/netflix/metacat/client/module/JacksonDecoder.java b/metacat-client/src/main/java/com/netflix/metacat/client/module/JacksonDecoder.java
new file mode 100644
index 000000000..faa528a6a
--- /dev/null
+++ b/metacat-client/src/main/java/com/netflix/metacat/client/module/JacksonDecoder.java
@@ -0,0 +1,35 @@
+package com.netflix.metacat.client.module;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.RuntimeJsonMappingException;
+import feign.Response;
+import feign.codec.Decoder;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Type;
+
+public class JacksonDecoder implements Decoder {
+ private final ObjectMapper mapper;
+
+ public JacksonDecoder(ObjectMapper mapper) {
+ this.mapper = mapper;
+ }
+
+ @Override
+ public Object decode(Response response, Type type) throws IOException {
+ if (response.body() == null || response.status() == 204
+ || (response.body().length() != null && response.body().length() == 0)) {
+ return null;
+ }
+ InputStream inputStream = response.body().asInputStream();
+ try {
+ return mapper.readValue(inputStream, mapper.constructType(type));
+ } catch (RuntimeJsonMappingException e) {
+ if (e.getCause() != null && e.getCause() instanceof IOException) {
+ throw IOException.class.cast(e.getCause());
+ }
+ throw e;
+ }
+ }
+}
diff --git a/metacat-client/src/main/java/com/netflix/metacat/client/module/JacksonEncoder.java b/metacat-client/src/main/java/com/netflix/metacat/client/module/JacksonEncoder.java
new file mode 100644
index 000000000..6046f29dc
--- /dev/null
+++ b/metacat-client/src/main/java/com/netflix/metacat/client/module/JacksonEncoder.java
@@ -0,0 +1,35 @@
+package com.netflix.metacat.client.module;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import feign.RequestTemplate;
+import feign.codec.EncodeException;
+import feign.codec.Encoder;
+
+import java.lang.reflect.Type;
+
+public class JacksonEncoder implements Encoder {
+ private final ObjectMapper mapper;
+
+ public JacksonEncoder(ObjectMapper mapper) {
+ this.mapper = mapper;
+ }
+
+ /**
+ * Converts objects to an appropriate representation in the template.
+ *
+ * @param object what to encode as the request body.
+ * @param bodyType the type the object should be encoded as. {@code Map}, if form
+ * encoding.
+ * @param template the request template to populate.
+ * @throws feign.codec.EncodeException when encoding failed due to a checked exception.
+ */
+ @Override
+ public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
+ try {
+ template.body(mapper.writeValueAsString(object));
+ } catch (JsonProcessingException e) {
+ throw new EncodeException(e.getMessage(), e);
+ }
+ }
+}
diff --git a/metacat-client/src/main/java/com/netflix/metacat/client/module/MetacatErrorDecoder.java b/metacat-client/src/main/java/com/netflix/metacat/client/module/MetacatErrorDecoder.java
new file mode 100644
index 000000000..10ba28967
--- /dev/null
+++ b/metacat-client/src/main/java/com/netflix/metacat/client/module/MetacatErrorDecoder.java
@@ -0,0 +1,56 @@
+package com.netflix.metacat.client.module;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.netflix.metacat.common.exception.MetacatAlreadyExistsException;
+import com.netflix.metacat.common.exception.MetacatBadRequestException;
+import com.netflix.metacat.common.exception.MetacatException;
+import com.netflix.metacat.common.exception.MetacatNotFoundException;
+import com.netflix.metacat.common.exception.MetacatNotSupportedException;
+import com.netflix.metacat.common.json.MetacatJson;
+import com.netflix.metacat.common.json.MetacatJsonException;
+import com.netflix.metacat.common.json.MetacatJsonLocator;
+import feign.Response;
+import feign.RetryableException;
+import feign.Util;
+
+import java.io.IOException;
+
+import static javax.ws.rs.core.Response.Status;
+
+/**
+ * Module that provides a error decoder, used to parse errors
+ */
+public class MetacatErrorDecoder extends feign.codec.ErrorDecoder.Default {
+ private static final MetacatJson metacatJson = MetacatJsonLocator.INSTANCE;
+ @Override
+ public Exception decode(String methodKey, Response response){
+ try {
+ Status status = Status.fromStatusCode(response.status());
+ String message = "";
+ if (response.body() != null){
+ message = Util.toString(response.body().asReader());
+ try {
+ ObjectNode body = metacatJson.parseJsonObject(message);
+ message = body.path("error").asText();
+ } catch (MetacatJsonException ignored) {}
+ }
+ switch (status) {
+ case UNSUPPORTED_MEDIA_TYPE:
+ return new MetacatNotSupportedException(message);
+ case BAD_REQUEST:
+ return new MetacatBadRequestException(message);
+ case NOT_FOUND:
+ return new MetacatNotFoundException(message);
+ case CONFLICT:
+ return new MetacatAlreadyExistsException(message);
+ case INTERNAL_SERVER_ERROR:
+ case SERVICE_UNAVAILABLE:
+ return new RetryableException(message, null);
+ default:
+ return new MetacatException(message, Status.INTERNAL_SERVER_ERROR, null);
+ }
+ } catch (IOException e) {
+ return super.decode(methodKey, response);
+ }
+ }
+}
diff --git a/metacat-common-server/build.gradle b/metacat-common-server/build.gradle
new file mode 100644
index 000000000..fe8d13219
--- /dev/null
+++ b/metacat-common-server/build.gradle
@@ -0,0 +1,11 @@
+dependencies {
+ compile project(':metacat-common')
+ compile "com.facebook.presto:presto-spi:${presto_version}"
+ compile 'org.apache.tomcat:tomcat-jdbc:8.0.22'
+ compile "com.google.guava:guava:${guava_version}"
+ compile "com.google.inject:guice:${guice_version}"
+ compile 'com.netflix.archaius:archaius-core:0.6.5'
+ compile 'com.netflix.servo:servo-core:0.8.3'
+ compile "io.airlift:configuration:${airlift_version}"
+ compile "org.slf4j:slf4j-api:${slf4j_version}"
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/exception/CatalogNotFoundException.java b/metacat-common-server/src/main/java/com/facebook/presto/exception/CatalogNotFoundException.java
new file mode 100644
index 000000000..2f7109d8f
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/exception/CatalogNotFoundException.java
@@ -0,0 +1,18 @@
+package com.facebook.presto.exception;
+
+import com.facebook.presto.spi.NotFoundException;
+
+/**
+ * Created by amajumdar on 4/30/15.
+ */
+public class CatalogNotFoundException extends NotFoundException{
+ private final String catalogName;
+ public CatalogNotFoundException(String catalogName) {
+ this(catalogName, null);
+ }
+
+ public CatalogNotFoundException(String catalogName, Throwable cause) {
+ super(String.format("Catalog %s not found.", catalogName), cause);
+ this.catalogName = catalogName;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/exception/InvalidMetaException.java b/metacat-common-server/src/main/java/com/facebook/presto/exception/InvalidMetaException.java
new file mode 100644
index 000000000..9fe891d0a
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/exception/InvalidMetaException.java
@@ -0,0 +1,34 @@
+package com.facebook.presto.exception;
+
+import com.facebook.presto.spi.PrestoException;
+import com.facebook.presto.spi.SchemaTableName;
+import com.facebook.presto.spi.StandardErrorCode;
+
+/**
+ * Created by amajumdar on 5/11/15.
+ */
+public class InvalidMetaException extends PrestoException {
+ private SchemaTableName tableName;
+ private String partitionId;
+
+ public InvalidMetaException(SchemaTableName tableName, Throwable cause) {
+ super(StandardErrorCode.USER_ERROR
+ , String.format("Invalid metadata for %s.", tableName)
+ , cause);
+ this.tableName = tableName;
+ }
+
+ public InvalidMetaException(SchemaTableName tableName, String partitionId, Throwable cause) {
+ super(StandardErrorCode.USER_ERROR
+ , String.format("Invalid metadata for %s for partition %s.", tableName, partitionId)
+ , cause);
+ this.tableName = tableName;
+ this.partitionId = partitionId;
+ }
+
+ public InvalidMetaException(String message, Throwable cause) {
+ super(StandardErrorCode.USER_ERROR
+ , message
+ , cause);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/exception/PartitionAlreadyExistsException.java b/metacat-common-server/src/main/java/com/facebook/presto/exception/PartitionAlreadyExistsException.java
new file mode 100644
index 000000000..0c0c38369
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/exception/PartitionAlreadyExistsException.java
@@ -0,0 +1,22 @@
+package com.facebook.presto.exception;
+
+import com.facebook.presto.spi.PrestoException;
+import com.facebook.presto.spi.SchemaTableName;
+import com.facebook.presto.spi.StandardErrorCode;
+
+/**
+ * Created by amajumdar on 4/30/15.
+ */
+public class PartitionAlreadyExistsException extends PrestoException{
+ private final SchemaTableName tableName;
+ private final String partitionId;
+ public PartitionAlreadyExistsException(SchemaTableName tableName, String partitionId) {
+ this(tableName, partitionId, null);
+ }
+
+ public PartitionAlreadyExistsException(SchemaTableName tableName, String partitionId, Throwable cause) {
+ super(StandardErrorCode.ALREADY_EXISTS, String.format("Partition %s already exists for table %s", tableName, partitionId==null?"": partitionId), cause);
+ this.tableName = tableName;
+ this.partitionId = partitionId;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/exception/PartitionNotFoundException.java b/metacat-common-server/src/main/java/com/facebook/presto/exception/PartitionNotFoundException.java
new file mode 100644
index 000000000..d4917bf01
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/exception/PartitionNotFoundException.java
@@ -0,0 +1,21 @@
+package com.facebook.presto.exception;
+
+import com.facebook.presto.spi.NotFoundException;
+import com.facebook.presto.spi.SchemaTableName;
+
+/**
+ * Created by amajumdar on 4/30/15.
+ */
+public class PartitionNotFoundException extends NotFoundException{
+ private final SchemaTableName tableName;
+ private final String partitionId;
+ public PartitionNotFoundException(SchemaTableName tableName, String partitionId) {
+ this(tableName, partitionId, null);
+ }
+
+ public PartitionNotFoundException(SchemaTableName tableName, String partitionId, Throwable cause) {
+ super(String.format("Partition %s not found for table %s", tableName, partitionId==null?"": partitionId), cause);
+ this.tableName = tableName;
+ this.partitionId = partitionId;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/exception/SchemaAlreadyExistsException.java b/metacat-common-server/src/main/java/com/facebook/presto/exception/SchemaAlreadyExistsException.java
new file mode 100644
index 000000000..1e0289012
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/exception/SchemaAlreadyExistsException.java
@@ -0,0 +1,19 @@
+package com.facebook.presto.exception;
+
+import com.facebook.presto.spi.PrestoException;
+import com.facebook.presto.spi.StandardErrorCode;
+
+/**
+ * Created by amajumdar on 4/30/15.
+ */
+public class SchemaAlreadyExistsException extends PrestoException{
+ private final String schemaName;
+ public SchemaAlreadyExistsException(String schemaName) {
+ this(schemaName, null);
+ }
+
+ public SchemaAlreadyExistsException(String schemaName, Throwable cause) {
+ super(StandardErrorCode.ALREADY_EXISTS, String.format("Schema %s already exists.", schemaName), cause);
+ this.schemaName = schemaName;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/plugin/ColumnDetailHandle.java b/metacat-common-server/src/main/java/com/facebook/presto/plugin/ColumnDetailHandle.java
new file mode 100644
index 000000000..56dcf77e6
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/plugin/ColumnDetailHandle.java
@@ -0,0 +1,167 @@
+package com.facebook.presto.plugin;
+
+import com.facebook.presto.spi.ColumnDetailMetadata;
+import com.facebook.presto.spi.ColumnHandle;
+import com.facebook.presto.spi.ColumnMetadata;
+import com.facebook.presto.spi.type.Type;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Created by amajumdar on 9/30/15.
+ */
+public class ColumnDetailHandle implements ColumnHandle {
+ private final String connectorId;
+ private final String columnName;
+ private final Type columnType;
+ private final Boolean isPartitionKey;
+ private final String comment;
+ private final String sourceType;
+ private final Integer size;
+ private final Boolean isNullable;
+ private final String defaultValue;
+ private final Boolean isSortKey;
+ private final Boolean isIndexKey;
+ @JsonCreator
+ public ColumnDetailHandle(
+ @JsonProperty("connectorId")
+ String connectorId,
+ @JsonProperty("columnName")
+ String columnName,
+ @JsonProperty("columnType")
+ Type columnType,
+ @JsonProperty("columnType")
+ Boolean isPartitionKey,
+ @JsonProperty("columnType")
+ String comment,
+ @JsonProperty("sourceType")
+ String sourceType,
+ @JsonProperty("size")
+ Integer size,
+ @JsonProperty("isNullable")
+ Boolean isNullable,
+ @JsonProperty("defaultValue")
+ String defaultValue,
+ @JsonProperty("isSortKey")
+ Boolean isSortKey,
+ @JsonProperty("isIndexKey")
+ Boolean isIndexKey) {
+ this.connectorId = checkNotNull(connectorId, "connectorId is null");
+ this.columnName = checkNotNull(columnName, "columnName is null");
+ this.columnType = checkNotNull(columnType, "columnType is null");
+ this.isPartitionKey = isPartitionKey;
+ this.comment = comment;
+ this.sourceType = sourceType;
+ this.size = size;
+ this.isNullable = isNullable;
+ this.defaultValue = defaultValue;
+ this.isSortKey = isSortKey;
+ this.isIndexKey = isIndexKey;
+ }
+
+ @JsonProperty
+ public String getConnectorId()
+ {
+ return connectorId;
+ }
+
+ @JsonProperty
+ public String getColumnName()
+ {
+ return columnName;
+ }
+
+ @JsonProperty
+ public Type getColumnType()
+ {
+ return columnType;
+ }
+
+ @JsonProperty
+ public Boolean getIsPartitionKey() {
+ return isPartitionKey;
+ }
+
+ @JsonProperty
+ public String getComment() {
+ return comment;
+ }
+
+ @JsonProperty
+ public String getSourceType() {
+ return sourceType;
+ }
+
+ @JsonProperty
+ public Integer getSize() {
+ return size;
+ }
+
+ @JsonProperty
+ public Boolean getIsNullable() {
+ return isNullable;
+ }
+
+ @JsonProperty
+ public String getDefaultValue() {
+ return defaultValue;
+ }
+
+ @JsonProperty
+ public Boolean getIsSortKey() {
+ return isSortKey;
+ }
+
+ @JsonProperty
+ public Boolean getIsIndexKey() {
+ return isIndexKey;
+ }
+
+ public ColumnMetadata getColumnMetadata()
+ {
+ StringBuilder comments = new StringBuilder(comment==null?"":comment).append(" ")
+ .append("nullable=").append(isNullable).append(", ")
+ .append("columnLength=").append(size).append(", ")
+ .append("default=").append(defaultValue).append(", ")
+ .append("sortKey=").append(isSortKey).append(", ")
+ .append("indexKey=").append(isIndexKey);
+
+ return new ColumnDetailMetadata(columnName, columnType, isPartitionKey==null?false:isPartitionKey,
+ comments.toString(), false, sourceType, size, isNullable, defaultValue, isSortKey, isIndexKey);
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if ((obj == null) || (getClass() != obj.getClass())) {
+ return false;
+ }
+ ColumnDetailHandle o = (ColumnDetailHandle) obj;
+ return Objects.equals(this.connectorId, o.connectorId) &&
+ Objects.equals(this.columnName, o.columnName);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(connectorId, columnName);
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("connectorId", connectorId)
+ .add("columnName", columnName)
+ .add("columnType", columnType)
+ .toString();
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/spi/AuditInfo.java b/metacat-common-server/src/main/java/com/facebook/presto/spi/AuditInfo.java
new file mode 100644
index 000000000..caf50d33d
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/spi/AuditInfo.java
@@ -0,0 +1,53 @@
+package com.facebook.presto.spi;
+
+/**
+ * Created by amajumdar on 3/3/15.
+ */
+public class AuditInfo {
+ private String createdBy;
+ private String lastUpdatedBy;
+ private Long createdDate;
+ private Long lastUpdatedDate;
+
+ public AuditInfo() {
+ }
+
+ public AuditInfo(String createdBy, String lastUpdatedBy, Long createdDate, Long lastUpdatedDate) {
+ this.createdBy = createdBy;
+ this.lastUpdatedBy = lastUpdatedBy;
+ this.createdDate = createdDate;
+ this.lastUpdatedDate = lastUpdatedDate;
+ }
+
+ public String getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(String createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public String getLastUpdatedBy() {
+ return lastUpdatedBy;
+ }
+
+ public void setLastUpdatedBy(String lastUpdatedBy) {
+ this.lastUpdatedBy = lastUpdatedBy;
+ }
+
+ public Long getCreatedDate() {
+ return createdDate;
+ }
+
+ public void setCreatedDate(Long createdDate) {
+ this.createdDate = createdDate;
+ }
+
+ public Long getLastUpdatedDate() {
+ return lastUpdatedDate;
+ }
+
+ public void setLastUpdatedDate(Long lastUpdatedDate) {
+ this.lastUpdatedDate = lastUpdatedDate;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/spi/ColumnDetailMetadata.java b/metacat-common-server/src/main/java/com/facebook/presto/spi/ColumnDetailMetadata.java
new file mode 100644
index 000000000..c55a3d2e6
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/spi/ColumnDetailMetadata.java
@@ -0,0 +1,60 @@
+package com.facebook.presto.spi;
+
+import com.facebook.presto.spi.type.Type;
+
+/**
+ * Created by amajumdar on 9/28/15.
+ */
+public class ColumnDetailMetadata extends ColumnMetadata {
+ private final String sourceType;
+ private final Integer size;
+ private final Boolean isNullable;
+ private final String defaultValue;
+ private final Boolean isSortKey;
+ private final Boolean isIndexKey;
+
+ public ColumnDetailMetadata(String name, Type type, boolean partitionKey, String sourceType) {
+ this(name , type, partitionKey, null, false, sourceType, null, null, null, null, null);
+ }
+
+ public ColumnDetailMetadata(String name, Type type, boolean partitionKey, String comment, boolean hidden
+ , String sourceType) {
+ this(name , type, partitionKey, comment, hidden, sourceType, null, null, null, null, null);
+ }
+
+ public ColumnDetailMetadata(String name, Type type, boolean partitionKey, String comment, boolean hidden
+ , String sourceType, Integer size, Boolean isNullable
+ , String defaultValue, Boolean isSortKey, Boolean isIndexKey) {
+ super(name, type, partitionKey, comment, hidden);
+ this.sourceType = sourceType;
+ this.size = size;
+ this.isNullable = isNullable;
+ this.defaultValue = defaultValue;
+ this.isSortKey = isSortKey;
+ this.isIndexKey = isIndexKey;
+ }
+
+ public String getSourceType() {
+ return sourceType;
+ }
+
+ public Boolean getIsNullable() {
+ return isNullable;
+ }
+
+ public Integer getSize() {
+ return size;
+ }
+
+ public String getDefaultValue() {
+ return defaultValue;
+ }
+
+ public Boolean getIsSortKey() {
+ return isSortKey;
+ }
+
+ public Boolean getIsIndexKey() {
+ return isIndexKey;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorDetailMetadata.java b/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorDetailMetadata.java
new file mode 100644
index 000000000..e0058fddf
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorDetailMetadata.java
@@ -0,0 +1,61 @@
+package com.facebook.presto.spi;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Created by amajumdar on 1/15/15.
+ */
+public interface ConnectorDetailMetadata extends ConnectorMetadata {
+ /**
+ * Creates a schema with the given schemaName
+ * @param session connector session
+ * @param schema schema metadata
+ */
+ void createSchema(ConnectorSession session, ConnectorSchemaMetadata schema);
+
+ /**
+ * Updates a schema with the given schemaName
+ * @param session connector session
+ * @param schema schema metadata
+ */
+ void updateSchema(ConnectorSession session, ConnectorSchemaMetadata schema);
+
+ /**
+ * Drop a schema with the given schemaName
+ * @param session connector session
+ * @param schemaName schema name
+ */
+ void dropSchema(ConnectorSession session, String schemaName);
+
+ /**
+ * Return schema with the given schemaName
+ * @param session connector session
+ * @param schemaName schema name
+ */
+ ConnectorSchemaMetadata getSchema(ConnectorSession session, String schemaName);
+
+ /**
+ * Updates a table using the specified table metadata.
+ */
+ ConnectorTableHandle alterTable(ConnectorSession session, ConnectorTableMetadata tableMetadata);
+
+ /**
+ * Returns all the table names referring to the given uri
+ * @param uri location
+ * @param prefixSearch if tru, we look for tables whose location starts with the given uri
+ * @return list of table names
+ */
+ default List getTableNames(String uri, boolean prefixSearch){
+ return Lists.newArrayList();
+ }
+
+ /**
+ * Similar to listTables but this method will return the list of tables along with its metadata.
+ * @param session connector session
+ * @param schemaName schema name
+ * @return list of table metadata
+ */
+ List listTableMetadatas(ConnectorSession session, String schemaName, List tableNames);
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorPartitionDetail.java b/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorPartitionDetail.java
new file mode 100644
index 000000000..99edbb43e
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorPartitionDetail.java
@@ -0,0 +1,27 @@
+package com.facebook.presto.spi;
+
+import java.util.Map;
+
+/**
+ * Created by amajumdar on 2/2/15.
+ */
+public interface ConnectorPartitionDetail extends ConnectorPartition
+{
+ /**
+ * Gets any extra properties of a partition that is relevant to a particular catalog.
+ * @return extra properties other than the partition key
+ */
+ Map getMetadata();
+
+ /**
+ * Gets the storage related information about the partition. This applies mostly in the case of unstructured data stored as files.
+ * @return storage information related properties
+ */
+ StorageInfo getStorageInfo();
+
+ /**
+ * Gets the audit information like created date, last update date etc..
+ * @return audit information
+ */
+ AuditInfo getAuditInfo();
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorPartitionDetailImpl.java b/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorPartitionDetailImpl.java
new file mode 100644
index 000000000..c3546c036
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorPartitionDetailImpl.java
@@ -0,0 +1,62 @@
+package com.facebook.presto.spi;
+
+import java.util.Map;
+
+/**
+ * Created by amajumdar on 2/2/15.
+ */
+public class ConnectorPartitionDetailImpl implements ConnectorPartitionDetail{
+ private final String partitionId;
+ private final TupleDomain tupleDomain;
+ private final StorageInfo storageInfo;
+ private Map metadata;
+ private final AuditInfo auditInfo;
+
+ public ConnectorPartitionDetailImpl(String partitionId,
+ TupleDomain tupleDomain, Map metadata) {
+ this(partitionId, tupleDomain, null, metadata, null);
+ }
+
+ public ConnectorPartitionDetailImpl(String partitionId,
+ TupleDomain tupleDomain, StorageInfo storageInfo, Map metadata) {
+ this(partitionId, tupleDomain, storageInfo, metadata, null);
+ }
+
+ public ConnectorPartitionDetailImpl(String partitionId,
+ TupleDomain tupleDomain, StorageInfo storageInfo, Map metadata, AuditInfo auditInfo) {
+ this.partitionId = partitionId;
+ this.tupleDomain = tupleDomain;
+ this.storageInfo = storageInfo;
+ this.metadata = metadata;
+ this.auditInfo = auditInfo!=null?auditInfo:new AuditInfo();
+ }
+
+ @Override
+ public Map getMetadata() {
+ return metadata;
+ }
+
+ @Override
+ public StorageInfo getStorageInfo() {
+ return storageInfo;
+ }
+
+ @Override
+ public String getPartitionId() {
+ return partitionId;
+ }
+
+ @Override
+ public TupleDomain getTupleDomain() {
+ return tupleDomain;
+ }
+
+ @Override
+ public AuditInfo getAuditInfo() {
+ return auditInfo;
+ }
+
+ public void setMetadata(Map metadata) {
+ this.metadata = metadata;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorSchemaMetadata.java b/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorSchemaMetadata.java
new file mode 100644
index 000000000..ff782f9a2
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorSchemaMetadata.java
@@ -0,0 +1,40 @@
+package com.facebook.presto.spi;
+
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+
+/**
+ * Created by amajumdar on 3/9/16.
+ */
+public class ConnectorSchemaMetadata {
+ private String schemaName;
+ private String uri;
+ private Map metadata;
+
+ public ConnectorSchemaMetadata(String schemaName) {
+ this(schemaName, null);
+ }
+
+ public ConnectorSchemaMetadata(String schemaName, String uri) {
+ this(schemaName, uri, Maps.newHashMap());
+ }
+
+ public ConnectorSchemaMetadata(String schemaName, String uri, Map metadata) {
+ this.schemaName = schemaName;
+ this.uri = uri;
+ this.metadata = metadata;
+ }
+
+ public String getSchemaName() {
+ return schemaName;
+ }
+
+ public String getUri() {
+ return uri;
+ }
+
+ public Map getMetadata() {
+ return metadata;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorSplitDetailManager.java b/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorSplitDetailManager.java
new file mode 100644
index 000000000..445607baf
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorSplitDetailManager.java
@@ -0,0 +1,52 @@
+package com.facebook.presto.spi;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Created by amajumdar on 2/2/15.
+ */
+public interface ConnectorSplitDetailManager extends ConnectorSplitManager{
+ /**
+ * Gets the Partitions based on a filter expression for the specified table.
+ * @param table table handle
+ * @param filterExpression JSP based filter expression string
+ * @param partitionNames filter the list that matches the given partition names. If null or empty, it will return all.
+ * @return filtered list of partitions
+ */
+ ConnectorPartitionResult getPartitions(ConnectorTableHandle table, String filterExpression, List partitionNames, Sort sort, Pageable pageable, boolean includePartitionDetails);
+
+ /**
+ * Add/Update/delete partitions for a table
+ * @param table table handle
+ * @param partitions list of partitions
+ * @param partitionIdsForDeletes list of partition ids/names for deletes
+ * @return added/updated list of partition names
+ */
+ SavePartitionResult savePartitions(ConnectorTableHandle table, List partitions, List partitionIdsForDeletes, boolean checkIfExists);
+
+ /**
+ * Delete partitions for a table
+ * @param table table handle
+ * @param partitionIds list of partition names
+ */
+ void deletePartitions(ConnectorTableHandle table, List partitionIds);
+
+ /**
+ * Number of partitions for the given table
+ * @param connectorHandle table handle
+ * @return Number of partitions
+ */
+ Integer getPartitionCount(ConnectorTableHandle connectorHandle);
+
+ /**
+ * Returns all the partition names referring to the given uri
+ * @param uri location
+ * @param prefixSearch if tru, we look for tables whose location starts with the given uri
+ * @return list of partition names
+ */
+ default List getPartitionNames(String uri, boolean prefixSearch){
+ return Lists.newArrayList();
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorTableDetailMetadata.java b/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorTableDetailMetadata.java
new file mode 100644
index 000000000..9aaf9622a
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/spi/ConnectorTableDetailMetadata.java
@@ -0,0 +1,61 @@
+package com.facebook.presto.spi;
+
+import com.google.common.collect.Maps;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class contains any extra metadata about the table. This was created initially for the serde info that exists in
+ * hive.
+ *
+ * Created by amajumdar on 1/15/15.
+ */
+public class ConnectorTableDetailMetadata extends ConnectorTableMetadata {
+ private StorageInfo storageInfo;
+ private Map metadata;
+ private AuditInfo auditInfo;
+ public ConnectorTableDetailMetadata(SchemaTableName table,
+ List columns, Map metadata) {
+ this( table, columns, null, null, metadata, null);
+ }
+
+ public ConnectorTableDetailMetadata(SchemaTableName table,
+ List columns, StorageInfo storageInfo, Map metadata) {
+ this( table, columns, null, storageInfo, metadata, null);
+ }
+
+ public ConnectorTableDetailMetadata(SchemaTableName table, List columns
+ , String owner, StorageInfo storageInfo, Map metadata
+ , AuditInfo auditInfo)
+ {
+ super(table, columns, Maps.newHashMap(), owner, false);
+ this.storageInfo = storageInfo;
+ this.metadata = metadata;
+ this.auditInfo = auditInfo!=null?auditInfo:new AuditInfo();
+ }
+
+ public StorageInfo getStorageInfo() {
+ return storageInfo;
+ }
+
+ public void setStorageInfo(StorageInfo storageInfo) {
+ this.storageInfo = storageInfo;
+ }
+
+ public Map getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(Map metadata) {
+ this.metadata = metadata;
+ }
+
+ public AuditInfo getAuditInfo() {
+ return auditInfo;
+ }
+
+ public void setAuditInfo(AuditInfo auditInfo) {
+ this.auditInfo = auditInfo;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/spi/Pageable.java b/metacat-common-server/src/main/java/com/facebook/presto/spi/Pageable.java
new file mode 100644
index 000000000..4d7112a87
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/spi/Pageable.java
@@ -0,0 +1,38 @@
+package com.facebook.presto.spi;
+
+/**
+ * Represents the pagination information
+ * Created by amajumdar on 3/16/15.
+ */
+public class Pageable {
+ private Integer limit;
+ private Integer offset;
+
+ public Pageable() {
+ }
+
+ public Pageable(Integer limit, Integer offset) {
+ this.limit = limit;
+ this.offset = offset;
+ }
+
+ public Integer getLimit() {
+ return limit;
+ }
+
+ public void setLimit(Integer limit) {
+ this.limit = limit;
+ }
+
+ public Integer getOffset() {
+ return offset==null?0:offset;
+ }
+
+ public void setOffset(Integer offset) {
+ this.offset = offset;
+ }
+
+ public boolean isPageable(){
+ return limit != null;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/spi/SavePartitionResult.java b/metacat-common-server/src/main/java/com/facebook/presto/spi/SavePartitionResult.java
new file mode 100644
index 000000000..e57a69d3b
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/spi/SavePartitionResult.java
@@ -0,0 +1,37 @@
+package com.facebook.presto.spi;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by amajumdar on 7/20/15.
+ */
+public class SavePartitionResult {
+ List added;
+ List updated;
+
+ public SavePartitionResult() {
+ added = new ArrayList<>();
+ updated = new ArrayList<>();
+ }
+
+ public List getAdded() {
+ return added;
+ }
+
+ public void setAdded(List added) {
+ if( added != null) {
+ this.added = added;
+ }
+ }
+
+ public List getUpdated() {
+ return updated;
+ }
+
+ public void setUpdated(List updated) {
+ if( updated != null) {
+ this.updated = updated;
+ }
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/spi/SchemaTablePartitionName.java b/metacat-common-server/src/main/java/com/facebook/presto/spi/SchemaTablePartitionName.java
new file mode 100644
index 000000000..676323bd9
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/spi/SchemaTablePartitionName.java
@@ -0,0 +1,22 @@
+package com.facebook.presto.spi;
+
+/**
+ * Created by amajumdar on 7/13/15.
+ */
+public class SchemaTablePartitionName {
+ private final SchemaTableName tableName;
+ private final String partitionId;
+
+ public SchemaTablePartitionName(SchemaTableName tableName, String partitionId) {
+ this.tableName = tableName;
+ this.partitionId = partitionId;
+ }
+
+ public String getPartitionId() {
+ return partitionId;
+ }
+
+ public SchemaTableName getTableName() {
+ return tableName;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/spi/Sort.java b/metacat-common-server/src/main/java/com/facebook/presto/spi/Sort.java
new file mode 100644
index 000000000..354dfbbbf
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/spi/Sort.java
@@ -0,0 +1,37 @@
+package com.facebook.presto.spi;
+
+/**
+ * Created by amajumdar on 3/16/15.
+ */
+public class Sort {
+ private String sortBy;
+ private SortOrder order;
+
+ public Sort() {
+ }
+
+ public Sort(String sortBy, SortOrder order) {
+ this.sortBy = sortBy;
+ this.order = order;
+ }
+
+ public String getSortBy() {
+ return sortBy;
+ }
+
+ public void setSortBy(String sortBy) {
+ this.sortBy = sortBy;
+ }
+
+ public SortOrder getOrder() {
+ return order==null?SortOrder.ASC:order;
+ }
+
+ public void setOrder(SortOrder order) {
+ this.order = order;
+ }
+
+ public boolean hasSort(){
+ return sortBy != null;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/spi/SortOrder.java b/metacat-common-server/src/main/java/com/facebook/presto/spi/SortOrder.java
new file mode 100644
index 000000000..cfa76202e
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/spi/SortOrder.java
@@ -0,0 +1,8 @@
+package com.facebook.presto.spi;
+
+/**
+ * Created by amajumdar on 3/16/15.
+ */
+public enum SortOrder {
+ ASC, DESC
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/spi/StorageInfo.java b/metacat-common-server/src/main/java/com/facebook/presto/spi/StorageInfo.java
new file mode 100644
index 000000000..2f3c5c953
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/spi/StorageInfo.java
@@ -0,0 +1,81 @@
+package com.facebook.presto.spi;
+
+import java.util.Map;
+
+/**
+ * Created by amajumdar on 3/3/15.
+ */
+public class StorageInfo {
+ /* Location of the data */
+ private String uri;
+ /* Input format of the file */
+ private String inputFormat;
+ /* Output format of the file */
+ private String outputFormat;
+ /* Serialization library */
+ private String serializationLib;
+ /* Serialization parameters */
+ private Map parameters;
+ private Map serdeInfoParameters;
+
+ public StorageInfo() {
+ }
+
+ public StorageInfo(String uri, String inputFormat, String outputFormat, String serializationLib,
+ Map parameters, Map serdeInfoParameters) {
+ this.uri = uri;
+ this.inputFormat = inputFormat;
+ this.outputFormat = outputFormat;
+ this.serializationLib = serializationLib;
+ this.parameters = parameters;
+ this.serdeInfoParameters = serdeInfoParameters;
+ }
+
+ public String getInputFormat() {
+ return inputFormat;
+ }
+
+ public void setInputFormat(String inputFormat) {
+ this.inputFormat = inputFormat;
+ }
+
+ public String getOutputFormat() {
+ return outputFormat;
+ }
+
+ public void setOutputFormat(String outputFormat) {
+ this.outputFormat = outputFormat;
+ }
+
+ public String getSerializationLib() {
+ return serializationLib;
+ }
+
+ public void setSerializationLib(String serializationLib) {
+ this.serializationLib = serializationLib;
+ }
+
+ public Map getParameters() {
+ return parameters;
+ }
+
+ public void setParameters(Map parameters) {
+ this.parameters = parameters;
+ }
+
+ public Map getSerdeInfoParameters() {
+ return serdeInfoParameters;
+ }
+
+ public void setSerdeInfoParameters(Map serdeInfoParameters) {
+ this.serdeInfoParameters = serdeInfoParameters;
+ }
+
+ public String getUri() {
+ return uri;
+ }
+
+ public void setUri(String uri) {
+ this.uri = uri;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/type/FloatType.java b/metacat-common-server/src/main/java/com/facebook/presto/type/FloatType.java
new file mode 100644
index 000000000..a37c27ee5
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/type/FloatType.java
@@ -0,0 +1,87 @@
+package com.facebook.presto.type;
+
+import com.facebook.presto.spi.ConnectorSession;
+import com.facebook.presto.spi.block.Block;
+import com.facebook.presto.spi.block.BlockBuilder;
+import com.facebook.presto.spi.type.AbstractFixedWidthType;
+
+import static com.facebook.presto.spi.type.TypeSignature.parseTypeSignature;
+import static io.airlift.slice.SizeOf.SIZE_OF_FLOAT;
+
+public final class FloatType extends AbstractFixedWidthType
+{
+ public static final FloatType FLOAT = new FloatType();
+ public static final String TYPE = "float";
+
+ private FloatType()
+ {
+ super(parseTypeSignature(TYPE), float.class, SIZE_OF_FLOAT);
+ }
+
+ @Override
+ public boolean isComparable()
+ {
+ return true;
+ }
+
+ @Override
+ public boolean isOrderable()
+ {
+ return true;
+ }
+
+ @Override
+ public Object getObjectValue(ConnectorSession session, Block block, int position)
+ {
+ if (block.isNull(position)) {
+ return null;
+ }
+ return block.getFloat(position, 0);
+ }
+
+ @Override
+ public boolean equalTo(Block leftBlock, int leftPosition, Block rightBlock, int rightPosition)
+ {
+ float leftValue = leftBlock.getFloat(leftPosition, 0);
+ float rightValue = rightBlock.getFloat(rightPosition, 0);
+ return leftValue == rightValue;
+ }
+
+ @Override
+ public int hash(Block block, int position)
+ {
+ long value = block.getLong(position, 0);
+ return (int) (value ^ (value >>> 32));
+ }
+
+ @Override
+ public int compareTo(Block leftBlock, int leftPosition, Block rightBlock, int rightPosition)
+ {
+ float leftValue = leftBlock.getFloat(leftPosition, 0);
+ float rightValue = rightBlock.getFloat(rightPosition, 0);
+ return Double.compare(leftValue, rightValue);
+ }
+
+ @Override
+ public void appendTo(Block block, int position, BlockBuilder blockBuilder)
+ {
+ if (block.isNull(position)) {
+ blockBuilder.appendNull();
+ }
+ else {
+ blockBuilder.writeFloat(block.getFloat(position, 0)).closeEntry();
+ }
+ }
+
+ @Override
+ public double getDouble(Block block, int position)
+ {
+ return block.getFloat(position, 0);
+ }
+
+ @Override
+ public void writeDouble(BlockBuilder blockBuilder, double value)
+ {
+ blockBuilder.writeFloat((float)value).closeEntry();
+ }
+}
\ No newline at end of file
diff --git a/metacat-common-server/src/main/java/com/facebook/presto/type/IntType.java b/metacat-common-server/src/main/java/com/facebook/presto/type/IntType.java
new file mode 100644
index 000000000..ac0e34788
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/facebook/presto/type/IntType.java
@@ -0,0 +1,80 @@
+package com.facebook.presto.type;
+
+import com.facebook.presto.spi.ConnectorSession;
+import com.facebook.presto.spi.block.Block;
+import com.facebook.presto.spi.block.BlockBuilder;
+import com.facebook.presto.spi.type.AbstractFixedWidthType;
+
+import static com.facebook.presto.spi.type.TypeSignature.parseTypeSignature;
+import static io.airlift.slice.SizeOf.SIZE_OF_INT;
+
+/**
+ * Created by amajumdar on 6/15/15.
+ */
+public final class IntType extends AbstractFixedWidthType {
+ public static final IntType INT = new IntType();
+ public static final String TYPE = "int";
+
+ private IntType() {
+ super(parseTypeSignature(TYPE), int.class, SIZE_OF_INT);
+ }
+
+ @Override
+ public boolean isComparable() {
+ return true;
+ }
+
+ @Override
+ public boolean isOrderable() {
+ return true;
+ }
+
+ @Override
+ public Object getObjectValue(ConnectorSession session, Block block, int position) {
+ if (block.isNull(position)) {
+ return null;
+ }
+
+ return block.getInt(position, 0);
+ }
+
+ @Override
+ public boolean equalTo(Block leftBlock, int leftPosition, Block rightBlock, int rightPosition) {
+ long leftValue = leftBlock.getInt(leftPosition, 0);
+ long rightValue = rightBlock.getInt(rightPosition, 0);
+ return leftValue == rightValue;
+ }
+
+ @Override
+ public int hash(Block block, int position) {
+ long value = block.getInt(position, 0);
+ return (int) (value ^ (value >>> 32));
+ }
+
+ @Override
+ @SuppressWarnings("SuspiciousNameCombination")
+ public int compareTo(Block leftBlock, int leftPosition, Block rightBlock, int rightPosition) {
+ int leftValue = leftBlock.getInt(leftPosition, 0);
+ int rightValue = rightBlock.getInt(rightPosition, 0);
+ return Integer.compare(leftValue, rightValue);
+ }
+
+ @Override
+ public void appendTo(Block block, int position, BlockBuilder blockBuilder) {
+ if (block.isNull(position)) {
+ blockBuilder.appendNull();
+ } else {
+ blockBuilder.writeInt(block.getInt(position, 0)).closeEntry();
+ }
+ }
+
+ @Override
+ public long getLong(Block block, int position) {
+ return block.getInt(position, 0);
+ }
+
+ @Override
+ public void writeLong(BlockBuilder blockBuilder, long value) {
+ blockBuilder.writeInt((int)value).closeEntry();
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/model/Lookup.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/model/Lookup.java
new file mode 100644
index 000000000..b6f8d0afd
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/model/Lookup.java
@@ -0,0 +1,103 @@
+package com.netflix.metacat.common.model;
+
+import com.netflix.metacat.common.server.Config;
+
+import javax.inject.Inject;
+import java.util.Date;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Created by amajumdar on 6/30/15.
+ */
+public class Lookup {
+ private static Config config;
+ private Long id;
+ private String name;
+ private String type = "string";
+ private Set values;
+ private Date dateCreated;
+ private Date lastUpdated;
+ private String createdBy;
+ private String lastUpdatedBy;
+
+ public Lookup() {
+ checkNotNull(config, "config should have been set in the static setConfig");
+ createdBy = lastUpdatedBy = config.getLookupServiceUserAdmin();
+ }
+
+ /**
+ * This must be called statically to set the config before the class can be used.
+ *
+ * @param config the metacat configuration
+ */
+ @Inject
+ public static void setConfig(Config config) {
+ Lookup.config = config;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public Set getValues() {
+ return values;
+ }
+
+ public void setValues(Set values) {
+ this.values = values;
+ }
+
+ public Date getDateCreated() {
+ return dateCreated;
+ }
+
+ public void setDateCreated(Date dateCreated) {
+ this.dateCreated = dateCreated;
+ }
+
+ public Date getLastUpdated() {
+ return lastUpdated;
+ }
+
+ public void setLastUpdated(Date lastUpdated) {
+ this.lastUpdated = lastUpdated;
+ }
+
+ public String getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(String createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public String getLastUpdatedBy() {
+ return lastUpdatedBy;
+ }
+
+ public void setLastUpdatedBy(String lastUpdatedBy) {
+ this.lastUpdatedBy = lastUpdatedBy;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/model/TagItem.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/model/TagItem.java
new file mode 100644
index 000000000..bee7fc27a
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/model/TagItem.java
@@ -0,0 +1,94 @@
+package com.netflix.metacat.common.model;
+
+import com.netflix.metacat.common.server.Config;
+
+import javax.inject.Inject;
+import java.util.Date;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Created by amajumdar on 6/30/15.
+ */
+public class TagItem {
+ private static Config config;
+ private Long id;
+ private String name;
+ private Set values;
+ private Date dateCreated;
+ private Date lastUpdated;
+ private String createdBy;
+ private String lastUpdatedBy;
+
+ public TagItem() {
+ checkNotNull(config, "config should have been set in the static setConfig");
+ createdBy = lastUpdatedBy = config.getLookupServiceUserAdmin();
+ }
+
+ /**
+ * This must be called statically to set the config before the class can be used.
+ *
+ * @param config the metacat configuration
+ */
+ @Inject
+ public static void setConfig(Config config) {
+ TagItem.config = config;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Set getValues() {
+ return values;
+ }
+
+ public void setValues(Set values) {
+ this.values = values;
+ }
+
+ public Date getDateCreated() {
+ return dateCreated;
+ }
+
+ public void setDateCreated(Date dateCreated) {
+ this.dateCreated = dateCreated;
+ }
+
+ public Date getLastUpdated() {
+ return lastUpdated;
+ }
+
+ public void setLastUpdated(Date lastUpdated) {
+ this.lastUpdated = lastUpdated;
+ }
+
+ public String getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(String createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public String getLastUpdatedBy() {
+ return lastUpdatedBy;
+ }
+
+ public void setLastUpdatedBy(String lastUpdatedBy) {
+ this.lastUpdatedBy = lastUpdatedBy;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/monitoring/CounterWrapper.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/monitoring/CounterWrapper.java
new file mode 100644
index 000000000..becd9abe2
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/monitoring/CounterWrapper.java
@@ -0,0 +1,48 @@
+package com.netflix.metacat.common.monitoring;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.netflix.servo.DefaultMonitorRegistry;
+import com.netflix.servo.monitor.Counter;
+import com.netflix.servo.monitor.Monitors;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nonnull;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Servo counter wrapper
+ *
+ * @author amajumdar
+ */
+public class CounterWrapper {
+ private static final LoadingCache COUNTERS = CacheBuilder.newBuilder()
+ .build(
+ new CacheLoader() {
+ public Counter load(@Nonnull String counterName) {
+ Counter counter = Monitors.newCounter(counterName);
+ DefaultMonitorRegistry.getInstance().register(counter);
+ return counter;
+ }
+ });
+ private static final Logger log = LoggerFactory.getLogger(CounterWrapper.class);
+
+ public static void incrementCounter(String counterName, long incrementAmount) {
+ try {
+ Counter counter = COUNTERS.get(counterName);
+ if (incrementAmount == 1) {
+ counter.increment();
+ } else {
+ counter.increment(incrementAmount);
+ }
+ } catch (ExecutionException ex) {
+ log.warn("Error fetching counter: {}", counterName, ex);
+ }
+ }
+
+ public static void incrementCounter(String counterName) {
+ incrementCounter(counterName, 1);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/monitoring/DynamicGauge.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/monitoring/DynamicGauge.java
new file mode 100644
index 000000000..10712d021
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/monitoring/DynamicGauge.java
@@ -0,0 +1,140 @@
+package com.netflix.metacat.common.monitoring;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Throwables;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableList;
+import com.netflix.servo.DefaultMonitorRegistry;
+import com.netflix.servo.monitor.CompositeMonitor;
+import com.netflix.servo.monitor.DoubleGauge;
+import com.netflix.servo.monitor.Monitor;
+import com.netflix.servo.monitor.MonitorConfig;
+import com.netflix.servo.monitor.Monitors;
+import com.netflix.servo.tag.TagList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Utility class that dynamically creates gauges based on an arbitrary (name, tagList), or {@link com.netflix.servo.monitor.MonitorConfig}
+ * Gauges are automatically expired after 15 minutes of inactivity.
+ */
+public final class DynamicGauge implements CompositeMonitor {
+ private static final Logger log = LoggerFactory.getLogger(DynamicGauge.class);
+ private static final String DEFAULT_EXPIRATION = "15";
+ private static final String DEFAULT_EXPIRATION_UNIT = "MINUTES";
+ private static final String CLASS_NAME = DynamicGauge.class.getCanonicalName();
+ private static final String EXPIRATION_PROP = CLASS_NAME + ".expiration";
+ private static final String EXPIRATION_PROP_UNIT = CLASS_NAME + ".expirationUnit";
+ private static final String INTERNAL_ID = "servoGauges";
+ private static final String CACHE_MONITOR_ID = "servoGaugesCache";
+ private static final MonitorConfig BASE_CONFIG = new MonitorConfig.Builder(INTERNAL_ID).build();
+
+ private static final DynamicGauge INSTANCE = new DynamicGauge();
+
+ private final LoadingCache gauges;
+ private final CompositeMonitor> cacheMonitor;
+
+ private DynamicGauge() {
+ final String expiration = System.getProperty(EXPIRATION_PROP, DEFAULT_EXPIRATION);
+ final String expirationUnit = System.getProperty(EXPIRATION_PROP_UNIT, DEFAULT_EXPIRATION_UNIT);
+ final long expirationValue = Long.parseLong(expiration);
+ final TimeUnit expirationUnitValue = TimeUnit.valueOf(expirationUnit);
+
+ gauges = CacheBuilder.newBuilder()
+ .expireAfterAccess(expirationValue, expirationUnitValue)
+ .build(new CacheLoader() {
+ @Override
+ public DoubleGauge load(@Nonnull final MonitorConfig config) throws Exception {
+ return new DoubleGauge(config);
+ }
+ });
+ cacheMonitor = Monitors.newCacheMonitor(CACHE_MONITOR_ID, gauges);
+ DefaultMonitorRegistry.getInstance().register(this);
+ }
+
+ /**
+ * Set a gauge based on a given {@link MonitorConfig} by a given value.
+ *
+ * @param config The monitoring config
+ * @param value The amount added to the current value
+ */
+ public static void set(MonitorConfig config, double value) {
+ INSTANCE.get(config).set(value);
+ }
+
+ /**
+ * Increment a gauge specified by a name.
+ */
+ public static void set(String name, double value) {
+ set(MonitorConfig.builder(name).build(), value);
+ }
+
+ /**
+ * Set the gauge for a given name, tagList by a given value.
+ */
+ public static void set(String name, TagList list, double value) {
+ final MonitorConfig config = MonitorConfig.builder(name).withTags(list).build();
+ set(config, value);
+ }
+
+ private DoubleGauge get(MonitorConfig config) {
+ try {
+ return gauges.get(config);
+ } catch (ExecutionException e) {
+ log.error("Failed to get a gauge for {}: {}", config, e.getMessage());
+ throw Throwables.propagate(e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List> getMonitors() {
+ final ConcurrentMap gaugesMap = gauges.asMap();
+ return ImmutableList.copyOf(gaugesMap.values());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Long getValue() {
+ return (long) gauges.asMap().size();
+ }
+
+ @Override
+ public Long getValue(int pollerIndex) {
+ return getValue();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public MonitorConfig getConfig() {
+ return BASE_CONFIG;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ ConcurrentMap, ?> map = gauges.asMap();
+ return MoreObjects.toStringHelper(this)
+ .add("baseConfig", BASE_CONFIG)
+ .add("totalGauges", map.size())
+ .add("gauges", map)
+ .toString();
+ }
+}
+
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/monitoring/LogConstants.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/monitoring/LogConstants.java
new file mode 100644
index 000000000..d60ac0183
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/monitoring/LogConstants.java
@@ -0,0 +1,104 @@
+package com.netflix.metacat.common.monitoring;
+
+/**
+ * Created by amajumdar on 11/4/14.
+ */
+public enum LogConstants {
+ /*
+ General logging constants
+ */
+ GlobalPrefix("dse"),
+ AppPrefix(GlobalPrefix + ".metacat"),
+ /*
+ Counters
+ */
+ CounterCreateCatalog(AppPrefix+".countCreateCatalog"),
+ CounterCreateTable(AppPrefix+".countCreateTable"),
+ CounterCreateDatabase(AppPrefix + ".countCreateDatabase"),
+ CounterCreateMView(AppPrefix + ".countCreateMView"),
+ CounterDeleteDatabase(AppPrefix + ".countDeleteDatabase"),
+ CounterDeleteTablePartitions(AppPrefix + ".countDeleteTablePartitions"),
+ CounterDeleteMViewPartitions(AppPrefix + ".countDeleteMViewPartitions"),
+ CounterDeleteTable(AppPrefix + ".countDropTable"),
+ CounterDeleteMView(AppPrefix + ".countDeleteMView"),
+ CounterGetCatalog(AppPrefix+".countGetMetadata"),
+ CounterGetCatalogNames(AppPrefix+".countGetCatalogNames"),
+ CounterGetDatabase(AppPrefix+".countGetDatabase"),
+ CounterGetMViewPartitions(AppPrefix+".countGetMViewPartitions"),
+ CounterGetTablePartitions(AppPrefix+".countGetTablePartitions"),
+ CounterGetTable(AppPrefix+".countGetTable"),
+ CounterGetMView(AppPrefix+".countGetMView"),
+ CounterGetCatalogMViews(AppPrefix+".countGetCatalogMViews"),
+ CounterGetTableMViews(AppPrefix+".countGetTableMViews"),
+ CounterRenameTable(AppPrefix+".countRenameTable"),
+ CounterUpdateCatalog(AppPrefix+".countUpdateCatalog"),
+ CounterUpdateTable(AppPrefix+".countUpdateTable"),
+ CounterSaveTablePartitions(AppPrefix+".countSaveTablePartitions"),
+ CounterSaveMViewPartitions(AppPrefix+".countSaveMViewPartitions"),
+ CounterCreateCatalogFailure(AppPrefix+".countCreateCatalogFailure"),
+ CounterCreateTableFailure(AppPrefix+".countCreateTableFailure"),
+ CounterCreateDatabaseFailure(AppPrefix + ".countCreateDatabaseFailure"),
+ CounterCreateMViewFailure(AppPrefix + ".countCreateMViewFailure"),
+ CounterDeleteDatabaseFailure(AppPrefix + ".countDeleteDatabaseFailure"),
+ CounterDeleteTablePartitionsFailure(AppPrefix + ".countDeleteTablePartitionsFailure"),
+ CounterDeleteMViewPartitionsFailure(AppPrefix + ".countDeleteMViewPartitionsFailure"),
+ CounterDeleteTableFailure(AppPrefix + ".countDropTableFailure"),
+ CounterDeleteMViewFailure(AppPrefix + ".countDeleteMViewFailure"),
+ CounterGetCatalogFailure(AppPrefix+".countGetMetadataFailure"),
+ CounterGetCatalogNamesFailure(AppPrefix+".countGetCatalogNamesFailure"),
+ CounterGetDatabaseFailure(AppPrefix+".countGetDatabaseFailure"),
+ CounterGetMViewPartitionsFailure(AppPrefix+".countGetMViewPartitionsFailure"),
+ CounterGetTablePartitionsFailure(AppPrefix+".countGetTablePartitionsFailure"),
+ CounterGetTableFailure(AppPrefix+".countGetTableFailure"),
+ CounterGetMViewFailure(AppPrefix+".countGetMViewFailure"),
+ CounterGetCatalogMViewsFailure(AppPrefix+".countGetCatalogMViewsFailure"),
+ CounterGetTableMViewsFailure(AppPrefix+".countGetTableMViewsFailure"),
+ CounterRenameTableFailure(AppPrefix+".countRenameTableFailure"),
+ CounterUpdateCatalogFailure(AppPrefix+".countUpdateCatalogFailure"),
+ CounterUpdateTableFailure(AppPrefix+".countUpdateTableFailure"),
+ CounterSaveTablePartitionsFailure(AppPrefix+".countSaveTablePartitionsFailure"),
+ CounterSaveMViewPartitionsFailure(AppPrefix+".countSaveMViewPartitionsFailure"),
+ /*
+ Tracers
+ */
+ TracerCreateCatalog(AppPrefix+".traceCreateCatalog"),
+ TracerCreateTable(AppPrefix+".traceCreateTable"),
+ TracerCreateDatabase(AppPrefix + ".traceCreateDatabase"),
+ TracerCreateMView(AppPrefix + ".traceCreateMView"),
+ TracerDeleteDatabase(AppPrefix + ".traceDeleteDatabase"),
+ TracerDeleteTablePartitions(AppPrefix + ".traceDeleteTablePartitions"),
+ TracerDeleteMViewPartitions(AppPrefix + ".traceDeleteMViewPartitions"),
+ TracerDeleteTable(AppPrefix + ".traceDropTable"),
+ TracerDeleteMView(AppPrefix + ".traceDeleteMView"),
+ TracerGetCatalog(AppPrefix+".traceGetMetadata"),
+ TracerGetCatalogNames(AppPrefix+".traceGetCatalogNames"),
+ TracerGetDatabase(AppPrefix+".traceGetDatabase"),
+ TracerGetMViewPartitions(AppPrefix+".traceGetMViewPartitions"),
+ TracerGetTablePartitions(AppPrefix+".traceGetTablePartitions"),
+ TracerGetTable(AppPrefix+".traceGetTable"),
+ TracerGetMView(AppPrefix+".traceGetMView"),
+ TracerGetCatalogMViews(AppPrefix+".traceGetCatalogMViews"),
+ TracerGetTableMViews(AppPrefix+".traceGetTableMViews"),
+ TracerRenameTable(AppPrefix+".traceRenameTable"),
+ TracerUpdateCatalog(AppPrefix+".traceUpdateCatalog"),
+ TracerUpdateTable(AppPrefix+".traceUpdateTable"),
+ TracerSaveTablePartitions(AppPrefix+".traceSaveTablePartitions"),
+ TracerSaveMViewPartitions(AppPrefix+".traceSaveMViewPartitions"),
+ /*
+ Gauges
+ */
+ GaugeAddPartitions(AppPrefix+".gaugeAddPartitions"),
+ GaugeDeletePartitions(AppPrefix+".gaugeDeletePartitions"),
+ GaugeGetPartitionsCount(AppPrefix+".gaugeGetPartitionsCount");
+
+ private final String constant;
+
+ LogConstants(String constant) {
+ this.constant = constant;
+ }
+
+ @Override
+ public String toString() {
+ return constant;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/monitoring/TimerWrapper.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/monitoring/TimerWrapper.java
new file mode 100644
index 000000000..b2153b3ee
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/monitoring/TimerWrapper.java
@@ -0,0 +1,131 @@
+package com.netflix.metacat.common.monitoring;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.netflix.servo.DefaultMonitorRegistry;
+import com.netflix.servo.monitor.MonitorConfig;
+import com.netflix.servo.monitor.Monitors;
+import com.netflix.servo.monitor.Stopwatch;
+import com.netflix.servo.monitor.Timer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nonnull;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Servo Timer wrapper
+ *
+ * @author amajumdar
+ */
+public class TimerWrapper {
+ private static final Stopwatch NULL_STOPWATCH = new Stopwatch() {
+ @Override
+ public long getDuration(TimeUnit timeUnit) {
+ return 0;
+ }
+
+ @Override
+ public long getDuration() {
+ return 0;
+ }
+
+ @Override
+ public void reset() {
+ }
+
+ @Override
+ public void start() {
+ }
+
+ @Override
+ public void stop() {
+ }
+ };
+ private static final Timer NULL_TIMER = new Timer() {
+ @Override
+ public MonitorConfig getConfig() {
+ return null;
+ }
+
+ @Override
+ public TimeUnit getTimeUnit() {
+ return null;
+ }
+
+ @Override
+ public Long getValue(int pollerIndex) {
+ return null;
+ }
+
+ @Override
+ public Long getValue() {
+ return null;
+ }
+
+ @Override
+ public void record(long duration, TimeUnit timeUnit) {
+
+ }
+
+ @Override
+ public void record(long duration) {
+
+ }
+
+ @Override
+ public Stopwatch start() {
+ return NULL_STOPWATCH;
+ }
+ };
+ private static final LoadingCache TIMERS = CacheBuilder.newBuilder()
+ .build(
+ new CacheLoader() {
+ public Timer load(@Nonnull String timerName) {
+ Timer timer = Monitors.newTimer(timerName);
+ DefaultMonitorRegistry.getInstance().register(timer);
+ return timer;
+ }
+ });
+ private static final Logger log = LoggerFactory.getLogger(TimerWrapper.class);
+ private final String name;
+ private final Timer timer;
+ private Stopwatch stopwatch;
+
+ private TimerWrapper(String name) {
+ this.name = name;
+ Timer t = NULL_TIMER;
+ try {
+ t = TIMERS.get(name);
+ } catch (ExecutionException ex) {
+ log.warn("Error fetching timer: {}", name, ex);
+ }
+ this.timer = t;
+ }
+
+ public static TimerWrapper createStarted(String name) {
+ TimerWrapper wrapper = new TimerWrapper(name);
+ wrapper.start();
+ return wrapper;
+ }
+
+ public static TimerWrapper createStopped(String name) {
+ return new TimerWrapper(name);
+ }
+
+ public void start() {
+ stopwatch = timer.start();
+ }
+
+ public long stop() {
+ stopwatch.stop();
+ return stopwatch.getDuration(TimeUnit.MILLISECONDS);
+ }
+
+ @Override
+ public String toString() {
+ return "Timer{" + name + " - " + stopwatch.getDuration(TimeUnit.MILLISECONDS) + "ms}";
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTAND.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTAND.java
new file mode 100644
index 000000000..d037136fd
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTAND.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTAND.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTAND extends SimpleNode {
+ public ASTAND(int id) {
+ super(id);
+ }
+
+ public ASTAND(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=47624dd380cfe00f384e5c8af03d69b3 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTEQ.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTEQ.java
new file mode 100644
index 000000000..21285dd50
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTEQ.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTEQ.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTEQ extends SimpleNode {
+ public ASTEQ(int id) {
+ super(id);
+ }
+
+ public ASTEQ(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=bbf13f81c94ea7197914ce9f46cc3526 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTEVAL.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTEVAL.java
new file mode 100644
index 000000000..db6eac3d6
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTEVAL.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTEVAL.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTEVAL extends SimpleNode {
+ public ASTEVAL(int id) {
+ super(id);
+ }
+
+ public ASTEVAL(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=44c4f3e64c75fbaff63b52dea370f72e (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTFILTER.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTFILTER.java
new file mode 100644
index 000000000..c64814026
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTFILTER.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTFILTER.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTFILTER extends SimpleNode {
+ public ASTFILTER(int id) {
+ super(id);
+ }
+
+ public ASTFILTER(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=502a3e691142a2ee92a5d005f0a1bb28 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTGT.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTGT.java
new file mode 100644
index 000000000..01bdcc422
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTGT.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTGT.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTGT extends SimpleNode {
+ public ASTGT(int id) {
+ super(id);
+ }
+
+ public ASTGT(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=97fa861ee8d9421ccb94612e513bc388 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTGTE.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTGTE.java
new file mode 100644
index 000000000..21e9c32dc
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTGTE.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTGTE.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTGTE extends SimpleNode {
+ public ASTGTE(int id) {
+ super(id);
+ }
+
+ public ASTGTE(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=64550e3fbfe981b802deef725b683e1a (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTLIKE.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTLIKE.java
new file mode 100644
index 000000000..9bf81a777
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTLIKE.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTLIKE.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTLIKE extends SimpleNode {
+ public ASTLIKE(int id) {
+ super(id);
+ }
+
+ public ASTLIKE(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=4c9049dc18265f1076e67d7fbab0250d (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTLT.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTLT.java
new file mode 100644
index 000000000..714f579fd
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTLT.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTLT.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTLT extends SimpleNode {
+ public ASTLT(int id) {
+ super(id);
+ }
+
+ public ASTLT(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=32e29fc080692c40e10bb780be9e3e00 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTLTE.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTLTE.java
new file mode 100644
index 000000000..4e2e6f009
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTLTE.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTLTE.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTLTE extends SimpleNode {
+ public ASTLTE(int id) {
+ super(id);
+ }
+
+ public ASTLTE(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=5166b2cf4d389162d081829f20e53bb9 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTMATCHES.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTMATCHES.java
new file mode 100644
index 000000000..6fe9d4569
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTMATCHES.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTMATCHES.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTMATCHES extends SimpleNode {
+ public ASTMATCHES(int id) {
+ super(id);
+ }
+
+ public ASTMATCHES(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=db244b83ab6cf6833b7dbd96aea93a2c (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTNEQ.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTNEQ.java
new file mode 100644
index 000000000..32ee4de42
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTNEQ.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTNEQ.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTNEQ extends SimpleNode {
+ public ASTNEQ(int id) {
+ super(id);
+ }
+
+ public ASTNEQ(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=4ed9b560c660a3074aeba567abf5c70b (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTNEVAL.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTNEVAL.java
new file mode 100644
index 000000000..3d0dce047
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTNEVAL.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTNEVAL.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTNEVAL extends SimpleNode {
+ public ASTNEVAL(int id) {
+ super(id);
+ }
+
+ public ASTNEVAL(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=751b8701055f6f9fe23ea83e1e531f14 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTNUM.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTNUM.java
new file mode 100644
index 000000000..b04091629
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTNUM.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTNUM.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTNUM extends SimpleNode {
+ public ASTNUM(int id) {
+ super(id);
+ }
+
+ public ASTNUM(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=8c978f5115fa4de48e54d30148a58bf1 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTOR.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTOR.java
new file mode 100644
index 000000000..897218c7c
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTOR.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTOR.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTOR extends SimpleNode {
+ public ASTOR(int id) {
+ super(id);
+ }
+
+ public ASTOR(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=b1f74c0c73a8c4b265e886c9e24da36a (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTSTRING.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTSTRING.java
new file mode 100644
index 000000000..1226c7710
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTSTRING.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTSTRING.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTSTRING extends SimpleNode {
+ public ASTSTRING(int id) {
+ super(id);
+ }
+
+ public ASTSTRING(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=8d75dfe50ee57545277a64f4f0a63221 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTVAR.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTVAR.java
new file mode 100644
index 000000000..c61b52199
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ASTVAR.java
@@ -0,0 +1,23 @@
+/* Generated By:JJTree: Do not edit this line. ASTVAR.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class ASTVAR extends SimpleNode {
+ public ASTVAR(int id) {
+ super(id);
+ }
+
+ public ASTVAR(PartitionParser p, int id) {
+ super(p, id);
+ }
+
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data) {
+
+ return
+ visitor.visit(this, data);
+ }
+}
+/* JavaCC - OriginalChecksum=69622d5c2212551b77e16c4e9145bc5c (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/JJTPartitionParserState.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/JJTPartitionParserState.java
new file mode 100644
index 000000000..aaacd8765
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/JJTPartitionParserState.java
@@ -0,0 +1,123 @@
+/* Generated By:JavaCC: Do not edit this line. JJTPartitionParserState.java Version 6.1_2 */
+package com.netflix.metacat.common.partition.parser;
+
+public class JJTPartitionParserState {
+ private java.util.List nodes;
+ private java.util.List marks;
+
+ private int sp; // number of nodes on stack
+ private int mk; // current mark
+ private boolean node_created;
+
+ public JJTPartitionParserState() {
+ nodes = new java.util.ArrayList();
+ marks = new java.util.ArrayList();
+ sp = 0;
+ mk = 0;
+ }
+
+ /* Determines whether the current node was actually closed and
+ pushed. This should only be called in the final user action of a
+ node scope. */
+ public boolean nodeCreated() {
+ return node_created;
+ }
+
+ /* Call this to reinitialize the node stack. It is called
+ automatically by the parser's ReInit() method. */
+ public void reset() {
+ nodes.clear();
+ marks.clear();
+ sp = 0;
+ mk = 0;
+ }
+
+ /* Returns the root node of the AST. It only makes sense to call
+ this after a successful parse. */
+ public Node rootNode() {
+ return nodes.get(0);
+ }
+
+ /* Pushes a node on to the stack. */
+ public void pushNode(Node n) {
+ nodes.add(n);
+ ++sp;
+ }
+
+ /* Returns the node on the top of the stack, and remove it from the
+ stack. */
+ public Node popNode() {
+ if (--sp < mk) {
+ mk = marks.remove(marks.size()-1);
+ }
+ return nodes.remove(nodes.size()-1);
+ }
+
+ /* Returns the node currently on the top of the stack. */
+ public Node peekNode() {
+ return nodes.get(nodes.size()-1);
+ }
+
+ /* Returns the number of children on the stack in the current node
+ scope. */
+ public int nodeArity() {
+ return sp - mk;
+ }
+
+
+ public void clearNodeScope(Node n) {
+ while (sp > mk) {
+ popNode();
+ }
+ mk = marks.remove(marks.size()-1);
+ }
+
+
+ public void openNodeScope(Node n) {
+ marks.add(mk);
+ mk = sp;
+ n.jjtOpen();
+ }
+
+
+ /* A definite node is constructed from a specified number of
+ children. That number of nodes are popped from the stack and
+ made the children of the definite node. Then the definite node
+ is pushed on to the stack. */
+ public void closeNodeScope(Node n, int num) {
+ mk = marks.remove(marks.size()-1);
+ while (num-- > 0) {
+ Node c = popNode();
+ c.jjtSetParent(n);
+ n.jjtAddChild(c, num);
+ }
+ n.jjtClose();
+ pushNode(n);
+ node_created = true;
+ }
+
+
+ /* A conditional node is constructed if its condition is true. All
+ the nodes that have been pushed since the node was opened are
+ made children of the conditional node, which is then pushed
+ on to the stack. If the condition is false the node is not
+ constructed and they are left on the stack. */
+ public void closeNodeScope(Node n, boolean condition) {
+ if (condition) {
+ int a = nodeArity();
+ mk = marks.remove(marks.size()-1);
+ while (a-- > 0) {
+ Node c = popNode();
+ c.jjtSetParent(n);
+ n.jjtAddChild(c, a);
+ }
+ n.jjtClose();
+ pushNode(n);
+ node_created = true;
+ } else {
+ mk = marks.remove(marks.size()-1);
+ node_created = false;
+ }
+ }
+}
+/* JavaCC - OriginalChecksum=15653e080246fc9384199e756e610179 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/Node.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/Node.java
new file mode 100644
index 000000000..770a00ce0
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/Node.java
@@ -0,0 +1,41 @@
+/* Generated By:JJTree: Do not edit this line. Node.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+/* All AST nodes must implement this interface. It provides basic
+ machinery for constructing the parent and child relationships
+ between nodes. */
+
+public
+interface Node {
+
+ /** This method is called after the node has been made the current
+ node. It indicates that child nodes can now be added to it. */
+ public void jjtOpen();
+
+ /** This method is called after all the child nodes have been
+ added. */
+ public void jjtClose();
+
+ /** This pair of methods are used to inform the node of its
+ parent. */
+ public void jjtSetParent(Node n);
+ public Node jjtGetParent();
+
+ /** This method tells the node to add its argument to the node's
+ list of children. */
+ public void jjtAddChild(Node n, int i);
+
+ /** This method returns a child node. The children are numbered
+ from zero, left to right. */
+ public Node jjtGetChild(int i);
+
+ /** Return the number of children the node has. */
+ public int jjtGetNumChildren();
+
+ public int getId();
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data);
+}
+/* JavaCC - OriginalChecksum=334ed1ebebd1735ac4fc4c275c58338c (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ParseException.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ParseException.java
new file mode 100644
index 000000000..97af41160
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/ParseException.java
@@ -0,0 +1,193 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 6.1 */
+/* JavaCCOptions:KEEP_LINE_COLUMN=true */
+package com.netflix.metacat.common.partition.parser;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * You can modify this class to customize your error reporting
+ * mechanisms so long as you retain the public fields.
+ */
+public class ParseException extends Exception {
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The end of line string for this machine.
+ */
+ protected static String EOL = System.getProperty("line.separator", "\n");
+
+ /**
+ * This constructor is used by the method "generateParseException"
+ * in the generated parser. Calling this constructor generates
+ * a new object of this type with the fields "currentToken",
+ * "expectedTokenSequences", and "tokenImage" set.
+ */
+ public ParseException(Token currentTokenVal,
+ int[][] expectedTokenSequencesVal,
+ String[] tokenImageVal
+ )
+ {
+ super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal));
+ currentToken = currentTokenVal;
+ expectedTokenSequences = expectedTokenSequencesVal;
+ tokenImage = tokenImageVal;
+ }
+
+ /**
+ * The following constructors are for use by you for whatever
+ * purpose you can think of. Constructing the exception in this
+ * manner makes the exception behave in the normal way - i.e., as
+ * documented in the class "Throwable". The fields "errorToken",
+ * "expectedTokenSequences", and "tokenImage" do not contain
+ * relevant information. The JavaCC generated code does not use
+ * these constructors.
+ */
+
+ public ParseException() {
+ super();
+ }
+
+ /** Constructor with message. */
+ public ParseException(String message) {
+ super(message);
+ }
+
+
+ /**
+ * This is the last token that has been consumed successfully. If
+ * this object has been created due to a parse error, the token
+ * followng this token will (therefore) be the first error token.
+ */
+ public Token currentToken;
+
+ /**
+ * Each entry in this array is an array of integers. Each array
+ * of integers represents a sequence of tokens (by their ordinal
+ * values) that is expected at this point of the parse.
+ */
+ public int[][] expectedTokenSequences;
+
+ /**
+ * This is a reference to the "tokenImage" array of the generated
+ * parser within which the parse error occurred. This array is
+ * defined in the generated ...Constants interface.
+ */
+ public String[] tokenImage;
+
+ /**
+ * It uses "currentToken" and "expectedTokenSequences" to generate a parse
+ * error message and returns it. If this object has been created
+ * due to a parse error, and you do not catch it (it gets thrown
+ * from the parser) the correct error message
+ * gets displayed.
+ */
+ private static String initialise(Token currentToken,
+ int[][] expectedTokenSequences,
+ String[] tokenImage) {
+
+ StringBuffer expected = new StringBuffer();
+ int maxSize = 0;
+ for (int i = 0; i < expectedTokenSequences.length; i++) {
+ if (maxSize < expectedTokenSequences[i].length) {
+ maxSize = expectedTokenSequences[i].length;
+ }
+ for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+ expected.append(tokenImage[expectedTokenSequences[i][j]]).append(' ');
+ }
+ if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+ expected.append("...");
+ }
+ expected.append(EOL).append(" ");
+ }
+ String retval = "Encountered \"";
+ Token tok = currentToken.next;
+ for (int i = 0; i < maxSize; i++) {
+ if (i != 0) retval += " ";
+ if (tok.kind == 0) {
+ retval += tokenImage[0];
+ break;
+ }
+ retval += " " + tokenImage[tok.kind];
+ retval += " \"";
+ retval += add_escapes(tok.image);
+ retval += " \"";
+ tok = tok.next;
+ }
+ retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+ retval += "." + EOL;
+
+
+ if (expectedTokenSequences.length == 0) {
+ // Nothing to add here
+ } else {
+ if (expectedTokenSequences.length == 1) {
+ retval += "Was expecting:" + EOL + " ";
+ } else {
+ retval += "Was expecting one of:" + EOL + " ";
+ }
+ retval += expected.toString();
+ }
+
+ return retval;
+ }
+
+
+ /**
+ * Used to convert raw characters to their escaped version
+ * when these raw version cannot be used as part of an ASCII
+ * string literal.
+ */
+ static String add_escapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0; i < str.length(); i++) {
+ switch (str.charAt(i))
+ {
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ case '\"':
+ retval.append("\\\"");
+ continue;
+ case '\'':
+ retval.append("\\\'");
+ continue;
+ case '\\':
+ retval.append("\\\\");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
+ }
+ }
+ return retval.toString();
+ }
+
+}
+/* JavaCC - OriginalChecksum=ebf7c49bc9f512da02492cb828cad7f5 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParser.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParser.java
new file mode 100644
index 000000000..b34b18ad4
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParser.java
@@ -0,0 +1,752 @@
+/* PartitionParser.java */
+/* Generated By:JJTree&JavaCC: Do not edit this line. PartitionParser.java */
+package com.netflix.metacat.common.partition.parser;
+public class PartitionParser/*@bgen(jjtree)*/implements PartitionParserTreeConstants, PartitionParserConstants {/*@bgen(jjtree)*/
+ protected JJTPartitionParserState jjtree = new JJTPartitionParserState();public static void main (String args []) throws ParseException {
+ PartitionParser parser = new PartitionParser(new java.io.StringReader(args[0]));
+ SimpleNode root = parser.filter();
+ root.dump("");
+ System.out.println(root.jjtAccept(new com.netflix.metacat.common.partition.visitor.PartitionParserEval(), null));
+ }
+
+ final public SimpleNode filter() throws ParseException {/*@bgen(jjtree) FILTER */
+ ASTFILTER jjtn000 = new ASTFILTER(JJTFILTER);
+ boolean jjtc000 = true;
+ jjtree.openNodeScope(jjtn000);
+ try {
+ expr();
+jjtree.closeNodeScope(jjtn000, true);
+ jjtc000 = false;
+{if ("" != null) return jjtn000;}
+ } catch (Throwable jjte000) {
+if (jjtc000) {
+ jjtree.clearNodeScope(jjtn000);
+ jjtc000 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte000 instanceof RuntimeException) {
+ {if (true) throw (RuntimeException)jjte000;}
+ }
+ if (jjte000 instanceof ParseException) {
+ {if (true) throw (ParseException)jjte000;}
+ }
+ {if (true) throw (Error)jjte000;}
+ } finally {
+if (jjtc000) {
+ jjtree.closeNodeScope(jjtn000, true);
+ }
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+ final public void expr() throws ParseException {
+ switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+ case LPAREN:{
+ jj_consume_token(LPAREN);
+ expr();
+ jj_consume_token(RPAREN);
+ switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+ case AND:
+ case OR:{
+ switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+ case AND:{
+ jj_consume_token(AND);
+ASTAND jjtn001 = new ASTAND(JJTAND);
+ boolean jjtc001 = true;
+ jjtree.openNodeScope(jjtn001);
+ try {
+ expr();
+ } catch (Throwable jjte001) {
+if (jjtc001) {
+ jjtree.clearNodeScope(jjtn001);
+ jjtc001 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte001 instanceof RuntimeException) {
+ {if (true) throw (RuntimeException)jjte001;}
+ }
+ if (jjte001 instanceof ParseException) {
+ {if (true) throw (ParseException)jjte001;}
+ }
+ {if (true) throw (Error)jjte001;}
+ } finally {
+if (jjtc001) {
+ jjtree.closeNodeScope(jjtn001, 2);
+ }
+ }
+ break;
+ }
+ case OR:{
+ jj_consume_token(OR);
+ASTOR jjtn002 = new ASTOR(JJTOR);
+ boolean jjtc002 = true;
+ jjtree.openNodeScope(jjtn002);
+ try {
+ expr();
+ } catch (Throwable jjte002) {
+if (jjtc002) {
+ jjtree.clearNodeScope(jjtn002);
+ jjtc002 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte002 instanceof RuntimeException) {
+ {if (true) throw (RuntimeException)jjte002;}
+ }
+ if (jjte002 instanceof ParseException) {
+ {if (true) throw (ParseException)jjte002;}
+ }
+ {if (true) throw (Error)jjte002;}
+ } finally {
+if (jjtc002) {
+ jjtree.closeNodeScope(jjtn002, 2);
+ }
+ }
+ break;
+ }
+ default:
+ jj_la1[0] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ break;
+ }
+ default:
+ jj_la1[1] = jj_gen;
+ ;
+ }
+ break;
+ }
+ case NOT:{
+ neval();
+ switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+ case AND:
+ case OR:{
+ switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+ case AND:{
+ jj_consume_token(AND);
+ASTAND jjtn003 = new ASTAND(JJTAND);
+ boolean jjtc003 = true;
+ jjtree.openNodeScope(jjtn003);
+ try {
+ expr();
+ } catch (Throwable jjte003) {
+if (jjtc003) {
+ jjtree.clearNodeScope(jjtn003);
+ jjtc003 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte003 instanceof RuntimeException) {
+ {if (true) throw (RuntimeException)jjte003;}
+ }
+ if (jjte003 instanceof ParseException) {
+ {if (true) throw (ParseException)jjte003;}
+ }
+ {if (true) throw (Error)jjte003;}
+ } finally {
+if (jjtc003) {
+ jjtree.closeNodeScope(jjtn003, 2);
+ }
+ }
+ break;
+ }
+ case OR:{
+ jj_consume_token(OR);
+ASTOR jjtn004 = new ASTOR(JJTOR);
+ boolean jjtc004 = true;
+ jjtree.openNodeScope(jjtn004);
+ try {
+ expr();
+ } catch (Throwable jjte004) {
+if (jjtc004) {
+ jjtree.clearNodeScope(jjtn004);
+ jjtc004 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte004 instanceof RuntimeException) {
+ {if (true) throw (RuntimeException)jjte004;}
+ }
+ if (jjte004 instanceof ParseException) {
+ {if (true) throw (ParseException)jjte004;}
+ }
+ {if (true) throw (Error)jjte004;}
+ } finally {
+if (jjtc004) {
+ jjtree.closeNodeScope(jjtn004, 2);
+ }
+ }
+ break;
+ }
+ default:
+ jj_la1[2] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ break;
+ }
+ default:
+ jj_la1[3] = jj_gen;
+ ;
+ }
+ break;
+ }
+ case INT:
+ case FLOAT:
+ case VARIABLE:
+ case QUOTE:
+ case SQUOTE:{
+ eval();
+ switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+ case AND:
+ case OR:{
+ switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+ case AND:{
+ jj_consume_token(AND);
+ASTAND jjtn005 = new ASTAND(JJTAND);
+ boolean jjtc005 = true;
+ jjtree.openNodeScope(jjtn005);
+ try {
+ expr();
+ } catch (Throwable jjte005) {
+if (jjtc005) {
+ jjtree.clearNodeScope(jjtn005);
+ jjtc005 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte005 instanceof RuntimeException) {
+ {if (true) throw (RuntimeException)jjte005;}
+ }
+ if (jjte005 instanceof ParseException) {
+ {if (true) throw (ParseException)jjte005;}
+ }
+ {if (true) throw (Error)jjte005;}
+ } finally {
+if (jjtc005) {
+ jjtree.closeNodeScope(jjtn005, 2);
+ }
+ }
+ break;
+ }
+ case OR:{
+ jj_consume_token(OR);
+ASTOR jjtn006 = new ASTOR(JJTOR);
+ boolean jjtc006 = true;
+ jjtree.openNodeScope(jjtn006);
+ try {
+ expr();
+ } catch (Throwable jjte006) {
+if (jjtc006) {
+ jjtree.clearNodeScope(jjtn006);
+ jjtc006 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte006 instanceof RuntimeException) {
+ {if (true) throw (RuntimeException)jjte006;}
+ }
+ if (jjte006 instanceof ParseException) {
+ {if (true) throw (ParseException)jjte006;}
+ }
+ {if (true) throw (Error)jjte006;}
+ } finally {
+if (jjtc006) {
+ jjtree.closeNodeScope(jjtn006, 2);
+ }
+ }
+ break;
+ }
+ default:
+ jj_la1[4] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ break;
+ }
+ default:
+ jj_la1[5] = jj_gen;
+ ;
+ }
+ break;
+ }
+ default:
+ jj_la1[6] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+
+ final public void neval() throws ParseException {/*@bgen(jjtree) NEVAL */
+ ASTNEVAL jjtn000 = new ASTNEVAL(JJTNEVAL);
+ boolean jjtc000 = true;
+ jjtree.openNodeScope(jjtn000);
+ try {
+ jj_consume_token(NOT);
+ eval();
+ } catch (Throwable jjte000) {
+if (jjtc000) {
+ jjtree.clearNodeScope(jjtn000);
+ jjtc000 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte000 instanceof RuntimeException) {
+ {if (true) throw (RuntimeException)jjte000;}
+ }
+ if (jjte000 instanceof ParseException) {
+ {if (true) throw (ParseException)jjte000;}
+ }
+ {if (true) throw (Error)jjte000;}
+ } finally {
+if (jjtc000) {
+ jjtree.closeNodeScope(jjtn000, true);
+ }
+ }
+ }
+
+ final public void eval() throws ParseException {/*@bgen(jjtree) EVAL */
+ ASTEVAL jjtn000 = new ASTEVAL(JJTEVAL);
+ boolean jjtc000 = true;
+ jjtree.openNodeScope(jjtn000);
+ try {
+ term();
+ comp();
+ term();
+ } catch (Throwable jjte000) {
+if (jjtc000) {
+ jjtree.clearNodeScope(jjtn000);
+ jjtc000 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte000 instanceof RuntimeException) {
+ {if (true) throw (RuntimeException)jjte000;}
+ }
+ if (jjte000 instanceof ParseException) {
+ {if (true) throw (ParseException)jjte000;}
+ }
+ {if (true) throw (Error)jjte000;}
+ } finally {
+if (jjtc000) {
+ jjtree.closeNodeScope(jjtn000, true);
+ }
+ }
+ }
+
+ final public void comp() throws ParseException {
+ switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+ case GT:{
+ASTGT jjtn001 = new ASTGT(JJTGT);
+ boolean jjtc001 = true;
+ jjtree.openNodeScope(jjtn001);
+ try {
+ jj_consume_token(GT);
+ } finally {
+if (jjtc001) {
+ jjtree.closeNodeScope(jjtn001, true);
+ }
+ }
+ break;
+ }
+ case LT:{
+ASTLT jjtn002 = new ASTLT(JJTLT);
+ boolean jjtc002 = true;
+ jjtree.openNodeScope(jjtn002);
+ try {
+ jj_consume_token(LT);
+ } finally {
+if (jjtc002) {
+ jjtree.closeNodeScope(jjtn002, true);
+ }
+ }
+ break;
+ }
+ case LTE:{
+ASTLTE jjtn003 = new ASTLTE(JJTLTE);
+ boolean jjtc003 = true;
+ jjtree.openNodeScope(jjtn003);
+ try {
+ jj_consume_token(LTE);
+ } finally {
+if (jjtc003) {
+ jjtree.closeNodeScope(jjtn003, true);
+ }
+ }
+ break;
+ }
+ case GTE:{
+ASTGTE jjtn004 = new ASTGTE(JJTGTE);
+ boolean jjtc004 = true;
+ jjtree.openNodeScope(jjtn004);
+ try {
+ jj_consume_token(GTE);
+ } finally {
+if (jjtc004) {
+ jjtree.closeNodeScope(jjtn004, true);
+ }
+ }
+ break;
+ }
+ case EQUAL:{
+ASTEQ jjtn005 = new ASTEQ(JJTEQ);
+ boolean jjtc005 = true;
+ jjtree.openNodeScope(jjtn005);
+ try {
+ jj_consume_token(EQUAL);
+ } finally {
+if (jjtc005) {
+ jjtree.closeNodeScope(jjtn005, true);
+ }
+ }
+ break;
+ }
+ case NEQUAL:{
+ASTNEQ jjtn006 = new ASTNEQ(JJTNEQ);
+ boolean jjtc006 = true;
+ jjtree.openNodeScope(jjtn006);
+ try {
+ jj_consume_token(NEQUAL);
+ } finally {
+if (jjtc006) {
+ jjtree.closeNodeScope(jjtn006, true);
+ }
+ }
+ break;
+ }
+ case MATCHES:{
+ASTMATCHES jjtn007 = new ASTMATCHES(JJTMATCHES);
+ boolean jjtc007 = true;
+ jjtree.openNodeScope(jjtn007);
+ try {
+ jj_consume_token(MATCHES);
+ } finally {
+if (jjtc007) {
+ jjtree.closeNodeScope(jjtn007, true);
+ }
+ }
+ break;
+ }
+ case LIKE:{
+ASTLIKE jjtn008 = new ASTLIKE(JJTLIKE);
+ boolean jjtc008 = true;
+ jjtree.openNodeScope(jjtn008);
+ try {
+ jj_consume_token(LIKE);
+ } finally {
+if (jjtc008) {
+ jjtree.closeNodeScope(jjtn008, true);
+ }
+ }
+ break;
+ }
+ default:
+ jj_la1[7] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+
+ final public void term() throws ParseException {Token t;
+ StringBuilder builder = new StringBuilder();
+ switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+ case INT:{
+ t = jj_consume_token(INT);
+ASTNUM jjtn001 = new ASTNUM(JJTNUM);
+ boolean jjtc001 = true;
+ jjtree.openNodeScope(jjtn001);
+ try {
+jjtree.closeNodeScope(jjtn001, true);
+ jjtc001 = false;
+jjtn001.value = new java.math.BigDecimal(t.image);
+ } finally {
+if (jjtc001) {
+ jjtree.closeNodeScope(jjtn001, true);
+ }
+ }
+ break;
+ }
+ case FLOAT:{
+ t = jj_consume_token(FLOAT);
+ASTNUM jjtn002 = new ASTNUM(JJTNUM);
+ boolean jjtc002 = true;
+ jjtree.openNodeScope(jjtn002);
+ try {
+jjtree.closeNodeScope(jjtn002, true);
+ jjtc002 = false;
+jjtn002.value = new java.math.BigDecimal(t.image);
+ } finally {
+if (jjtc002) {
+ jjtree.closeNodeScope(jjtn002, true);
+ }
+ }
+ break;
+ }
+ case QUOTE:{
+ jj_consume_token(QUOTE);
+ label_1:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+ case CHAR:{
+ ;
+ break;
+ }
+ default:
+ jj_la1[8] = jj_gen;
+ break label_1;
+ }
+ t = jj_consume_token(CHAR);
+builder.append(t.image);
+ }
+ jj_consume_token(ENDQUOTE);
+ASTSTRING jjtn003 = new ASTSTRING(JJTSTRING);
+ boolean jjtc003 = true;
+ jjtree.openNodeScope(jjtn003);
+ try {
+jjtree.closeNodeScope(jjtn003, true);
+ jjtc003 = false;
+jjtn003.value = builder.toString();
+ } finally {
+if (jjtc003) {
+ jjtree.closeNodeScope(jjtn003, true);
+ }
+ }
+ break;
+ }
+ case SQUOTE:{
+ jj_consume_token(SQUOTE);
+ label_2:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+ case SCHAR:{
+ ;
+ break;
+ }
+ default:
+ jj_la1[9] = jj_gen;
+ break label_2;
+ }
+ t = jj_consume_token(SCHAR);
+builder.append(t.image);
+ }
+ jj_consume_token(SENDQUOTE);
+ASTSTRING jjtn004 = new ASTSTRING(JJTSTRING);
+ boolean jjtc004 = true;
+ jjtree.openNodeScope(jjtn004);
+ try {
+jjtree.closeNodeScope(jjtn004, true);
+ jjtc004 = false;
+jjtn004.value = builder.toString();
+ } finally {
+if (jjtc004) {
+ jjtree.closeNodeScope(jjtn004, true);
+ }
+ }
+ break;
+ }
+ case VARIABLE:{
+ t = jj_consume_token(VARIABLE);
+ASTVAR jjtn005 = new ASTVAR(JJTVAR);
+ boolean jjtc005 = true;
+ jjtree.openNodeScope(jjtn005);
+ try {
+jjtree.closeNodeScope(jjtn005, true);
+ jjtc005 = false;
+jjtn005.value = new Variable(t.image);
+ } finally {
+if (jjtc005) {
+ jjtree.closeNodeScope(jjtn005, true);
+ }
+ }
+ break;
+ }
+ default:
+ jj_la1[10] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+
+ /** Generated Token Manager. */
+ public PartitionParserTokenManager token_source;
+ SimpleCharStream jj_input_stream;
+ /** Current token. */
+ public Token token;
+ /** Next token. */
+ public Token jj_nt;
+ private int jj_ntk;
+ private int jj_gen;
+ final private int[] jj_la1 = new int[11];
+ static private int[] jj_la1_0;
+ static {
+ jj_la1_init_0();
+ }
+ private static void jj_la1_init_0() {
+ jj_la1_0 = new int[] {0x60000,0x60000,0x60000,0x60000,0x60000,0x60000,0x3482a00,0x3001f8,0x8000000,0x20000000,0x3402800,};
+ }
+
+ /** Constructor with InputStream. */
+ public PartitionParser(java.io.InputStream stream) {
+ this(stream, null);
+ }
+ /** Constructor with InputStream and supplied encoding */
+ public PartitionParser(java.io.InputStream stream, String encoding) {
+ try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+ token_source = new PartitionParserTokenManager(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 11; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream stream) {
+ ReInit(stream, null);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream stream, String encoding) {
+ try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+ token_source.ReInit(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jjtree.reset();
+ jj_gen = 0;
+ for (int i = 0; i < 11; i++) jj_la1[i] = -1;
+ }
+
+ /** Constructor. */
+ public PartitionParser(java.io.Reader stream) {
+ jj_input_stream = new SimpleCharStream(stream, 1, 1);
+ token_source = new PartitionParserTokenManager(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 11; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader stream) {
+ if (jj_input_stream == null) {
+ jj_input_stream = new SimpleCharStream(stream, 1, 1);
+ } else {
+ jj_input_stream.ReInit(stream, 1, 1);
+ }
+ if (token_source == null) {
+ token_source = new PartitionParserTokenManager(jj_input_stream);
+ }
+
+ token_source.ReInit(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jjtree.reset();
+ jj_gen = 0;
+ for (int i = 0; i < 11; i++) jj_la1[i] = -1;
+ }
+
+ /** Constructor with generated Token Manager. */
+ public PartitionParser(PartitionParserTokenManager tm) {
+ token_source = tm;
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 11; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(PartitionParserTokenManager tm) {
+ token_source = tm;
+ token = new Token();
+ jj_ntk = -1;
+ jjtree.reset();
+ jj_gen = 0;
+ for (int i = 0; i < 11; i++) jj_la1[i] = -1;
+ }
+
+ private Token jj_consume_token(int kind) throws ParseException {
+ Token oldToken;
+ if ((oldToken = token).next != null) token = token.next;
+ else token = token.next = token_source.getNextToken();
+ jj_ntk = -1;
+ if (token.kind == kind) {
+ jj_gen++;
+ return token;
+ }
+ token = oldToken;
+ jj_kind = kind;
+ throw generateParseException();
+ }
+
+
+/** Get the next Token. */
+ final public Token getNextToken() {
+ if (token.next != null) token = token.next;
+ else token = token.next = token_source.getNextToken();
+ jj_ntk = -1;
+ jj_gen++;
+ return token;
+ }
+
+/** Get the specific Token. */
+ final public Token getToken(int index) {
+ Token t = token;
+ for (int i = 0; i < index; i++) {
+ if (t.next != null) t = t.next;
+ else t = t.next = token_source.getNextToken();
+ }
+ return t;
+ }
+
+ private int jj_ntk_f() {
+ if ((jj_nt=token.next) == null)
+ return (jj_ntk = (token.next=token_source.getNextToken()).kind);
+ else
+ return (jj_ntk = jj_nt.kind);
+ }
+
+ private java.util.List jj_expentries = new java.util.ArrayList();
+ private int[] jj_expentry;
+ private int jj_kind = -1;
+
+ /** Generate ParseException. */
+ public ParseException generateParseException() {
+ jj_expentries.clear();
+ boolean[] la1tokens = new boolean[30];
+ if (jj_kind >= 0) {
+ la1tokens[jj_kind] = true;
+ jj_kind = -1;
+ }
+ for (int i = 0; i < 11; i++) {
+ if (jj_la1[i] == jj_gen) {
+ for (int j = 0; j < 32; j++) {
+ if ((jj_la1_0[i] & (1<
+| < NEQUAL: "!=" | "<>">
+| < GTE: ">=" >
+| < GT: ">" >
+| < LTE: "<=" >
+| < LT: "<" >
+| < LPAREN : "(">
+| < RPAREN : ")">
+| < INT: ( )+ >
+| < #DIGIT: ["0" - "9"] >
+| < FLOAT: | ( )? >
+| < #EXPONENT: ["e", "E"] ("+"|"-")? >
+| < #MANTISSA: "." ( )* | ( )* "." >
+| < #DIGITS : (["0"-"9"])+ >
+| < AND: "and" | "&&">
+| < OR: "or" | "||">
+| < NOT: "not">
+| < MATCHES: "matches">
+| < LIKE: "like">
+| < VARIABLE : "_" < CHARS > | ["A"-"Z"] < CHARS > | ["a"-"z"] >
+| < #CHARS : (["a"-"z","0"-"9","_","A"-"Z"])+ >
+| < QUOTE:"\"" > : STRING_STATE
+| < SQUOTE:"\'" > : SSTRING_STATE
+}
+ TOKEN:
+{
+ > : DEFAULT
+|
+}
+ TOKEN:
+{
+ > : DEFAULT
+|
+}
+SimpleNode filter() :
+{/*@bgen(jjtree) FILTER */
+ ASTFILTER jjtn000 = new ASTFILTER(JJTFILTER);
+ boolean jjtc000 = true;
+ jjtree.openNodeScope(jjtn000);
+/*@egen*/ }{/*@bgen(jjtree) FILTER */
+ try {
+/*@egen*/
+ expr()/*@bgen(jjtree)*/
+ {
+ jjtree.closeNodeScope(jjtn000, true);
+ jjtc000 = false;
+ }
+/*@egen*/ { return jjtn000; }/*@bgen(jjtree)*/
+ } catch (Throwable jjte000) {
+ if (jjtc000) {
+ jjtree.clearNodeScope(jjtn000);
+ jjtc000 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte000 instanceof RuntimeException) {
+ throw (RuntimeException)jjte000;
+ }
+ if (jjte000 instanceof ParseException) {
+ throw (ParseException)jjte000;
+ }
+ throw (Error)jjte000;
+ } finally {
+ if (jjtc000) {
+ jjtree.closeNodeScope(jjtn000, true);
+ }
+ }
+/*@egen*/
+}
+void expr():
+{ }
+{
+ < LPAREN > expr() < RPAREN > (< AND >/*@bgen(jjtree) #AND( 2) */
+ {
+ ASTAND jjtn001 = new ASTAND(JJTAND);
+ boolean jjtc001 = true;
+ jjtree.openNodeScope(jjtn001);
+ }
+ try {
+/*@egen*/ expr()/*@bgen(jjtree)*/
+ } catch (Throwable jjte001) {
+ if (jjtc001) {
+ jjtree.clearNodeScope(jjtn001);
+ jjtc001 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte001 instanceof RuntimeException) {
+ throw (RuntimeException)jjte001;
+ }
+ if (jjte001 instanceof ParseException) {
+ throw (ParseException)jjte001;
+ }
+ throw (Error)jjte001;
+ } finally {
+ if (jjtc001) {
+ jjtree.closeNodeScope(jjtn001, 2);
+ }
+ }
+/*@egen*/ | < OR >/*@bgen(jjtree) #OR( 2) */
+ {
+ ASTOR jjtn002 = new ASTOR(JJTOR);
+ boolean jjtc002 = true;
+ jjtree.openNodeScope(jjtn002);
+ }
+ try {
+/*@egen*/ expr()/*@bgen(jjtree)*/
+ } catch (Throwable jjte002) {
+ if (jjtc002) {
+ jjtree.clearNodeScope(jjtn002);
+ jjtc002 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte002 instanceof RuntimeException) {
+ throw (RuntimeException)jjte002;
+ }
+ if (jjte002 instanceof ParseException) {
+ throw (ParseException)jjte002;
+ }
+ throw (Error)jjte002;
+ } finally {
+ if (jjtc002) {
+ jjtree.closeNodeScope(jjtn002, 2);
+ }
+ }
+/*@egen*/ )?
+| neval() (< AND >/*@bgen(jjtree) #AND( 2) */
+ {
+ ASTAND jjtn003 = new ASTAND(JJTAND);
+ boolean jjtc003 = true;
+ jjtree.openNodeScope(jjtn003);
+ }
+ try {
+/*@egen*/ expr()/*@bgen(jjtree)*/
+ } catch (Throwable jjte003) {
+ if (jjtc003) {
+ jjtree.clearNodeScope(jjtn003);
+ jjtc003 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte003 instanceof RuntimeException) {
+ throw (RuntimeException)jjte003;
+ }
+ if (jjte003 instanceof ParseException) {
+ throw (ParseException)jjte003;
+ }
+ throw (Error)jjte003;
+ } finally {
+ if (jjtc003) {
+ jjtree.closeNodeScope(jjtn003, 2);
+ }
+ }
+/*@egen*/ | < OR >/*@bgen(jjtree) #OR( 2) */
+ {
+ ASTOR jjtn004 = new ASTOR(JJTOR);
+ boolean jjtc004 = true;
+ jjtree.openNodeScope(jjtn004);
+ }
+ try {
+/*@egen*/ expr()/*@bgen(jjtree)*/
+ } catch (Throwable jjte004) {
+ if (jjtc004) {
+ jjtree.clearNodeScope(jjtn004);
+ jjtc004 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte004 instanceof RuntimeException) {
+ throw (RuntimeException)jjte004;
+ }
+ if (jjte004 instanceof ParseException) {
+ throw (ParseException)jjte004;
+ }
+ throw (Error)jjte004;
+ } finally {
+ if (jjtc004) {
+ jjtree.closeNodeScope(jjtn004, 2);
+ }
+ }
+/*@egen*/ )?
+| eval() (< AND >/*@bgen(jjtree) #AND( 2) */
+ {
+ ASTAND jjtn005 = new ASTAND(JJTAND);
+ boolean jjtc005 = true;
+ jjtree.openNodeScope(jjtn005);
+ }
+ try {
+/*@egen*/ expr()/*@bgen(jjtree)*/
+ } catch (Throwable jjte005) {
+ if (jjtc005) {
+ jjtree.clearNodeScope(jjtn005);
+ jjtc005 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte005 instanceof RuntimeException) {
+ throw (RuntimeException)jjte005;
+ }
+ if (jjte005 instanceof ParseException) {
+ throw (ParseException)jjte005;
+ }
+ throw (Error)jjte005;
+ } finally {
+ if (jjtc005) {
+ jjtree.closeNodeScope(jjtn005, 2);
+ }
+ }
+/*@egen*/ | < OR >/*@bgen(jjtree) #OR( 2) */
+ {
+ ASTOR jjtn006 = new ASTOR(JJTOR);
+ boolean jjtc006 = true;
+ jjtree.openNodeScope(jjtn006);
+ }
+ try {
+/*@egen*/ expr()/*@bgen(jjtree)*/
+ } catch (Throwable jjte006) {
+ if (jjtc006) {
+ jjtree.clearNodeScope(jjtn006);
+ jjtc006 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte006 instanceof RuntimeException) {
+ throw (RuntimeException)jjte006;
+ }
+ if (jjte006 instanceof ParseException) {
+ throw (ParseException)jjte006;
+ }
+ throw (Error)jjte006;
+ } finally {
+ if (jjtc006) {
+ jjtree.closeNodeScope(jjtn006, 2);
+ }
+ }
+/*@egen*/ )?
+}
+void neval() :
+{/*@bgen(jjtree) NEVAL */
+ ASTNEVAL jjtn000 = new ASTNEVAL(JJTNEVAL);
+ boolean jjtc000 = true;
+ jjtree.openNodeScope(jjtn000);
+/*@egen*/ }
+{/*@bgen(jjtree) NEVAL */
+ try {
+/*@egen*/
+ < NOT > eval()/*@bgen(jjtree)*/
+ } catch (Throwable jjte000) {
+ if (jjtc000) {
+ jjtree.clearNodeScope(jjtn000);
+ jjtc000 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte000 instanceof RuntimeException) {
+ throw (RuntimeException)jjte000;
+ }
+ if (jjte000 instanceof ParseException) {
+ throw (ParseException)jjte000;
+ }
+ throw (Error)jjte000;
+ } finally {
+ if (jjtc000) {
+ jjtree.closeNodeScope(jjtn000, true);
+ }
+ }
+/*@egen*/
+}
+void eval() :
+{/*@bgen(jjtree) EVAL */
+ ASTEVAL jjtn000 = new ASTEVAL(JJTEVAL);
+ boolean jjtc000 = true;
+ jjtree.openNodeScope(jjtn000);
+/*@egen*/ }
+{/*@bgen(jjtree) EVAL */
+ try {
+/*@egen*/
+ term() comp() term()/*@bgen(jjtree)*/
+ } catch (Throwable jjte000) {
+ if (jjtc000) {
+ jjtree.clearNodeScope(jjtn000);
+ jjtc000 = false;
+ } else {
+ jjtree.popNode();
+ }
+ if (jjte000 instanceof RuntimeException) {
+ throw (RuntimeException)jjte000;
+ }
+ if (jjte000 instanceof ParseException) {
+ throw (ParseException)jjte000;
+ }
+ throw (Error)jjte000;
+ } finally {
+ if (jjtc000) {
+ jjtree.closeNodeScope(jjtn000, true);
+ }
+ }
+/*@egen*/
+}
+void comp():
+{ }
+{/*@bgen(jjtree) GT */
+ {
+ ASTGT jjtn001 = new ASTGT(JJTGT);
+ boolean jjtc001 = true;
+ jjtree.openNodeScope(jjtn001);
+ }
+ try {
+/*@egen*/ < GT >/*@bgen(jjtree)*/
+ } finally {
+ if (jjtc001) {
+ jjtree.closeNodeScope(jjtn001, true);
+ }
+ }
+/*@egen*/
+|/*@bgen(jjtree) LT */
+ {
+ ASTLT jjtn002 = new ASTLT(JJTLT);
+ boolean jjtc002 = true;
+ jjtree.openNodeScope(jjtn002);
+ }
+ try {
+/*@egen*/ < LT >/*@bgen(jjtree)*/
+ } finally {
+ if (jjtc002) {
+ jjtree.closeNodeScope(jjtn002, true);
+ }
+ }
+/*@egen*/
+|/*@bgen(jjtree) LTE */
+ {
+ ASTLTE jjtn003 = new ASTLTE(JJTLTE);
+ boolean jjtc003 = true;
+ jjtree.openNodeScope(jjtn003);
+ }
+ try {
+/*@egen*/ < LTE >/*@bgen(jjtree)*/
+ } finally {
+ if (jjtc003) {
+ jjtree.closeNodeScope(jjtn003, true);
+ }
+ }
+/*@egen*/
+|/*@bgen(jjtree) GTE */
+ {
+ ASTGTE jjtn004 = new ASTGTE(JJTGTE);
+ boolean jjtc004 = true;
+ jjtree.openNodeScope(jjtn004);
+ }
+ try {
+/*@egen*/ < GTE >/*@bgen(jjtree)*/
+ } finally {
+ if (jjtc004) {
+ jjtree.closeNodeScope(jjtn004, true);
+ }
+ }
+/*@egen*/
+|/*@bgen(jjtree) EQ */
+ {
+ ASTEQ jjtn005 = new ASTEQ(JJTEQ);
+ boolean jjtc005 = true;
+ jjtree.openNodeScope(jjtn005);
+ }
+ try {
+/*@egen*/ < EQUAL >/*@bgen(jjtree)*/
+ } finally {
+ if (jjtc005) {
+ jjtree.closeNodeScope(jjtn005, true);
+ }
+ }
+/*@egen*/
+|/*@bgen(jjtree) NEQ */
+ {
+ ASTNEQ jjtn006 = new ASTNEQ(JJTNEQ);
+ boolean jjtc006 = true;
+ jjtree.openNodeScope(jjtn006);
+ }
+ try {
+/*@egen*/ < NEQUAL >/*@bgen(jjtree)*/
+ } finally {
+ if (jjtc006) {
+ jjtree.closeNodeScope(jjtn006, true);
+ }
+ }
+/*@egen*/
+|/*@bgen(jjtree) MATCHES */
+ {
+ ASTMATCHES jjtn007 = new ASTMATCHES(JJTMATCHES);
+ boolean jjtc007 = true;
+ jjtree.openNodeScope(jjtn007);
+ }
+ try {
+/*@egen*/ < MATCHES >/*@bgen(jjtree)*/
+ } finally {
+ if (jjtc007) {
+ jjtree.closeNodeScope(jjtn007, true);
+ }
+ }
+/*@egen*/
+|/*@bgen(jjtree) LIKE */
+ {
+ ASTLIKE jjtn008 = new ASTLIKE(JJTLIKE);
+ boolean jjtc008 = true;
+ jjtree.openNodeScope(jjtn008);
+ }
+ try {
+/*@egen*/ < LIKE >/*@bgen(jjtree)*/
+ } finally {
+ if (jjtc008) {
+ jjtree.closeNodeScope(jjtn008, true);
+ }
+ }
+/*@egen*/
+}
+void term():
+{
+ Token t;
+ StringBuilder builder = new StringBuilder();
+}
+{
+ ( t = < INT >/*@bgen(jjtree) NUM */
+ {
+ ASTNUM jjtn001 = new ASTNUM(JJTNUM);
+ boolean jjtc001 = true;
+ jjtree.openNodeScope(jjtn001);
+ }
+ try {
+/*@egen*//*@bgen(jjtree)*/
+ {
+ jjtree.closeNodeScope(jjtn001, true);
+ jjtc001 = false;
+ }
+/*@egen*/ { jjtn001.value = new java.math.BigDecimal(t.image); }/*@bgen(jjtree)*/
+ } finally {
+ if (jjtc001) {
+ jjtree.closeNodeScope(jjtn001, true);
+ }
+ }
+/*@egen*/ )
+ | ( t = < FLOAT >/*@bgen(jjtree) NUM */
+ {
+ ASTNUM jjtn002 = new ASTNUM(JJTNUM);
+ boolean jjtc002 = true;
+ jjtree.openNodeScope(jjtn002);
+ }
+ try {
+/*@egen*//*@bgen(jjtree)*/
+ {
+ jjtree.closeNodeScope(jjtn002, true);
+ jjtc002 = false;
+ }
+/*@egen*/ { jjtn002.value = new java.math.BigDecimal(t.image); }/*@bgen(jjtree)*/
+ } finally {
+ if (jjtc002) {
+ jjtree.closeNodeScope(jjtn002, true);
+ }
+ }
+/*@egen*/ )
+ | ( < QUOTE > (t = < CHAR > { builder.append(t.image); })* < ENDQUOTE >/*@bgen(jjtree) STRING */
+ {
+ ASTSTRING jjtn003 = new ASTSTRING(JJTSTRING);
+ boolean jjtc003 = true;
+ jjtree.openNodeScope(jjtn003);
+ }
+ try {
+/*@egen*//*@bgen(jjtree)*/
+ {
+ jjtree.closeNodeScope(jjtn003, true);
+ jjtc003 = false;
+ }
+/*@egen*/ { jjtn003.value = builder.toString(); }/*@bgen(jjtree)*/
+ } finally {
+ if (jjtc003) {
+ jjtree.closeNodeScope(jjtn003, true);
+ }
+ }
+/*@egen*/ )
+ | ( < SQUOTE > (t = < SCHAR > { builder.append(t.image); })* < SENDQUOTE >/*@bgen(jjtree) STRING */
+ {
+ ASTSTRING jjtn004 = new ASTSTRING(JJTSTRING);
+ boolean jjtc004 = true;
+ jjtree.openNodeScope(jjtn004);
+ }
+ try {
+/*@egen*//*@bgen(jjtree)*/
+ {
+ jjtree.closeNodeScope(jjtn004, true);
+ jjtc004 = false;
+ }
+/*@egen*/ { jjtn004.value = builder.toString(); }/*@bgen(jjtree)*/
+ } finally {
+ if (jjtc004) {
+ jjtree.closeNodeScope(jjtn004, true);
+ }
+ }
+/*@egen*/ )
+ | ( t = < VARIABLE >/*@bgen(jjtree) VAR */
+ {
+ ASTVAR jjtn005 = new ASTVAR(JJTVAR);
+ boolean jjtc005 = true;
+ jjtree.openNodeScope(jjtn005);
+ }
+ try {
+/*@egen*//*@bgen(jjtree)*/
+ {
+ jjtree.closeNodeScope(jjtn005, true);
+ jjtc005 = false;
+ }
+/*@egen*/ { jjtn005.value = new Variable(t.image); }/*@bgen(jjtree)*/
+ } finally {
+ if (jjtc005) {
+ jjtree.closeNodeScope(jjtn005, true);
+ }
+ }
+/*@egen*/ )
+}
\ No newline at end of file
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParser.jjt b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParser.jjt
new file mode 100644
index 000000000..23136c138
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParser.jjt
@@ -0,0 +1,103 @@
+options {
+ NODE_DEFAULT_VOID = true;
+ MULTI = true;
+ STATIC = false;
+ VISITOR = true;
+}
+
+PARSER_BEGIN(PartitionParser)
+package com.netflix.metacat.common.partition.parser;
+public class PartitionParser {
+ public static void main (String args []) throws ParseException {
+ PartitionParser parser = new PartitionParser(new java.io.StringReader(args[0]));
+ SimpleNode root = parser.filter();
+ root.dump("");
+ System.out.println(root.jjtAccept(new com.netflix.metacat.common.partition.visitor.PartitionParserEval(), null));
+ }
+}
+PARSER_END(PartitionParser)
+
+SKIP :
+{
+ " " | "\t"
+}
+TOKEN :
+{
+ < EQUAL: "==" | "=">
+| < NEQUAL: "!=" | "<>">
+| < GTE: ">=" >
+| < GT: ">" >
+| < LTE: "<=" >
+| < LT: "<" >
+| < LPAREN : "(">
+| < RPAREN : ")">
+| < INT: ( )+ >
+| < #DIGIT: ["0" - "9"] >
+| < FLOAT: | ( )? >
+| < #EXPONENT: ["e", "E"] ("+"|"-")? >
+| < #MANTISSA: "." ( )* | ( )* "." >
+| < #DIGITS : (["0"-"9"])+ >
+| < AND: "and" | "&&">
+| < OR: "or" | "||">
+| < NOT: "not">
+| < MATCHES: "matches">
+| < LIKE: "like">
+| < VARIABLE : "_" < CHARS > | ["A"-"Z"] < CHARS > | ["a"-"z"] >
+| < #CHARS : (["a"-"z","0"-"9","_","A"-"Z"])+ >
+| < QUOTE:"\"" > : STRING_STATE
+| < SQUOTE:"\'" > : SSTRING_STATE
+}
+ TOKEN:
+{
+ > : DEFAULT
+|
+}
+ TOKEN:
+{
+ > : DEFAULT
+|
+}
+SimpleNode filter() #FILTER:
+{ }{
+ expr() { return jjtThis; }
+}
+void expr():
+{ }
+{
+ < LPAREN > expr() < RPAREN > (< AND > expr() #AND(2) | < OR > expr() #OR(2))?
+| neval() (< AND > expr() #AND(2) | < OR > expr() #OR(2))?
+| eval() (< AND > expr() #AND(2) | < OR > expr() #OR(2))?
+}
+void neval() #NEVAL:
+{ }
+{
+ < NOT > eval()
+}
+void eval() #EVAL:
+{ }
+{
+ term() comp() term()
+}
+void comp():
+{ }
+{ < GT > #GT
+| < LT > #LT
+| < LTE > #LTE
+| < GTE > #GTE
+| < EQUAL > #EQ
+| < NEQUAL > #NEQ
+| < MATCHES > #MATCHES
+| < LIKE > #LIKE
+}
+void term():
+{
+ Token t;
+ StringBuilder builder = new StringBuilder();
+}
+{
+ ( t = < INT > { jjtThis.value = new java.math.BigDecimal(t.image); } #NUM )
+ | ( t = < FLOAT > { jjtThis.value = new java.math.BigDecimal(t.image); } #NUM)
+ | ( < QUOTE > (t = < CHAR > { builder.append(t.image); })* < ENDQUOTE > { jjtThis.value = builder.toString(); } #STRING)
+ | ( < SQUOTE > (t = < SCHAR > { builder.append(t.image); })* < SENDQUOTE > { jjtThis.value = builder.toString(); } #STRING)
+ | ( t = < VARIABLE > { jjtThis.value = new Variable(t.image); } #VAR)
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserConstants.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserConstants.java
new file mode 100644
index 000000000..e86fa5647
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserConstants.java
@@ -0,0 +1,109 @@
+/* Generated By:JJTree&JavaCC: Do not edit this line. PartitionParserConstants.java */
+package com.netflix.metacat.common.partition.parser;
+
+
+/**
+ * Token literal values and constants.
+ * Generated by org.javacc.parser.OtherFilesGen#start()
+ */
+public interface PartitionParserConstants {
+
+ /** End of File. */
+ int EOF = 0;
+ /** RegularExpression Id. */
+ int EQUAL = 3;
+ /** RegularExpression Id. */
+ int NEQUAL = 4;
+ /** RegularExpression Id. */
+ int GTE = 5;
+ /** RegularExpression Id. */
+ int GT = 6;
+ /** RegularExpression Id. */
+ int LTE = 7;
+ /** RegularExpression Id. */
+ int LT = 8;
+ /** RegularExpression Id. */
+ int LPAREN = 9;
+ /** RegularExpression Id. */
+ int RPAREN = 10;
+ /** RegularExpression Id. */
+ int INT = 11;
+ /** RegularExpression Id. */
+ int DIGIT = 12;
+ /** RegularExpression Id. */
+ int FLOAT = 13;
+ /** RegularExpression Id. */
+ int EXPONENT = 14;
+ /** RegularExpression Id. */
+ int MANTISSA = 15;
+ /** RegularExpression Id. */
+ int DIGITS = 16;
+ /** RegularExpression Id. */
+ int AND = 17;
+ /** RegularExpression Id. */
+ int OR = 18;
+ /** RegularExpression Id. */
+ int NOT = 19;
+ /** RegularExpression Id. */
+ int MATCHES = 20;
+ /** RegularExpression Id. */
+ int LIKE = 21;
+ /** RegularExpression Id. */
+ int VARIABLE = 22;
+ /** RegularExpression Id. */
+ int CHARS = 23;
+ /** RegularExpression Id. */
+ int QUOTE = 24;
+ /** RegularExpression Id. */
+ int SQUOTE = 25;
+ /** RegularExpression Id. */
+ int ENDQUOTE = 26;
+ /** RegularExpression Id. */
+ int CHAR = 27;
+ /** RegularExpression Id. */
+ int SENDQUOTE = 28;
+ /** RegularExpression Id. */
+ int SCHAR = 29;
+
+ /** Lexical state. */
+ int DEFAULT = 0;
+ /** Lexical state. */
+ int STRING_STATE = 1;
+ /** Lexical state. */
+ int SSTRING_STATE = 2;
+
+ /** Literal token values. */
+ String[] tokenImage = {
+ "",
+ "\" \"",
+ "\"\\t\"",
+ "",
+ "",
+ "\">=\"",
+ "\">\"",
+ "\"<=\"",
+ "\"<\"",
+ "\"(\"",
+ "\")\"",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "\"not\"",
+ "\"matches\"",
+ "\"like\"",
+ "",
+ "",
+ "\"\\\"\"",
+ "\"\\\'\"",
+ "",
+ "",
+ "",
+ "",
+ };
+
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserDefaultVisitor.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserDefaultVisitor.java
new file mode 100644
index 000000000..9fee1a7fe
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserDefaultVisitor.java
@@ -0,0 +1,61 @@
+/* Generated By:JavaCC: Do not edit this line. PartitionParserDefaultVisitor.java Version 6.1_2 */
+package com.netflix.metacat.common.partition.parser;
+
+public class PartitionParserDefaultVisitor implements PartitionParserVisitor{
+ public Object defaultVisit(SimpleNode node, Object data){
+ node.childrenAccept(this, data);
+ return data;
+ }
+ public Object visit(SimpleNode node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTFILTER node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTAND node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTOR node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTNEVAL node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTEVAL node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTGT node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTLT node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTLTE node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTGTE node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTEQ node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTNEQ node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTMATCHES node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTLIKE node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTNUM node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTSTRING node, Object data){
+ return defaultVisit(node, data);
+ }
+ public Object visit(ASTVAR node, Object data){
+ return defaultVisit(node, data);
+ }
+}
+/* JavaCC - OriginalChecksum=449d8c0abd893cbe090860f00a25fca3 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserTokenManager.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserTokenManager.java
new file mode 100644
index 000000000..014e34777
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserTokenManager.java
@@ -0,0 +1,923 @@
+/* PartitionParserTokenManager.java */
+/* Generated By:JJTree&JavaCC: Do not edit this line. PartitionParserTokenManager.java */
+package com.netflix.metacat.common.partition.parser;
+
+/** Token Manager. */
+@SuppressWarnings("unused")public class PartitionParserTokenManager implements PartitionParserConstants {
+
+ /** Debug output. */
+ public java.io.PrintStream debugStream = System.out;
+ /** Set debug output. */
+ public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
+private final int jjStopStringLiteralDfa_0(int pos, long active0){
+ switch (pos)
+ {
+ case 0:
+ if ((active0 & 0x380000L) != 0L)
+ return 26;
+ if ((active0 & 0x180L) != 0L)
+ return 5;
+ return -1;
+ case 1:
+ if ((active0 & 0x380000L) != 0L)
+ {
+ jjmatchedKind = 22;
+ jjmatchedPos = 1;
+ return 26;
+ }
+ return -1;
+ case 2:
+ if ((active0 & 0x80000L) != 0L)
+ return 26;
+ if ((active0 & 0x300000L) != 0L)
+ {
+ jjmatchedKind = 22;
+ jjmatchedPos = 2;
+ return 26;
+ }
+ return -1;
+ case 3:
+ if ((active0 & 0x200000L) != 0L)
+ return 26;
+ if ((active0 & 0x100000L) != 0L)
+ {
+ jjmatchedKind = 22;
+ jjmatchedPos = 3;
+ return 26;
+ }
+ return -1;
+ case 4:
+ if ((active0 & 0x100000L) != 0L)
+ {
+ jjmatchedKind = 22;
+ jjmatchedPos = 4;
+ return 26;
+ }
+ return -1;
+ case 5:
+ if ((active0 & 0x100000L) != 0L)
+ {
+ jjmatchedKind = 22;
+ jjmatchedPos = 5;
+ return 26;
+ }
+ return -1;
+ default :
+ return -1;
+ }
+}
+private final int jjStartNfa_0(int pos, long active0){
+ return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
+}
+private int jjStopAtPos(int pos, int kind)
+{
+ jjmatchedKind = kind;
+ jjmatchedPos = pos;
+ return pos + 1;
+}
+private int jjMoveStringLiteralDfa0_0(){
+ switch(curChar)
+ {
+ case 34:
+ return jjStopAtPos(0, 24);
+ case 39:
+ return jjStopAtPos(0, 25);
+ case 40:
+ return jjStopAtPos(0, 9);
+ case 41:
+ return jjStopAtPos(0, 10);
+ case 60:
+ jjmatchedKind = 8;
+ return jjMoveStringLiteralDfa1_0(0x80L);
+ case 62:
+ jjmatchedKind = 6;
+ return jjMoveStringLiteralDfa1_0(0x20L);
+ case 108:
+ return jjMoveStringLiteralDfa1_0(0x200000L);
+ case 109:
+ return jjMoveStringLiteralDfa1_0(0x100000L);
+ case 110:
+ return jjMoveStringLiteralDfa1_0(0x80000L);
+ default :
+ return jjMoveNfa_0(1, 0);
+ }
+}
+private int jjMoveStringLiteralDfa1_0(long active0){
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(0, active0);
+ return 1;
+ }
+ switch(curChar)
+ {
+ case 61:
+ if ((active0 & 0x20L) != 0L)
+ return jjStopAtPos(1, 5);
+ else if ((active0 & 0x80L) != 0L)
+ return jjStopAtPos(1, 7);
+ break;
+ case 97:
+ return jjMoveStringLiteralDfa2_0(active0, 0x100000L);
+ case 105:
+ return jjMoveStringLiteralDfa2_0(active0, 0x200000L);
+ case 111:
+ return jjMoveStringLiteralDfa2_0(active0, 0x80000L);
+ default :
+ break;
+ }
+ return jjStartNfa_0(0, active0);
+}
+private int jjMoveStringLiteralDfa2_0(long old0, long active0){
+ if (((active0 &= old0)) == 0L)
+ return jjStartNfa_0(0, old0);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(1, active0);
+ return 2;
+ }
+ switch(curChar)
+ {
+ case 107:
+ return jjMoveStringLiteralDfa3_0(active0, 0x200000L);
+ case 116:
+ if ((active0 & 0x80000L) != 0L)
+ return jjStartNfaWithStates_0(2, 19, 26);
+ return jjMoveStringLiteralDfa3_0(active0, 0x100000L);
+ default :
+ break;
+ }
+ return jjStartNfa_0(1, active0);
+}
+private int jjMoveStringLiteralDfa3_0(long old0, long active0){
+ if (((active0 &= old0)) == 0L)
+ return jjStartNfa_0(1, old0);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(2, active0);
+ return 3;
+ }
+ switch(curChar)
+ {
+ case 99:
+ return jjMoveStringLiteralDfa4_0(active0, 0x100000L);
+ case 101:
+ if ((active0 & 0x200000L) != 0L)
+ return jjStartNfaWithStates_0(3, 21, 26);
+ break;
+ default :
+ break;
+ }
+ return jjStartNfa_0(2, active0);
+}
+private int jjMoveStringLiteralDfa4_0(long old0, long active0){
+ if (((active0 &= old0)) == 0L)
+ return jjStartNfa_0(2, old0);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(3, active0);
+ return 4;
+ }
+ switch(curChar)
+ {
+ case 104:
+ return jjMoveStringLiteralDfa5_0(active0, 0x100000L);
+ default :
+ break;
+ }
+ return jjStartNfa_0(3, active0);
+}
+private int jjMoveStringLiteralDfa5_0(long old0, long active0){
+ if (((active0 &= old0)) == 0L)
+ return jjStartNfa_0(3, old0);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(4, active0);
+ return 5;
+ }
+ switch(curChar)
+ {
+ case 101:
+ return jjMoveStringLiteralDfa6_0(active0, 0x100000L);
+ default :
+ break;
+ }
+ return jjStartNfa_0(4, active0);
+}
+private int jjMoveStringLiteralDfa6_0(long old0, long active0){
+ if (((active0 &= old0)) == 0L)
+ return jjStartNfa_0(4, old0);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(5, active0);
+ return 6;
+ }
+ switch(curChar)
+ {
+ case 115:
+ if ((active0 & 0x100000L) != 0L)
+ return jjStartNfaWithStates_0(6, 20, 26);
+ break;
+ default :
+ break;
+ }
+ return jjStartNfa_0(5, active0);
+}
+private int jjStartNfaWithStates_0(int pos, int kind, int state)
+{
+ jjmatchedKind = kind;
+ jjmatchedPos = pos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return pos + 1; }
+ return jjMoveNfa_0(state, pos + 1);
+}
+private int jjMoveNfa_0(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 37;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 1:
+ if ((0x3ff000000000000L & l) != 0L)
+ {
+ if (kind > 11)
+ kind = 11;
+ { jjCheckNAddStates(0, 6); }
+ }
+ else if (curChar == 38)
+ jjstateSet[jjnewStateCnt++] = 15;
+ else if (curChar == 46)
+ { jjCheckNAdd(8); }
+ else if (curChar == 60)
+ jjstateSet[jjnewStateCnt++] = 5;
+ else if (curChar == 33)
+ jjstateSet[jjnewStateCnt++] = 3;
+ else if (curChar == 61)
+ {
+ if (kind > 3)
+ kind = 3;
+ }
+ if (curChar == 61)
+ jjstateSet[jjnewStateCnt++] = 0;
+ break;
+ case 0:
+ if (curChar == 61 && kind > 3)
+ kind = 3;
+ break;
+ case 2:
+ if (curChar == 61 && kind > 3)
+ kind = 3;
+ break;
+ case 3:
+ if (curChar == 61 && kind > 4)
+ kind = 4;
+ break;
+ case 4:
+ if (curChar == 33)
+ jjstateSet[jjnewStateCnt++] = 3;
+ break;
+ case 5:
+ if (curChar == 62)
+ kind = 4;
+ break;
+ case 6:
+ if (curChar == 60)
+ jjstateSet[jjnewStateCnt++] = 5;
+ break;
+ case 7:
+ if (curChar == 46)
+ { jjCheckNAdd(8); }
+ break;
+ case 8:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 13)
+ kind = 13;
+ { jjCheckNAddTwoStates(8, 9); }
+ break;
+ case 10:
+ if ((0x280000000000L & l) != 0L)
+ { jjCheckNAdd(11); }
+ break;
+ case 11:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 13)
+ kind = 13;
+ { jjCheckNAdd(11); }
+ break;
+ case 15:
+ if (curChar == 38 && kind > 17)
+ kind = 17;
+ break;
+ case 16:
+ if (curChar == 38)
+ jjstateSet[jjnewStateCnt++] = 15;
+ break;
+ case 22:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 22)
+ kind = 22;
+ jjstateSet[jjnewStateCnt++] = 22;
+ break;
+ case 24:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 22)
+ kind = 22;
+ jjstateSet[jjnewStateCnt++] = 24;
+ break;
+ case 26:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 22)
+ kind = 22;
+ jjstateSet[jjnewStateCnt++] = 26;
+ break;
+ case 27:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 11)
+ kind = 11;
+ { jjCheckNAddStates(0, 6); }
+ break;
+ case 28:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 11)
+ kind = 11;
+ { jjCheckNAdd(28); }
+ break;
+ case 29:
+ if ((0x3ff000000000000L & l) != 0L)
+ { jjCheckNAddTwoStates(29, 30); }
+ break;
+ case 31:
+ if ((0x280000000000L & l) != 0L)
+ { jjCheckNAdd(32); }
+ break;
+ case 32:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 13)
+ kind = 13;
+ { jjCheckNAdd(32); }
+ break;
+ case 33:
+ if ((0x3ff000000000000L & l) != 0L)
+ { jjCheckNAddTwoStates(33, 34); }
+ break;
+ case 34:
+ if (curChar != 46)
+ break;
+ if (kind > 13)
+ kind = 13;
+ { jjCheckNAddTwoStates(35, 9); }
+ break;
+ case 35:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 13)
+ kind = 13;
+ { jjCheckNAddTwoStates(35, 9); }
+ break;
+ case 36:
+ if ((0x3ff000000000000L & l) != 0L)
+ { jjCheckNAddTwoStates(36, 7); }
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 1:
+ if ((0x7fffffe00000000L & l) != 0L)
+ { jjCheckNAdd(26); }
+ else if ((0x7fffffeL & l) != 0L)
+ { jjCheckNAdd(24); }
+ else if (curChar == 95)
+ { jjCheckNAdd(22); }
+ else if (curChar == 124)
+ jjstateSet[jjnewStateCnt++] = 19;
+ if (curChar == 111)
+ jjstateSet[jjnewStateCnt++] = 17;
+ else if (curChar == 97)
+ jjstateSet[jjnewStateCnt++] = 13;
+ break;
+ case 9:
+ if ((0x2000000020L & l) != 0L)
+ { jjAddStates(7, 8); }
+ break;
+ case 12:
+ if (curChar == 100 && kind > 17)
+ kind = 17;
+ break;
+ case 13:
+ if (curChar == 110)
+ jjstateSet[jjnewStateCnt++] = 12;
+ break;
+ case 14:
+ if (curChar == 97)
+ jjstateSet[jjnewStateCnt++] = 13;
+ break;
+ case 17:
+ if (curChar == 114 && kind > 18)
+ kind = 18;
+ break;
+ case 18:
+ if (curChar == 111)
+ jjstateSet[jjnewStateCnt++] = 17;
+ break;
+ case 19:
+ if (curChar == 124 && kind > 18)
+ kind = 18;
+ break;
+ case 20:
+ if (curChar == 124)
+ jjstateSet[jjnewStateCnt++] = 19;
+ break;
+ case 21:
+ if (curChar == 95)
+ { jjCheckNAdd(22); }
+ break;
+ case 22:
+ if ((0x7fffffe87fffffeL & l) == 0L)
+ break;
+ if (kind > 22)
+ kind = 22;
+ { jjCheckNAdd(22); }
+ break;
+ case 23:
+ if ((0x7fffffeL & l) != 0L)
+ { jjCheckNAdd(24); }
+ break;
+ case 24:
+ if ((0x7fffffe87fffffeL & l) == 0L)
+ break;
+ if (kind > 22)
+ kind = 22;
+ { jjCheckNAdd(24); }
+ break;
+ case 25:
+ if ((0x7fffffe00000000L & l) != 0L)
+ { jjCheckNAdd(26); }
+ break;
+ case 26:
+ if ((0x7fffffe87fffffeL & l) == 0L)
+ break;
+ if (kind > 22)
+ kind = 22;
+ { jjCheckNAdd(26); }
+ break;
+ case 30:
+ if ((0x2000000020L & l) != 0L)
+ { jjAddStates(9, 10); }
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 37 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+private int jjMoveStringLiteralDfa0_2()
+{
+ return jjMoveNfa_2(0, 0);
+}
+static final long[] jjbitVec0 = {
+ 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+private int jjMoveNfa_2(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 2;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((0xffffff7fffffffffL & l) != 0L)
+ {
+ if (kind > 29)
+ kind = 29;
+ }
+ else if (curChar == 39)
+ {
+ if (kind > 28)
+ kind = 28;
+ }
+ break;
+ case 1:
+ if ((0xffffff7fffffffffL & l) != 0L)
+ kind = 29;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ kind = 29;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 29)
+ kind = 29;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 2 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+private int jjMoveStringLiteralDfa0_1()
+{
+ return jjMoveNfa_1(0, 0);
+}
+private int jjMoveNfa_1(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 2;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((0xfffffffbffffffffL & l) != 0L)
+ {
+ if (kind > 27)
+ kind = 27;
+ }
+ else if (curChar == 34)
+ {
+ if (kind > 26)
+ kind = 26;
+ }
+ break;
+ case 1:
+ if ((0xfffffffbffffffffL & l) != 0L)
+ kind = 27;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ kind = 27;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 27)
+ kind = 27;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 2 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+static final int[] jjnextStates = {
+ 28, 29, 30, 33, 34, 36, 7, 10, 11, 31, 32,
+};
+
+/** Token literal values. */
+public static final String[] jjstrLiteralImages = {
+"", null, null, null, null, "\76\75", "\76", "\74\75", "\74", "\50", "\51",
+null, null, null, null, null, null, null, null, "\156\157\164",
+"\155\141\164\143\150\145\163", "\154\151\153\145", null, null, "\42", "\47", null, null, null, null, };
+protected Token jjFillToken()
+{
+ final Token t;
+ final String curTokenImage;
+ final int beginLine;
+ final int endLine;
+ final int beginColumn;
+ final int endColumn;
+ String im = jjstrLiteralImages[jjmatchedKind];
+ curTokenImage = (im == null) ? input_stream.GetImage() : im;
+ beginLine = input_stream.getBeginLine();
+ beginColumn = input_stream.getBeginColumn();
+ endLine = input_stream.getEndLine();
+ endColumn = input_stream.getEndColumn();
+ t = Token.newToken(jjmatchedKind, curTokenImage);
+
+ t.beginLine = beginLine;
+ t.endLine = endLine;
+ t.beginColumn = beginColumn;
+ t.endColumn = endColumn;
+
+ return t;
+}
+
+int curLexState = 0;
+int defaultLexState = 0;
+int jjnewStateCnt;
+int jjround;
+int jjmatchedPos;
+int jjmatchedKind;
+
+/** Get the next Token. */
+public Token getNextToken()
+{
+ Token matchedToken;
+ int curPos = 0;
+
+ EOFLoop :
+ for (;;)
+ {
+ try
+ {
+ curChar = input_stream.BeginToken();
+ }
+ catch(Exception e)
+ {
+ jjmatchedKind = 0;
+ jjmatchedPos = -1;
+ matchedToken = jjFillToken();
+ return matchedToken;
+ }
+
+ switch(curLexState)
+ {
+ case 0:
+ try { input_stream.backup(0);
+ while (curChar <= 32 && (0x100000200L & (1L << curChar)) != 0L)
+ curChar = input_stream.BeginToken();
+ }
+ catch (java.io.IOException e1) { continue EOFLoop; }
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_0();
+ break;
+ case 1:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_1();
+ break;
+ case 2:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_2();
+ break;
+ }
+ if (jjmatchedKind != 0x7fffffff)
+ {
+ if (jjmatchedPos + 1 < curPos)
+ input_stream.backup(curPos - jjmatchedPos - 1);
+ if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+ {
+ matchedToken = jjFillToken();
+ if (jjnewLexState[jjmatchedKind] != -1)
+ curLexState = jjnewLexState[jjmatchedKind];
+ return matchedToken;
+ }
+ else
+ {
+ if (jjnewLexState[jjmatchedKind] != -1)
+ curLexState = jjnewLexState[jjmatchedKind];
+ continue EOFLoop;
+ }
+ }
+ int error_line = input_stream.getEndLine();
+ int error_column = input_stream.getEndColumn();
+ String error_after = null;
+ boolean EOFSeen = false;
+ try { input_stream.readChar(); input_stream.backup(1); }
+ catch (java.io.IOException e1) {
+ EOFSeen = true;
+ error_after = curPos <= 1 ? "" : input_stream.GetImage();
+ if (curChar == '\n' || curChar == '\r') {
+ error_line++;
+ error_column = 0;
+ }
+ else
+ error_column++;
+ }
+ if (!EOFSeen) {
+ input_stream.backup(1);
+ error_after = curPos <= 1 ? "" : input_stream.GetImage();
+ }
+ throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR);
+ }
+}
+
+private void jjCheckNAdd(int state)
+{
+ if (jjrounds[state] != jjround)
+ {
+ jjstateSet[jjnewStateCnt++] = state;
+ jjrounds[state] = jjround;
+ }
+}
+private void jjAddStates(int start, int end)
+{
+ do {
+ jjstateSet[jjnewStateCnt++] = jjnextStates[start];
+ } while (start++ != end);
+}
+private void jjCheckNAddTwoStates(int state1, int state2)
+{
+ jjCheckNAdd(state1);
+ jjCheckNAdd(state2);
+}
+
+private void jjCheckNAddStates(int start, int end)
+{
+ do {
+ jjCheckNAdd(jjnextStates[start]);
+ } while (start++ != end);
+}
+
+ /** Constructor. */
+ public PartitionParserTokenManager(SimpleCharStream stream){
+
+ if (SimpleCharStream.staticFlag)
+ throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
+
+ input_stream = stream;
+ }
+
+ /** Constructor. */
+ public PartitionParserTokenManager (SimpleCharStream stream, int lexState){
+ ReInit(stream);
+ SwitchTo(lexState);
+ }
+
+ /** Reinitialise parser. */
+ public void ReInit(SimpleCharStream stream)
+ {
+
+ jjmatchedPos = jjnewStateCnt = 0;
+ curLexState = defaultLexState;
+ input_stream = stream;
+ ReInitRounds();
+ }
+
+ private void ReInitRounds()
+ {
+ int i;
+ jjround = 0x80000001;
+ for (i = 37; i-- > 0;)
+ jjrounds[i] = 0x80000000;
+ }
+
+ /** Reinitialise parser. */
+ public void ReInit( SimpleCharStream stream, int lexState)
+ {
+
+ ReInit( stream);
+ SwitchTo(lexState);
+ }
+
+ /** Switch to specified lex state. */
+ public void SwitchTo(int lexState)
+ {
+ if (lexState >= 3 || lexState < 0)
+ throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
+ else
+ curLexState = lexState;
+ }
+
+/** Lexer state names. */
+public static final String[] lexStateNames = {
+ "DEFAULT",
+ "STRING_STATE",
+ "SSTRING_STATE",
+};
+
+/** Lex State array. */
+public static final int[] jjnewLexState = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1,
+ 2, 0, -1, 0, -1,
+};
+static final long[] jjtoToken = {
+ 0x3f7e2ff9L,
+};
+static final long[] jjtoSkip = {
+ 0x6L,
+};
+ protected SimpleCharStream input_stream;
+
+ private final int[] jjrounds = new int[37];
+ private final int[] jjstateSet = new int[2 * 37];
+
+
+ protected int curChar;
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserTreeConstants.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserTreeConstants.java
new file mode 100644
index 000000000..d3de2ef7d
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserTreeConstants.java
@@ -0,0 +1,45 @@
+/* Generated By:JavaCC: Do not edit this line. PartitionParserTreeConstants.java Version 6.1_2 */
+package com.netflix.metacat.common.partition.parser;
+
+public interface PartitionParserTreeConstants
+{
+ public int JJTFILTER = 0;
+ public int JJTVOID = 1;
+ public int JJTAND = 2;
+ public int JJTOR = 3;
+ public int JJTNEVAL = 4;
+ public int JJTEVAL = 5;
+ public int JJTGT = 6;
+ public int JJTLT = 7;
+ public int JJTLTE = 8;
+ public int JJTGTE = 9;
+ public int JJTEQ = 10;
+ public int JJTNEQ = 11;
+ public int JJTMATCHES = 12;
+ public int JJTLIKE = 13;
+ public int JJTNUM = 14;
+ public int JJTSTRING = 15;
+ public int JJTVAR = 16;
+
+
+ public String[] jjtNodeName = {
+ "FILTER",
+ "void",
+ "AND",
+ "OR",
+ "NEVAL",
+ "EVAL",
+ "GT",
+ "LT",
+ "LTE",
+ "GTE",
+ "EQ",
+ "NEQ",
+ "MATCHES",
+ "LIKE",
+ "NUM",
+ "STRING",
+ "VAR",
+ };
+}
+/* JavaCC - OriginalChecksum=39fa5c3d77b7e45b2de2245168f22ad8 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserVisitor.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserVisitor.java
new file mode 100644
index 000000000..ec9f7561c
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/PartitionParserVisitor.java
@@ -0,0 +1,24 @@
+/* Generated By:JavaCC: Do not edit this line. PartitionParserVisitor.java Version 6.1_2 */
+package com.netflix.metacat.common.partition.parser;
+
+public interface PartitionParserVisitor
+{
+ public Object visit(SimpleNode node, Object data);
+ public Object visit(ASTFILTER node, Object data);
+ public Object visit(ASTAND node, Object data);
+ public Object visit(ASTOR node, Object data);
+ public Object visit(ASTNEVAL node, Object data);
+ public Object visit(ASTEVAL node, Object data);
+ public Object visit(ASTGT node, Object data);
+ public Object visit(ASTLT node, Object data);
+ public Object visit(ASTLTE node, Object data);
+ public Object visit(ASTGTE node, Object data);
+ public Object visit(ASTEQ node, Object data);
+ public Object visit(ASTNEQ node, Object data);
+ public Object visit(ASTMATCHES node, Object data);
+ public Object visit(ASTLIKE node, Object data);
+ public Object visit(ASTNUM node, Object data);
+ public Object visit(ASTSTRING node, Object data);
+ public Object visit(ASTVAR node, Object data);
+}
+/* JavaCC - OriginalChecksum=05c7915a864bf7b60e61bf6f66b57af6 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/SimpleCharStream.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/SimpleCharStream.java
new file mode 100644
index 000000000..5bb4b2dd7
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/SimpleCharStream.java
@@ -0,0 +1,474 @@
+/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 6.1 */
+/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+/**
+ * An implementation of interface CharStream, where the stream is assumed to
+ * contain only ASCII characters (without unicode processing).
+ */
+
+public class SimpleCharStream
+{
+/** Whether parser is static. */
+ public static final boolean staticFlag = false;
+ int bufsize;
+ int available;
+ int tokenBegin;
+/** Position in buffer. */
+ public int bufpos = -1;
+ protected int bufline[];
+ protected int bufcolumn[];
+
+ protected int column = 0;
+ protected int line = 1;
+
+ protected boolean prevCharIsCR = false;
+ protected boolean prevCharIsLF = false;
+
+ protected java.io.Reader inputStream;
+
+ protected char[] buffer;
+ protected int maxNextCharInd = 0;
+ protected int inBuf = 0;
+ protected int tabSize = 1;
+ protected boolean trackLineColumn = true;
+
+ public void setTabSize(int i) { tabSize = i; }
+ public int getTabSize() { return tabSize; }
+
+
+
+ protected void ExpandBuff(boolean wrapAround)
+ {
+ char[] newbuffer = new char[bufsize + 2048];
+ int newbufline[] = new int[bufsize + 2048];
+ int newbufcolumn[] = new int[bufsize + 2048];
+
+ try
+ {
+ if (wrapAround)
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
+ buffer = newbuffer;
+
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+ bufline = newbufline;
+
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+ bufcolumn = newbufcolumn;
+
+ maxNextCharInd = (bufpos += (bufsize - tokenBegin));
+ }
+ else
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ buffer = newbuffer;
+
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ bufline = newbufline;
+
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ bufcolumn = newbufcolumn;
+
+ maxNextCharInd = (bufpos -= tokenBegin);
+ }
+ }
+ catch (Throwable t)
+ {
+ throw new Error(t.getMessage());
+ }
+
+
+ bufsize += 2048;
+ available = bufsize;
+ tokenBegin = 0;
+ }
+
+ protected void FillBuff() throws java.io.IOException
+ {
+ if (maxNextCharInd == available)
+ {
+ if (available == bufsize)
+ {
+ if (tokenBegin > 2048)
+ {
+ bufpos = maxNextCharInd = 0;
+ available = tokenBegin;
+ }
+ else if (tokenBegin < 0)
+ bufpos = maxNextCharInd = 0;
+ else
+ ExpandBuff(false);
+ }
+ else if (available > tokenBegin)
+ available = bufsize;
+ else if ((tokenBegin - available) < 2048)
+ ExpandBuff(true);
+ else
+ available = tokenBegin;
+ }
+
+ int i;
+ try {
+ if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1)
+ {
+ inputStream.close();
+ throw new java.io.IOException();
+ }
+ else
+ maxNextCharInd += i;
+ return;
+ }
+ catch(java.io.IOException e) {
+ --bufpos;
+ backup(0);
+ if (tokenBegin == -1)
+ tokenBegin = bufpos;
+ throw e;
+ }
+ }
+
+/** Start. */
+ public char BeginToken() throws java.io.IOException
+ {
+ tokenBegin = -1;
+ char c = readChar();
+ tokenBegin = bufpos;
+
+ return c;
+ }
+
+ protected void UpdateLineColumn(char c)
+ {
+ column++;
+
+ if (prevCharIsLF)
+ {
+ prevCharIsLF = false;
+ line += (column = 1);
+ }
+ else if (prevCharIsCR)
+ {
+ prevCharIsCR = false;
+ if (c == '\n')
+ {
+ prevCharIsLF = true;
+ }
+ else
+ line += (column = 1);
+ }
+
+ switch (c)
+ {
+ case '\r' :
+ prevCharIsCR = true;
+ break;
+ case '\n' :
+ prevCharIsLF = true;
+ break;
+ case '\t' :
+ column--;
+ column += (tabSize - (column % tabSize));
+ break;
+ default :
+ break;
+ }
+
+ bufline[bufpos] = line;
+ bufcolumn[bufpos] = column;
+ }
+
+/** Read a character. */
+ public char readChar() throws java.io.IOException
+ {
+ if (inBuf > 0)
+ {
+ --inBuf;
+
+ if (++bufpos == bufsize)
+ bufpos = 0;
+
+ return buffer[bufpos];
+ }
+
+ if (++bufpos >= maxNextCharInd)
+ FillBuff();
+
+ char c = buffer[bufpos];
+
+ UpdateLineColumn(c);
+ return c;
+ }
+
+ @Deprecated
+ /**
+ * @deprecated
+ * @see #getEndColumn
+ */
+
+ public int getColumn() {
+ return bufcolumn[bufpos];
+ }
+
+ @Deprecated
+ /**
+ * @deprecated
+ * @see #getEndLine
+ */
+
+ public int getLine() {
+ return bufline[bufpos];
+ }
+
+ /** Get token end column number. */
+ public int getEndColumn() {
+ return bufcolumn[bufpos];
+ }
+
+ /** Get token end line number. */
+ public int getEndLine() {
+ return bufline[bufpos];
+ }
+
+ /** Get token beginning column number. */
+ public int getBeginColumn() {
+ return bufcolumn[tokenBegin];
+ }
+
+ /** Get token beginning line number. */
+ public int getBeginLine() {
+ return bufline[tokenBegin];
+ }
+
+/** Backup a number of characters. */
+ public void backup(int amount) {
+
+ inBuf += amount;
+ if ((bufpos -= amount) < 0)
+ bufpos += bufsize;
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ inputStream = dstream;
+ line = startline;
+ column = startcolumn - 1;
+
+ available = bufsize = buffersize;
+ buffer = new char[buffersize];
+ bufline = new int[buffersize];
+ bufcolumn = new int[buffersize];
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream, int startline,
+ int startcolumn)
+ {
+ this(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream)
+ {
+ this(dstream, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ inputStream = dstream;
+ line = startline;
+ column = startcolumn - 1;
+
+ if (buffer == null || buffersize != buffer.length)
+ {
+ available = bufsize = buffersize;
+ buffer = new char[buffersize];
+ bufline = new int[buffersize];
+ bufcolumn = new int[buffersize];
+ }
+ prevCharIsLF = prevCharIsCR = false;
+ tokenBegin = inBuf = maxNextCharInd = 0;
+ bufpos = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream, int startline,
+ int startcolumn)
+ {
+ ReInit(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream)
+ {
+ ReInit(dstream, 1, 1, 4096);
+ }
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+ {
+ this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn) throws java.io.UnsupportedEncodingException
+ {
+ this(dstream, encoding, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, int startline,
+ int startcolumn)
+ {
+ this(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+ {
+ this(dstream, encoding, 1, 1, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream)
+ {
+ this(dstream, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(dstream, encoding, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream)
+ {
+ ReInit(dstream, 1, 1, 4096);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(dstream, encoding, startline, startcolumn, 4096);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, int startline,
+ int startcolumn)
+ {
+ ReInit(dstream, startline, startcolumn, 4096);
+ }
+ /** Get token literal value. */
+ public String GetImage()
+ {
+ if (bufpos >= tokenBegin)
+ return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+ else
+ return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+ new String(buffer, 0, bufpos + 1);
+ }
+
+ /** Get the suffix. */
+ public char[] GetSuffix(int len)
+ {
+ char[] ret = new char[len];
+
+ if ((bufpos + 1) >= len)
+ System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+ else
+ {
+ System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+ len - bufpos - 1);
+ System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+ }
+
+ return ret;
+ }
+
+ /** Reset buffer when finished. */
+ public void Done()
+ {
+ buffer = null;
+ bufline = null;
+ bufcolumn = null;
+ }
+
+ /**
+ * Method to adjust line and column numbers for the start of a token.
+ */
+ public void adjustBeginLineColumn(int newLine, int newCol)
+ {
+ int start = tokenBegin;
+ int len;
+
+ if (bufpos >= tokenBegin)
+ {
+ len = bufpos - tokenBegin + inBuf + 1;
+ }
+ else
+ {
+ len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+ }
+
+ int i = 0, j = 0, k = 0;
+ int nextColDiff = 0, columnDiff = 0;
+
+ while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
+ {
+ bufline[j] = newLine;
+ nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+ bufcolumn[j] = newCol + columnDiff;
+ columnDiff = nextColDiff;
+ i++;
+ }
+
+ if (i < len)
+ {
+ bufline[j] = newLine++;
+ bufcolumn[j] = newCol + columnDiff;
+
+ while (i++ < len)
+ {
+ if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+ bufline[j] = newLine++;
+ else
+ bufline[j] = newLine;
+ }
+ }
+
+ line = bufline[j];
+ column = bufcolumn[j];
+ }
+ boolean getTrackLineColumn() { return trackLineColumn; }
+ void setTrackLineColumn(boolean tlc) { trackLineColumn = tlc; }
+}
+/* JavaCC - OriginalChecksum=9c39ca7cdd22491638c65876bc9c5ba3 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/SimpleNode.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/SimpleNode.java
new file mode 100644
index 000000000..3f0a6ecb5
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/SimpleNode.java
@@ -0,0 +1,102 @@
+/* Generated By:JJTree: Do not edit this line. SimpleNode.java Version 6.1 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+public
+class SimpleNode implements Node {
+
+ protected Node parent;
+ protected Node[] children;
+ protected int id;
+ protected Object value;
+ protected PartitionParser parser;
+
+ public SimpleNode(int i) {
+ id = i;
+ }
+
+ public SimpleNode(PartitionParser p, int i) {
+ this(i);
+ parser = p;
+ }
+
+ public void jjtOpen() {
+ }
+
+ public void jjtClose() {
+ }
+
+ public void jjtSetParent(Node n) { parent = n; }
+ public Node jjtGetParent() { return parent; }
+
+ public void jjtAddChild(Node n, int i) {
+ if (children == null) {
+ children = new Node[i + 1];
+ } else if (i >= children.length) {
+ Node c[] = new Node[i + 1];
+ System.arraycopy(children, 0, c, 0, children.length);
+ children = c;
+ }
+ children[i] = n;
+ }
+
+ public Node jjtGetChild(int i) {
+ return children[i];
+ }
+
+ public int jjtGetNumChildren() {
+ return (children == null) ? 0 : children.length;
+ }
+
+ public void jjtSetValue(Object value) { this.value = value; }
+ public Object jjtGetValue() { return value; }
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(PartitionParserVisitor visitor, Object data)
+{
+ return visitor.visit(this, data);
+ }
+
+ /** Accept the visitor. **/
+ public Object childrenAccept(PartitionParserVisitor visitor, Object data)
+{
+ if (children != null) {
+ for (int i = 0; i < children.length; ++i) {
+ children[i].jjtAccept(visitor, data);
+ }
+ }
+ return data;
+ }
+
+ /* You can override these two methods in subclasses of SimpleNode to
+ customize the way the node appears when the tree is dumped. If
+ your output uses more than one line you should override
+ toString(String), otherwise overriding toString() is probably all
+ you need to do. */
+
+ public String toString() {
+ return PartitionParserTreeConstants.jjtNodeName[id];
+ }
+ public String toString(String prefix) { return prefix + toString(); }
+
+ /* Override this method if you want to customize how the node dumps
+ out its children. */
+
+ public void dump(String prefix) {
+ System.out.println(toString(prefix));
+ if (children != null) {
+ for (int i = 0; i < children.length; ++i) {
+ SimpleNode n = (SimpleNode)children[i];
+ if (n != null) {
+ n.dump(prefix + " ");
+ }
+ }
+ }
+ }
+
+ public int getId() {
+ return id;
+ }
+}
+
+/* JavaCC - OriginalChecksum=d933f51a60f5df18ee957e3447d1a0d6 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/Token.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/Token.java
new file mode 100644
index 000000000..fa40615f8
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/Token.java
@@ -0,0 +1,131 @@
+/* Generated By:JavaCC: Do not edit this line. Token.java Version 6.1 */
+/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COLUMN=true,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package com.netflix.metacat.common.partition.parser;
+
+/**
+ * Describes the input token stream.
+ */
+
+public class Token implements java.io.Serializable {
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * An integer that describes the kind of this token. This numbering
+ * system is determined by JavaCCParser, and a table of these numbers is
+ * stored in the file ...Constants.java.
+ */
+ public int kind;
+
+ /** The line number of the first character of this Token. */
+ public int beginLine;
+ /** The column number of the first character of this Token. */
+ public int beginColumn;
+ /** The line number of the last character of this Token. */
+ public int endLine;
+ /** The column number of the last character of this Token. */
+ public int endColumn;
+
+ /**
+ * The string image of the token.
+ */
+ public String image;
+
+ /**
+ * A reference to the next regular (non-special) token from the input
+ * stream. If this is the last token from the input stream, or if the
+ * token manager has not read tokens beyond this one, this field is
+ * set to null. This is true only if this token is also a regular
+ * token. Otherwise, see below for a description of the contents of
+ * this field.
+ */
+ public Token next;
+
+ /**
+ * This field is used to access special tokens that occur prior to this
+ * token, but after the immediately preceding regular (non-special) token.
+ * If there are no such special tokens, this field is set to null.
+ * When there are more than one such special token, this field refers
+ * to the last of these special tokens, which in turn refers to the next
+ * previous special token through its specialToken field, and so on
+ * until the first special token (whose specialToken field is null).
+ * The next fields of special tokens refer to other special tokens that
+ * immediately follow it (without an intervening regular token). If there
+ * is no such token, this field is null.
+ */
+ public Token specialToken;
+
+ /**
+ * An optional attribute value of the Token.
+ * Tokens which are not used as syntactic sugar will often contain
+ * meaningful values that will be used later on by the compiler or
+ * interpreter. This attribute value is often different from the image.
+ * Any subclass of Token that actually wants to return a non-null value can
+ * override this method as appropriate.
+ */
+ public Object getValue() {
+ return null;
+ }
+
+ /**
+ * No-argument constructor
+ */
+ public Token() {}
+
+ /**
+ * Constructs a new token for the specified Image.
+ */
+ public Token(int kind)
+ {
+ this(kind, null);
+ }
+
+ /**
+ * Constructs a new token for the specified Image and Kind.
+ */
+ public Token(int kind, String image)
+ {
+ this.kind = kind;
+ this.image = image;
+ }
+
+ /**
+ * Returns the image.
+ */
+ public String toString()
+ {
+ return image;
+ }
+
+ /**
+ * Returns a new Token object, by default. However, if you want, you
+ * can create and return subclass objects based on the value of ofKind.
+ * Simply add the cases to the switch for all those special cases.
+ * For example, if you have a subclass of Token called IDToken that
+ * you want to create if ofKind is ID, simply add something like :
+ *
+ * case MyParserConstants.ID : return new IDToken(ofKind, image);
+ *
+ * to the following switch statement. Then you can cast matchedToken
+ * variable to the appropriate type and use sit in your lexical actions.
+ */
+ public static Token newToken(int ofKind, String image)
+ {
+ switch(ofKind)
+ {
+ default : return new Token(ofKind, image);
+ }
+ }
+
+ public static Token newToken(int ofKind)
+ {
+ return newToken(ofKind, null);
+ }
+
+}
+/* JavaCC - OriginalChecksum=4d702a3a65566da534de18086a42aa30 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/TokenMgrError.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/TokenMgrError.java
new file mode 100644
index 000000000..e44a4a8ea
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/TokenMgrError.java
@@ -0,0 +1,146 @@
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 6.1 */
+/* JavaCCOptions: */
+package com.netflix.metacat.common.partition.parser;
+
+/** Token Manager Error. */
+public class TokenMgrError extends Error
+{
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /*
+ * Ordinals for various reasons why an Error of this type can be thrown.
+ */
+
+ /**
+ * Lexical error occurred.
+ */
+ public static final int LEXICAL_ERROR = 0;
+
+ /**
+ * An attempt was made to create a second instance of a static token manager.
+ */
+ public static final int STATIC_LEXER_ERROR = 1;
+
+ /**
+ * Tried to change to an invalid lexical state.
+ */
+ public static final int INVALID_LEXICAL_STATE = 2;
+
+ /**
+ * Detected (and bailed out of) an infinite loop in the token manager.
+ */
+ public static final int LOOP_DETECTED = 3;
+
+ /**
+ * Indicates the reason why the exception is thrown. It will have
+ * one of the above 4 values.
+ */
+ int errorCode;
+
+ /**
+ * Replaces unprintable characters by their escaped (or unicode escaped)
+ * equivalents in the given string
+ */
+ protected static final String addEscapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0; i < str.length(); i++) {
+ switch (str.charAt(i))
+ {
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ case '\"':
+ retval.append("\\\"");
+ continue;
+ case '\'':
+ retval.append("\\\'");
+ continue;
+ case '\\':
+ retval.append("\\\\");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
+ }
+ }
+ return retval.toString();
+ }
+
+ /**
+ * Returns a detailed message for the Error when it is thrown by the
+ * token manager to indicate a lexical error.
+ * Parameters :
+ * EOFSeen : indicates if EOF caused the lexical error
+ * curLexState : lexical state in which this error occurred
+ * errorLine : line number when the error occurred
+ * errorColumn : column number when the error occurred
+ * errorAfter : prefix that was seen before this error occurred
+ * curchar : the offending character
+ * Note: You can customize the lexical error message by modifying this method.
+ */
+ protected static String LexicalErr(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, int curChar) {
+ char curChar1 = (char)curChar;
+ return("Lexical error at line " +
+ errorLine + ", column " +
+ errorColumn + ". Encountered: " +
+ (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar1)) + "\"") + " (" + (int)curChar + "), ") +
+ "after : \"" + addEscapes(errorAfter) + "\"");
+ }
+
+ /**
+ * You can also modify the body of this method to customize your error messages.
+ * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+ * of end-users concern, so you can return something like :
+ *
+ * "Internal Error : Please file a bug report .... "
+ *
+ * from this method for such cases in the release version of your parser.
+ */
+ public String getMessage() {
+ return super.getMessage();
+ }
+
+ /*
+ * Constructors of various flavors follow.
+ */
+
+ /** No arg constructor. */
+ public TokenMgrError() {
+ }
+
+ /** Constructor with message and reason. */
+ public TokenMgrError(String message, int reason) {
+ super(message);
+ errorCode = reason;
+ }
+
+ /** Full Constructor. */
+ public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, int curChar, int reason) {
+ this(LexicalErr(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
+ }
+}
+/* JavaCC - OriginalChecksum=3812be28fe4e0d40fc76a8de299261b3 (do not edit this line) */
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/Variable.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/Variable.java
new file mode 100644
index 000000000..8439c7015
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/parser/Variable.java
@@ -0,0 +1,17 @@
+package com.netflix.metacat.common.partition.parser;
+
+public class Variable {
+ private String name;
+
+ public Variable(String name) {
+ this.setName(name);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/util/FilterPartition.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/util/FilterPartition.java
new file mode 100644
index 000000000..776329a1e
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/util/FilterPartition.java
@@ -0,0 +1,51 @@
+package com.netflix.metacat.common.partition.util;
+
+import com.google.common.collect.Maps;
+import com.netflix.metacat.common.partition.parser.PartitionParser;
+import com.netflix.metacat.common.partition.visitor.PartitionParserEval;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Map;
+
+public class FilterPartition {
+ private static final Logger log = LoggerFactory.getLogger(FilterPartition.class);
+
+ PartitionParser parser;
+ Map context = Maps.newLinkedHashMap();
+
+ public boolean evaluatePartitionExpression(String partitionExpression, String name, String path) throws
+ IOException {
+ return evaluatePartitionExpression(partitionExpression, name, path, false, null);
+ }
+ public boolean evaluatePartitionExpression(String partitionExpression, String name, String path, boolean batchid, Map values) {
+ if (partitionExpression != null) {
+ try {
+ if (parser == null) {
+ parser = new PartitionParser(new StringReader(partitionExpression));
+ } else {
+ parser.ReInit(new StringReader(partitionExpression));
+ }
+ context.clear();
+ if (batchid) {
+ PartitionUtil.getPartitionKeyValues(path, context);
+ }
+ PartitionUtil.getPartitionKeyValues(name, context);
+ if( values != null){
+ context.putAll(values);
+ }
+ if(context.size() > 0) {
+ return (Boolean) parser.filter().jjtAccept(new PartitionParserEval(context), null);
+ } else {
+ return false;
+ }
+ } catch(Exception e) {
+ log.warn("Caught unexpected exception during evaluatePartitionExpression," + e);
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/util/PartitionUtil.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/util/PartitionUtil.java
new file mode 100644
index 000000000..845c4d02e
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/util/PartitionUtil.java
@@ -0,0 +1,55 @@
+package com.netflix.metacat.common.partition.util;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.Maps;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by amajumdar on 5/7/15.
+ */
+public class PartitionUtil {
+ private static final Splitter EQUAL_SPLITTER = Splitter.on('=').trimResults();
+ private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings().trimResults();
+ private static final Logger log = LoggerFactory.getLogger(PartitionUtil.class);
+ public static Map getPartitionKeyValues(String location) {
+ Map parts = Maps.newLinkedHashMap();
+ getPartitionKeyValues(location, parts);
+ return parts;
+ }
+
+ public static void getPartitionKeyValues(String location, Map parts) {
+ for (String part : Splitter.on('/').omitEmptyStrings().split(location)) {
+ if (part.contains("=")) {
+ String[] values = part.split("=", 2);
+
+ if(values[0].equalsIgnoreCase("null") || values[1].equalsIgnoreCase("null")) {
+ log.debug("Found 'null' string in kvp [{}] skipping.", part);
+ } else {
+ parts.put(values[0], values[1]);
+ }
+ }
+ }
+ }
+
+ public static void validatePartitionName(String partitionName, List partitionKeys) {
+ if (partitionKeys == null || partitionKeys.isEmpty()) {
+ throw new IllegalStateException("No partitionKeys are defined");
+ }
+
+ for (String part : SLASH_SPLITTER.split(partitionName)) {
+ List tokens = EQUAL_SPLITTER.splitToList(part);
+ if (tokens.size() != 2) {
+ throw new IllegalArgumentException(String.format("Partition name '%s' is invalid", partitionName));
+ }
+ String key = tokens.get(0);
+ String value = tokens.get(1);
+ if (!partitionKeys.contains(key) || value.isEmpty() || "null".equalsIgnoreCase(value)) {
+ throw new IllegalArgumentException(String.format("Partition name '%s' is invalid", partitionName));
+ }
+ }
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/visitor/PartitionKeyParserEval.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/visitor/PartitionKeyParserEval.java
new file mode 100644
index 000000000..697871dd7
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/visitor/PartitionKeyParserEval.java
@@ -0,0 +1,79 @@
+package com.netflix.metacat.common.partition.visitor;
+
+import com.google.common.collect.Sets;
+import com.netflix.metacat.common.partition.parser.ASTAND;
+import com.netflix.metacat.common.partition.parser.ASTEQ;
+import com.netflix.metacat.common.partition.parser.ASTEVAL;
+import com.netflix.metacat.common.partition.parser.ASTFILTER;
+import com.netflix.metacat.common.partition.parser.ASTGT;
+import com.netflix.metacat.common.partition.parser.ASTGTE;
+import com.netflix.metacat.common.partition.parser.ASTLIKE;
+import com.netflix.metacat.common.partition.parser.ASTLT;
+import com.netflix.metacat.common.partition.parser.ASTLTE;
+import com.netflix.metacat.common.partition.parser.ASTMATCHES;
+import com.netflix.metacat.common.partition.parser.ASTNEQ;
+import com.netflix.metacat.common.partition.parser.ASTNEVAL;
+import com.netflix.metacat.common.partition.parser.ASTNUM;
+import com.netflix.metacat.common.partition.parser.ASTOR;
+import com.netflix.metacat.common.partition.parser.ASTSTRING;
+import com.netflix.metacat.common.partition.parser.ASTVAR;
+import com.netflix.metacat.common.partition.parser.PartitionParserVisitor;
+import com.netflix.metacat.common.partition.parser.SimpleNode;
+import com.netflix.metacat.common.partition.parser.Variable;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+public class PartitionKeyParserEval extends PartitionParserEval {
+
+ public String evalString(SimpleNode node, Object data) {
+ Object value1 = node.jjtGetChild(0).jjtAccept(this, data);
+ Compare comparison = (Compare) node.jjtGetChild(1).jjtAccept(this, data);
+ Object value2 = node.jjtGetChild(2).jjtAccept(this, data);
+ if (comparison != Compare.EQ) {
+ return null;
+ }
+ return String.format("%s=%s", value1, value2.toString());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object visit(ASTAND node, Object data) {
+ Collection v1 = (Collection) node.jjtGetChild(0).jjtAccept(this, data);
+ Object b = node.jjtGetChild(1).jjtAccept(this, data);
+ v1.addAll((Collection) b);
+ return v1;
+ }
+
+ @Override
+ public Object visit(ASTEQ node, Object data) {
+ return Compare.EQ;
+ }
+
+ @Override
+ public Object visit(ASTEVAL node, Object data) {
+ Set result = Sets.newHashSet();
+ String value = evalString(node, data);
+ if( value != null){
+ result = Sets.newHashSet(value);
+ }
+ return result;
+ }
+
+ @Override
+ public Object visit(ASTNEVAL node, Object data) {
+ return new HashSet();
+ }
+
+ @Override
+ public Object visit(ASTOR node, Object data) {
+ return new HashSet();
+ }
+
+ @Override
+ public Object visit(ASTVAR node, Object data) {
+ return ((Variable)node.jjtGetValue()).getName();
+ }
+
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/visitor/PartitionParamParserEval.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/visitor/PartitionParamParserEval.java
new file mode 100644
index 000000000..fd912003d
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/visitor/PartitionParamParserEval.java
@@ -0,0 +1,16 @@
+package com.netflix.metacat.common.partition.visitor;
+
+import com.netflix.metacat.common.partition.parser.SimpleNode;
+
+public class PartitionParamParserEval extends PartitionKeyParserEval {
+
+ public String evalString(SimpleNode node, Object data) {
+ Object value1 = node.jjtGetChild(0).jjtAccept(this, data);
+ if (!"dateCreated".equals(value1)) {
+ return null;
+ }
+ Compare comparison = (Compare) node.jjtGetChild(1).jjtAccept(this, data);
+ Object value2 = node.jjtGetChild(2).jjtAccept(this, data);
+ return String.format("%s%s%s", value1, comparison.getExpression(),value2.toString());
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/visitor/PartitionParserEval.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/visitor/PartitionParserEval.java
new file mode 100644
index 000000000..1e8b1e4c0
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/partition/visitor/PartitionParserEval.java
@@ -0,0 +1,218 @@
+package com.netflix.metacat.common.partition.visitor;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.netflix.metacat.common.partition.parser.ASTAND;
+import com.netflix.metacat.common.partition.parser.ASTEQ;
+import com.netflix.metacat.common.partition.parser.ASTEVAL;
+import com.netflix.metacat.common.partition.parser.ASTFILTER;
+import com.netflix.metacat.common.partition.parser.ASTGT;
+import com.netflix.metacat.common.partition.parser.ASTGTE;
+import com.netflix.metacat.common.partition.parser.ASTLIKE;
+import com.netflix.metacat.common.partition.parser.ASTLT;
+import com.netflix.metacat.common.partition.parser.ASTLTE;
+import com.netflix.metacat.common.partition.parser.ASTMATCHES;
+import com.netflix.metacat.common.partition.parser.ASTNEQ;
+import com.netflix.metacat.common.partition.parser.ASTNEVAL;
+import com.netflix.metacat.common.partition.parser.ASTNUM;
+import com.netflix.metacat.common.partition.parser.ASTOR;
+import com.netflix.metacat.common.partition.parser.ASTSTRING;
+import com.netflix.metacat.common.partition.parser.ASTVAR;
+import com.netflix.metacat.common.partition.parser.PartitionParserVisitor;
+import com.netflix.metacat.common.partition.parser.SimpleNode;
+import com.netflix.metacat.common.partition.parser.Variable;
+
+import java.math.BigDecimal;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PartitionParserEval implements PartitionParserVisitor {
+ public static final Pattern likePattern = Pattern.compile("(\\[%\\]|\\[_\\]|\\[\\[\\]|%|_)");
+ public static final Map likeToRegexReplacements = new ImmutableMap.Builder()
+ .put("[%]", "%")
+ .put("[_]", "_")
+ .put("[[]", "[")
+ .put("%", ".*")
+ .put("_", ".").build();
+ public enum Compare {
+ EQ("="), GT(">"), GTE(">="), LT("<"), LTE("<="), NEQ("!="), MATCHES("MATCHES"), LIKE("LIKE");
+ String expression;
+ Compare(String expression) {
+ this.expression = expression;
+ }
+ public String getExpression(){
+ return expression;
+ }
+ }
+
+ private Map context;
+
+ public PartitionParserEval() {
+ this(Maps.newHashMap());
+ }
+ public PartitionParserEval(Map context) {
+ this.context = context;
+ }
+
+ public Boolean eval(SimpleNode node, Object data) {
+ Object value1 = node.jjtGetChild(0).jjtAccept(this, data);
+ Compare comparison = (Compare) node.jjtGetChild(1).jjtAccept(this, data);
+ Object value2 = node.jjtGetChild(2).jjtAccept(this, data);
+ if (value2 instanceof String) {
+ return compare(comparison, value1.toString(), value2.toString());
+ }
+ if (value2 instanceof BigDecimal) {
+ if (value1 instanceof String) {
+ value1 = new BigDecimal(value1.toString());
+ }
+ return compare(comparison, (BigDecimal) value1, (BigDecimal) value2);
+ }
+ throw new RuntimeException("error processing partition filter");
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public Boolean compare(Compare comparison, Comparable value1, Comparable value2) {
+ if (value1 == null) {
+ switch (comparison) {
+ case EQ:
+ case LIKE:
+ case MATCHES:
+ return value2 == null;
+ case NEQ:
+ return value2 != null;
+ default:
+ return false;
+ }
+ }
+ if( comparison.equals(Compare.LIKE) || comparison.equals(Compare.MATCHES)){
+ if( value2 != null){
+ String value = value2.toString();
+ if(comparison.equals(Compare.LIKE)){
+ value = sqlLiketoRegexExpression(value);
+ }
+ return value1.toString().matches(value);
+ }
+ } else {
+ int compare = value1.compareTo(value2);
+ switch (comparison) {
+ case GT:
+ return compare > 0;
+ case GTE:
+ return compare >= 0;
+ case LT:
+ return compare < 0;
+ case LTE:
+ return compare <= 0;
+ case EQ:
+ return compare == 0;
+ case NEQ:
+ return compare != 0;
+ }
+ }
+ return false;
+ }
+
+ //TODO: Need to escape regex meta characters
+ protected String sqlLiketoRegexExpression(String likeExpression) {
+ Matcher m = likePattern.matcher(likeExpression);
+
+ StringBuffer builder = new StringBuffer();
+ while(m.find()){
+ m.appendReplacement(builder, likeToRegexReplacements.get(m.group()));
+ }
+ m.appendTail(builder);
+ return builder.toString();
+ }
+
+ @Override
+ public Object visit(ASTAND node, Object data) {
+ Boolean v1 = (Boolean) node.jjtGetChild(0).jjtAccept(this, data);
+ return v1 && (Boolean) node.jjtGetChild(1).jjtAccept(this, data);
+ }
+
+ @Override
+ public Object visit(ASTEQ node, Object data) {
+ return Compare.EQ;
+ }
+
+ @Override
+ public Object visit(ASTEVAL node, Object data) {
+ return eval(node, data);
+ }
+
+ @Override
+ public Object visit(ASTFILTER node, Object data) {
+ return node.jjtGetChild(0).jjtAccept(this, data);
+ }
+
+ @Override
+ public Object visit(ASTGT node, Object data) {
+ return Compare.GT;
+ }
+
+ @Override
+ public Object visit(ASTGTE node, Object data) {
+ return Compare.GTE;
+ }
+
+ @Override
+ public Object visit(ASTLT node, Object data) {
+ return Compare.LT;
+ }
+
+ @Override
+ public Object visit(ASTLTE node, Object data) {
+ return Compare.LTE;
+ }
+
+ @Override
+ public Object visit(ASTNEQ node, Object data) {
+ return Compare.NEQ;
+ }
+
+ @Override
+ public Object visit(ASTMATCHES node, Object data) {
+ return Compare.MATCHES;
+ }
+
+ @Override
+ public Object visit(ASTLIKE node, Object data) {
+ return Compare.LIKE;
+ }
+
+ @Override
+ public Object visit(ASTNEVAL node, Object data) {
+ return !(Boolean) node.jjtGetChild(0).jjtAccept(this, data);
+ }
+
+ @Override
+ public Object visit(ASTNUM node, Object data) {
+ return node.jjtGetValue();
+ }
+
+ @Override
+ public Object visit(ASTOR node, Object data) {
+ Boolean v1 = (Boolean) node.jjtGetChild(0).jjtAccept(this, data);
+ return v1 || (Boolean) node.jjtGetChild(1).jjtAccept(this, data);
+ }
+
+ @Override
+ public Object visit(ASTSTRING node, Object data) {
+ return node.jjtGetValue();
+ }
+
+ @Override
+ public Object visit(ASTVAR node, Object data) {
+ if (!context.containsKey(((Variable)node.jjtGetValue()).getName())) {
+ throw new RuntimeException("Missing variable: " + ((Variable)node.jjtGetValue()).getName());
+ }
+ return context.get(((Variable)node.jjtGetValue()).getName());
+ }
+
+ @Override
+ public Object visit(SimpleNode node, Object data) {
+ return null;
+ }
+
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/ArchaiusConfigImpl.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/ArchaiusConfigImpl.java
new file mode 100644
index 000000000..a38058ba5
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/ArchaiusConfigImpl.java
@@ -0,0 +1,172 @@
+package com.netflix.metacat.common.server;
+
+import com.netflix.config.DynamicBooleanProperty;
+import com.netflix.config.DynamicIntProperty;
+import com.netflix.config.DynamicPropertyFactory;
+import com.netflix.config.DynamicStringProperty;
+
+public class ArchaiusConfigImpl implements Config {
+ private final DynamicStringProperty defaultTypeConverter;
+ private final DynamicStringProperty elasticSearchClusterName;
+ private final DynamicStringProperty elasticSearchClusterNodes;
+ private final DynamicIntProperty elasticSearchClusterPort;
+ private final DynamicStringProperty elasticSearchRefreshExcludeDatabases;
+ private final DynamicStringProperty elasticSearchRefreshIncludeCatalogs;
+ private final DynamicStringProperty elasticSearchRefreshIncludeDatabases;
+ private final DynamicStringProperty elasticSearchRefreshPartitionsIncludeCatalogs;
+ private final DynamicIntProperty elasticSearchScrollFetchSize;
+ private final DynamicIntProperty elasticSearchScrollTimeout;
+ private final DynamicIntProperty elasticSearchThresholdUnmarkedDatabasesDelete;
+ private final DynamicIntProperty elasticSearchThresholdUnmarkedTablesDelete;
+ private final DynamicBooleanProperty epochInSeconds;
+ private final DynamicIntProperty eventBusExecutorThreadCount;
+ private final DynamicIntProperty eventBusThreadCount;
+ private final DynamicStringProperty hivePartitionWhitelistPattern;
+ private final DynamicStringProperty lookupServiceUserAdmin;
+ private final DynamicStringProperty pluginConfigLocation;
+ private final DynamicStringProperty tagServiceUserAdmin;
+ private final DynamicStringProperty metacatVersion;
+ private final DynamicBooleanProperty usePigTypes;
+
+ public ArchaiusConfigImpl() {
+ this(DynamicPropertyFactory.getInstance());
+ }
+
+ public ArchaiusConfigImpl(DynamicPropertyFactory factory) {
+ this.defaultTypeConverter = factory
+ .getStringProperty("metacat.type.converter", "com.netflix.metacat.converters.impl.PrestoTypeConverter");
+ this.elasticSearchClusterName = factory.getStringProperty("metacat.elacticsearch.cluster.name", null);
+ this.elasticSearchClusterNodes = factory.getStringProperty("metacat.elacticsearch.cluster.nodes", null);
+ this.elasticSearchClusterPort = factory.getIntProperty("metacat.elacticsearch.cluster.port", 7102);
+ this.elasticSearchRefreshExcludeDatabases = factory
+ .getStringProperty("metacat.elacticsearch.refresh.exclude.databases", null);
+ this.elasticSearchRefreshIncludeCatalogs = factory
+ .getStringProperty("metacat.elacticsearch.refresh.include.catalogs", null);
+ this.elasticSearchRefreshIncludeDatabases = factory
+ .getStringProperty("metacat.elacticsearch.refresh.include.databases", null);
+ this.elasticSearchRefreshPartitionsIncludeCatalogs = factory
+ .getStringProperty("metacat.elacticsearch.refresh.partitions.include.catalogs",
+ "prodhive,testhive,s3,aegisthus");
+ this.elasticSearchScrollFetchSize = factory.getIntProperty("metacat.elacticsearch.scroll.fetch.size", 500);
+ this.elasticSearchScrollTimeout = factory.getIntProperty("metacat.elacticsearch.scroll.timeout.ms", 60000);
+ this.elasticSearchThresholdUnmarkedDatabasesDelete = factory
+ .getIntProperty("metacat.elacticsearch.refresh.threshold.unmarked.databases.delete", 100);
+ this.elasticSearchThresholdUnmarkedTablesDelete = factory
+ .getIntProperty("metacat.elacticsearch.refresh.threshold.unmarked.tables.delete", 1000);
+ this.epochInSeconds = factory.getBooleanProperty("metacat.type.epoch_in_seconds", true);
+ this.eventBusExecutorThreadCount = factory.getIntProperty("metacat.event.bus.executor.thread.count", 10);
+ this.eventBusThreadCount = factory.getIntProperty("metacat.event.thread.count", 10);
+ this.hivePartitionWhitelistPattern = factory
+ .getStringProperty("metacat.hive.metastore.partition.name.whitelist.pattern", "");
+ this.lookupServiceUserAdmin = factory.getStringProperty("metacat.lookup_service.user_admin", "admin");
+ this.metacatVersion = factory.getStringProperty("netflix.appinfo.version", "1.0.0");
+ this.pluginConfigLocation = factory.getStringProperty("metacat.plugin.config.location", null);
+ this.tagServiceUserAdmin = factory.getStringProperty("metacat.tag_service.user_admin", "admin");
+ this.usePigTypes = factory.getBooleanProperty("metacat.franklin.connector.use.pig.type", true);
+ }
+
+ @Override
+ public String getDefaultTypeConverter() {
+ return defaultTypeConverter.get();
+ }
+
+ @Override
+ public String getElasticSearchClusterName() {
+ return elasticSearchClusterName.get();
+ }
+
+ @Override
+ public String getElasticSearchClusterNodes() {
+ return elasticSearchClusterNodes.get();
+ }
+
+ @Override
+ public int getElasticSearchClusterPort() {
+ return elasticSearchClusterPort.get();
+ }
+
+ @Override
+ public String getElasticSearchRefreshExcludeDatabases() {
+ return elasticSearchRefreshExcludeDatabases.get();
+ }
+
+ @Override
+ public String getElasticSearchRefreshIncludeCatalogs() {
+ return elasticSearchRefreshIncludeCatalogs.get();
+ }
+
+ @Override
+ public String getElasticSearchRefreshIncludeDatabases() {
+ return elasticSearchRefreshIncludeDatabases.get();
+ }
+
+ @Override
+ public String getElasticSearchRefreshPartitionsIncludeCatalogs() {
+ return elasticSearchRefreshPartitionsIncludeCatalogs.get();
+ }
+
+ @Override
+ public int getElasticSearchScrollFetchSize() {
+ return elasticSearchScrollFetchSize.get();
+ }
+
+ @Override
+ public int getElasticSearchScrollTimeout() {
+ return elasticSearchScrollTimeout.get();
+ }
+
+ @Override
+ public int getElasticSearchThresholdUnmarkedDatabasesDelete() {
+ return elasticSearchThresholdUnmarkedDatabasesDelete.get();
+ }
+
+ @Override
+ public int getElasticSearchThresholdUnmarkedTablesDelete() {
+ return elasticSearchThresholdUnmarkedTablesDelete.get();
+ }
+
+ @Override
+ public int getEventBusExecutorThreadCount() {
+ return eventBusExecutorThreadCount.get();
+ }
+
+ @Override
+ public int getEventBusThreadCount() {
+ return eventBusThreadCount.get();
+ }
+
+ @Override
+ public String getHivePartitionWhitelistPattern() {
+ return hivePartitionWhitelistPattern.get();
+ }
+
+ @Override
+ public String getLookupServiceUserAdmin() {
+ return lookupServiceUserAdmin.get();
+ }
+
+ @Override
+ public String getMetacatVersion() {
+ return metacatVersion.get();
+ }
+
+ @Override
+ public String getPluginConfigLocation() {
+ return pluginConfigLocation.get();
+ }
+
+ @Override
+ public String getTagServiceUserAdmin() {
+ return tagServiceUserAdmin.get();
+ }
+
+ @Override
+ public boolean isEpochInSeconds() {
+ return epochInSeconds.get();
+ }
+
+ @Override
+ public boolean isUsePigTypes() {
+ return usePigTypes.get();
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/CommonModule.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/CommonModule.java
new file mode 100644
index 000000000..dd42322c4
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/CommonModule.java
@@ -0,0 +1,48 @@
+package com.netflix.metacat.common.server;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.google.inject.AbstractModule;
+import com.google.inject.TypeLiteral;
+import com.google.inject.matcher.Matchers;
+import com.google.inject.spi.InjectionListener;
+import com.google.inject.spi.TypeEncounter;
+import com.google.inject.spi.TypeListener;
+import com.netflix.metacat.common.json.MetacatJson;
+import com.netflix.metacat.common.json.MetacatJsonLocator;
+import com.netflix.metacat.common.model.Lookup;
+import com.netflix.metacat.common.model.TagItem;
+import com.netflix.metacat.common.server.events.DeadEventHandler;
+import com.netflix.metacat.common.server.events.MetacatEventBus;
+import com.netflix.metacat.common.util.DataSourceManager;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+public class CommonModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ Config config = new ArchaiusConfigImpl();
+
+ bind(Config.class).toInstance(config);
+ bind(MetacatJson.class).toInstance(MetacatJsonLocator.INSTANCE);
+ bind(DeadEventHandler.class).asEagerSingleton();
+ bind(DataSourceManager.class).toInstance(DataSourceManager.get());
+ MetacatEventBus eventBus = createMetacatEventBus(config);
+ bind(MetacatEventBus.class).toInstance(eventBus);
+ bindListener(Matchers.any(), new TypeListener() {
+ public void hear(TypeLiteral typeLiteral, TypeEncounter typeEncounter) {
+ typeEncounter.register((InjectionListener) eventBus::register);
+ }
+ });
+
+ // Injecting statics is a bad pattern and should be avoided, but I am doing it as a first step to allow
+ // us to remove the hard coded username.
+ binder().requestStaticInjection(Lookup.class, TagItem.class);
+ }
+
+ protected MetacatEventBus createMetacatEventBus(Config config) {
+ ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("metacat-event-pool-%d").build();
+ int threadCount = config.getEventBusThreadCount();
+ return new MetacatEventBus("metacat-event-bus", Executors.newFixedThreadPool(threadCount, threadFactory));
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/Config.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/Config.java
new file mode 100644
index 000000000..2a4523f90
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/Config.java
@@ -0,0 +1,25 @@
+package com.netflix.metacat.common.server;
+
+public interface Config {
+ String getDefaultTypeConverter();
+ String getElasticSearchClusterName();
+ String getElasticSearchClusterNodes();
+ int getElasticSearchClusterPort();
+ int getElasticSearchScrollFetchSize();
+ int getElasticSearchScrollTimeout();
+ String getElasticSearchRefreshExcludeDatabases();
+ String getElasticSearchRefreshIncludeCatalogs();
+ String getElasticSearchRefreshIncludeDatabases();
+ String getElasticSearchRefreshPartitionsIncludeCatalogs();
+ int getElasticSearchThresholdUnmarkedDatabasesDelete();
+ int getElasticSearchThresholdUnmarkedTablesDelete();
+ int getEventBusExecutorThreadCount();
+ int getEventBusThreadCount();
+ String getHivePartitionWhitelistPattern();
+ String getLookupServiceUserAdmin();
+ String getMetacatVersion();
+ String getPluginConfigLocation();
+ String getTagServiceUserAdmin();
+ boolean isEpochInSeconds();
+ boolean isUsePigTypes();
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/DeadEventHandler.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/DeadEventHandler.java
new file mode 100644
index 000000000..5fb8c4306
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/DeadEventHandler.java
@@ -0,0 +1,22 @@
+package com.netflix.metacat.common.server.events;
+
+import com.google.common.eventbus.AllowConcurrentEvents;
+import com.google.common.eventbus.DeadEvent;
+import com.google.common.eventbus.Subscribe;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Singleton;
+
+@Singleton
+public class DeadEventHandler {
+ private static final Logger log = LoggerFactory.getLogger(DeadEventHandler.class);
+
+ @Subscribe
+ @AllowConcurrentEvents
+ public void logDeadEvent(DeadEvent event) {
+ Object sourceEvent = event.getEvent();
+ Object source = event.getSource();
+ log.debug("Unhandled event: {} from source: {}", sourceEvent, source);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateDatabasePostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateDatabasePostEvent.java
new file mode 100644
index 000000000..d636e8987
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateDatabasePostEvent.java
@@ -0,0 +1,38 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.dto.DatabaseDto;
+
+import java.util.Objects;
+
+public class MetacatCreateDatabasePostEvent extends MetacatEvent {
+ private final DatabaseDto dto;
+
+ public MetacatCreateDatabasePostEvent(DatabaseDto dto, MetacatContext metacatContext) {
+ super( dto!=null?dto.getName():null, metacatContext);
+ this.dto = dto;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatCreateDatabasePostEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatCreateDatabasePostEvent that = (MetacatCreateDatabasePostEvent) o;
+ return Objects.equals(dto, that.dto);
+ }
+
+ public DatabaseDto getDto() {
+ return dto;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(dto);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatCreateDatabasePostEvent{" + "dto=" + dto + '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateDatabasePreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateDatabasePreEvent.java
new file mode 100644
index 000000000..936d6066b
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateDatabasePreEvent.java
@@ -0,0 +1,10 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+public class MetacatCreateDatabasePreEvent extends MetacatEvent {
+ public MetacatCreateDatabasePreEvent(QualifiedName name, MetacatContext metacatContext) {
+ super(name, metacatContext);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateMViewPostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateMViewPostEvent.java
new file mode 100644
index 000000000..4b69191cb
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateMViewPostEvent.java
@@ -0,0 +1,56 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.dto.TableDto;
+
+import java.util.Objects;
+
+public class MetacatCreateMViewPostEvent extends MetacatEvent {
+ private final TableDto dto;
+ private final String filter;
+ private final Boolean snapshot;
+
+ public MetacatCreateMViewPostEvent(TableDto dto, Boolean snapshot, String filter, MetacatContext metacatContext) {
+ super( dto!=null?dto.getName():null, metacatContext);
+ this.dto = dto;
+ this.snapshot = snapshot;
+ this.filter = filter;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatCreateMViewPostEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatCreateMViewPostEvent that = (MetacatCreateMViewPostEvent) o;
+ return Objects.equals(dto, that.dto) &&
+ Objects.equals(snapshot, that.snapshot) &&
+ Objects.equals(filter, that.filter);
+ }
+
+ public TableDto getDto() {
+ return dto;
+ }
+
+ public String getFilter() {
+ return filter;
+ }
+
+ public Boolean getSnapshot() {
+ return snapshot;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(dto, snapshot, filter);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatCreateMViewPostEvent{" +
+ "dto=" + dto +
+ ", snapshot=" + snapshot +
+ ", filter='" + filter + '\'' +
+ '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateMViewPreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateMViewPreEvent.java
new file mode 100644
index 000000000..849107978
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateMViewPreEvent.java
@@ -0,0 +1,48 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+import java.util.Objects;
+
+public class MetacatCreateMViewPreEvent extends MetacatEvent {
+ private final String filter;
+ private final Boolean snapshot;
+
+ public MetacatCreateMViewPreEvent(QualifiedName name, Boolean snapshot, String filter, MetacatContext metacatContext) {
+ super( name, metacatContext);
+ this.snapshot = snapshot;
+ this.filter = filter;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatCreateMViewPreEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatCreateMViewPreEvent that = (MetacatCreateMViewPreEvent) o;
+ return Objects.equals(snapshot, that.snapshot) &&
+ Objects.equals(filter, that.filter);
+ }
+
+ public String getFilter() {
+ return filter;
+ }
+
+ public Boolean getSnapshot() {
+ return snapshot;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(snapshot, filter);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatCreateMViewPreEvent{" +
+ ", snapshot=" + snapshot +
+ ", filter='" + filter + '\'' +
+ '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateTablePostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateTablePostEvent.java
new file mode 100644
index 000000000..bfc18aab9
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateTablePostEvent.java
@@ -0,0 +1,39 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.dto.TableDto;
+
+import java.util.Objects;
+
+public class MetacatCreateTablePostEvent extends MetacatEvent {
+ private final TableDto dto;
+
+ public MetacatCreateTablePostEvent(TableDto dto, MetacatContext metacatContext) {
+ super( dto!=null?dto.getName():null, metacatContext);
+ this.dto = dto;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatCreateTablePostEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatCreateTablePostEvent that = (MetacatCreateTablePostEvent) o;
+ return Objects.equals(dto, that.dto);
+ }
+
+ public TableDto getDto() {
+
+ return dto;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(dto);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatCreateTablePostEvent{dto=" + dto + '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateTablePreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateTablePreEvent.java
new file mode 100644
index 000000000..87782adf7
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatCreateTablePreEvent.java
@@ -0,0 +1,11 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+public class MetacatCreateTablePreEvent extends MetacatEvent {
+
+ public MetacatCreateTablePreEvent(QualifiedName name, MetacatContext metacatContext) {
+ super(name, metacatContext);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteDatabasePostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteDatabasePostEvent.java
new file mode 100644
index 000000000..d8ff5fb9e
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteDatabasePostEvent.java
@@ -0,0 +1,39 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.dto.DatabaseDto;
+
+import java.util.Objects;
+
+public class MetacatDeleteDatabasePostEvent extends MetacatEvent {
+ private final DatabaseDto dto;
+
+ public MetacatDeleteDatabasePostEvent(DatabaseDto dto, MetacatContext metacatContext) {
+ super( dto!=null?dto.getName():null, metacatContext);
+ this.dto = dto;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatDeleteDatabasePostEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatDeleteDatabasePostEvent that = (MetacatDeleteDatabasePostEvent) o;
+ return Objects.equals(dto, that.dto);
+ }
+
+ public DatabaseDto getDto() {
+
+ return dto;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(dto);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatDeleteDatabasePostEvent{dto=" + dto + '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteDatabasePreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteDatabasePreEvent.java
new file mode 100644
index 000000000..0fcdb686f
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteDatabasePreEvent.java
@@ -0,0 +1,39 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.dto.DatabaseDto;
+
+import java.util.Objects;
+
+public class MetacatDeleteDatabasePreEvent extends MetacatEvent {
+ private final DatabaseDto dto;
+
+ public MetacatDeleteDatabasePreEvent(DatabaseDto dto, MetacatContext metacatContext) {
+ super( dto!=null?dto.getName():null, metacatContext);
+ this.dto = dto;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatDeleteDatabasePreEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatDeleteDatabasePreEvent that = (MetacatDeleteDatabasePreEvent) o;
+ return Objects.equals(dto, that.dto);
+ }
+
+ public DatabaseDto getDto() {
+
+ return dto;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(dto);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatDeleteDatabasePreEvent{dto=" + dto + '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteMViewPartitionPostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteMViewPartitionPostEvent.java
new file mode 100644
index 000000000..08dc7f92b
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteMViewPartitionPostEvent.java
@@ -0,0 +1,41 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+import java.util.List;
+import java.util.Objects;
+
+public class MetacatDeleteMViewPartitionPostEvent extends MetacatEvent {
+ private final List partitionIds;
+
+ public MetacatDeleteMViewPartitionPostEvent(QualifiedName name, List partitionIds, MetacatContext metacatContext) {
+ super(name, metacatContext);
+ this.partitionIds = partitionIds;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatDeleteMViewPartitionPostEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatDeleteMViewPartitionPostEvent that = (MetacatDeleteMViewPartitionPostEvent) o;
+ return Objects.equals(partitionIds, that.partitionIds);
+ }
+
+ public List getPartitionIds() {
+ return partitionIds;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(partitionIds);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatDeleteMViewPartitionPostEvent{" +
+ ", partitions=" + partitionIds +
+ '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteMViewPartitionPreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteMViewPartitionPreEvent.java
new file mode 100644
index 000000000..da9f6c73d
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteMViewPartitionPreEvent.java
@@ -0,0 +1,41 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+import java.util.List;
+import java.util.Objects;
+
+public class MetacatDeleteMViewPartitionPreEvent extends MetacatEvent {
+ private final List partitionIds;
+
+ public MetacatDeleteMViewPartitionPreEvent(QualifiedName name, List partitionIds, MetacatContext metacatContext) {
+ super( name, metacatContext);
+ this.partitionIds = partitionIds;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatDeleteMViewPartitionPreEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatDeleteMViewPartitionPreEvent that = (MetacatDeleteMViewPartitionPreEvent) o;
+ return Objects.equals(partitionIds, that.partitionIds);
+ }
+
+ public List getPartitionIds() {
+ return partitionIds;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(partitionIds);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatDeleteMViewPartitionPreEvent{" +
+ ", partitions=" + partitionIds +
+ '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteMViewPostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteMViewPostEvent.java
new file mode 100644
index 000000000..e293d0750
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteMViewPostEvent.java
@@ -0,0 +1,38 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.dto.TableDto;
+
+import java.util.Objects;
+
+public class MetacatDeleteMViewPostEvent extends MetacatEvent {
+ private final TableDto dto;
+
+ public MetacatDeleteMViewPostEvent(TableDto dto, MetacatContext metacatContext) {
+ super( dto!=null?dto.getName():null, metacatContext);
+ this.dto = dto;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatDeleteMViewPostEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatDeleteMViewPostEvent that = (MetacatDeleteMViewPostEvent) o;
+ return Objects.equals(dto, that.dto);
+ }
+
+ public TableDto getDto() {
+ return dto;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(dto);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatDeleteMViewPostEvent{dto=" + dto + '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteMViewPreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteMViewPreEvent.java
new file mode 100644
index 000000000..5f49fbf25
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteMViewPreEvent.java
@@ -0,0 +1,11 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+public class MetacatDeleteMViewPreEvent extends MetacatEvent {
+
+ public MetacatDeleteMViewPreEvent(QualifiedName name, MetacatContext metacatContext) {
+ super( name, metacatContext);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteTablePartitionPostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteTablePartitionPostEvent.java
new file mode 100644
index 000000000..99b819dee
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteTablePartitionPostEvent.java
@@ -0,0 +1,41 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+import java.util.List;
+import java.util.Objects;
+
+public class MetacatDeleteTablePartitionPostEvent extends MetacatEvent {
+ private final List partitionIds;
+
+ public MetacatDeleteTablePartitionPostEvent(QualifiedName name, List partitionIds, MetacatContext metacatContext) {
+ super( name, metacatContext);
+ this.partitionIds = partitionIds;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatDeleteTablePartitionPostEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatDeleteTablePartitionPostEvent that = (MetacatDeleteTablePartitionPostEvent) o;
+ return Objects.equals(partitionIds, that.partitionIds);
+ }
+
+ public List getPartitionIds() {
+ return partitionIds;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(partitionIds);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatDeleteTablePartitionPostEvent{" +
+ ", partitions=" + partitionIds +
+ '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteTablePartitionPreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteTablePartitionPreEvent.java
new file mode 100644
index 000000000..40460a579
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteTablePartitionPreEvent.java
@@ -0,0 +1,40 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+import java.util.List;
+import java.util.Objects;
+
+public class MetacatDeleteTablePartitionPreEvent extends MetacatEvent {
+ private final List partitionIds;
+
+ public MetacatDeleteTablePartitionPreEvent(QualifiedName name, List partitionIds, MetacatContext metacatContext) {
+ super( name, metacatContext);
+ this.partitionIds = partitionIds;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatDeleteTablePartitionPreEvent)) return false;
+ MetacatDeleteTablePartitionPreEvent that = (MetacatDeleteTablePartitionPreEvent) o;
+ return Objects.equals(partitionIds, that.partitionIds);
+ }
+
+ public List getPartitionIds() {
+ return partitionIds;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(partitionIds);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatDeleteTablePartitionPreEvent{" +
+ ", partitions=" + partitionIds +
+ '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteTablePostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteTablePostEvent.java
new file mode 100644
index 000000000..32664f0fe
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteTablePostEvent.java
@@ -0,0 +1,39 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.dto.TableDto;
+
+import java.util.Objects;
+
+public class MetacatDeleteTablePostEvent extends MetacatEvent {
+ private final TableDto dto;
+
+ public MetacatDeleteTablePostEvent(TableDto dto, MetacatContext metacatContext) {
+ super( dto!=null?dto.getName():null, metacatContext);
+ this.dto = dto;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatDeleteTablePostEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatDeleteTablePostEvent that = (MetacatDeleteTablePostEvent) o;
+ return Objects.equals(dto, that.dto);
+ }
+
+ public TableDto getDto() {
+
+ return dto;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(dto);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatDeleteTablePostEvent{dto=" + dto + '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteTablePreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteTablePreEvent.java
new file mode 100644
index 000000000..034ef8a5d
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatDeleteTablePreEvent.java
@@ -0,0 +1,11 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+public class MetacatDeleteTablePreEvent extends MetacatEvent {
+
+ public MetacatDeleteTablePreEvent(QualifiedName name, MetacatContext metacatContext) {
+ super( name, metacatContext);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatEvent.java
new file mode 100644
index 000000000..5776eea61
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatEvent.java
@@ -0,0 +1,42 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+import java.util.Objects;
+
+public class MetacatEvent {
+ private final QualifiedName name;
+ private final MetacatContext metacatContext;
+
+ public MetacatEvent(QualifiedName name, MetacatContext metacatContext) {
+ this.name = name;
+ this.metacatContext = metacatContext;
+ }
+
+ public QualifiedName getName() {
+ return name;
+ }
+
+ public MetacatContext getMetacatContext() {
+ return metacatContext;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatEvent)) return false;
+ MetacatEvent that = (MetacatEvent) o;
+ return Objects.equals(name, that.name) && Objects.equals(metacatContext, that.metacatContext);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, metacatContext);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatEvent{" + "name=" + name + ", metacatContext=" + metacatContext + '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatEventBus.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatEventBus.java
new file mode 100644
index 000000000..547af2897
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatEventBus.java
@@ -0,0 +1,21 @@
+package com.netflix.metacat.common.server.events;
+
+import com.google.common.eventbus.AsyncEventBus;
+import com.google.common.eventbus.SubscriberExceptionHandler;
+
+import java.util.concurrent.Executor;
+
+public class MetacatEventBus extends AsyncEventBus {
+ public MetacatEventBus(String identifier, Executor executor) {
+ super(identifier, executor);
+ }
+
+ public MetacatEventBus(Executor executor,
+ SubscriberExceptionHandler subscriberExceptionHandler) {
+ super(executor, subscriberExceptionHandler);
+ }
+
+ public MetacatEventBus(Executor executor) {
+ super(executor);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameDatabasePostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameDatabasePostEvent.java
new file mode 100644
index 000000000..3edafed80
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameDatabasePostEvent.java
@@ -0,0 +1,11 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+public class MetacatRenameDatabasePostEvent extends MetacatEvent {
+ public MetacatRenameDatabasePostEvent(QualifiedName name,
+ MetacatContext metacatContext) {
+ super(name, metacatContext);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameDatabasePreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameDatabasePreEvent.java
new file mode 100644
index 000000000..842886005
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameDatabasePreEvent.java
@@ -0,0 +1,11 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+public class MetacatRenameDatabasePreEvent extends MetacatEvent {
+ public MetacatRenameDatabasePreEvent(QualifiedName name,
+ MetacatContext metacatContext) {
+ super(name, metacatContext);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameMViewPostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameMViewPostEvent.java
new file mode 100644
index 000000000..ebb0258a9
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameMViewPostEvent.java
@@ -0,0 +1,11 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+public class MetacatRenameMViewPostEvent extends MetacatEvent {
+ public MetacatRenameMViewPostEvent(QualifiedName name,
+ MetacatContext metacatContext) {
+ super(name, metacatContext);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameMViewPreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameMViewPreEvent.java
new file mode 100644
index 000000000..812bad79f
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameMViewPreEvent.java
@@ -0,0 +1,11 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+public class MetacatRenameMViewPreEvent extends MetacatEvent {
+ public MetacatRenameMViewPreEvent(QualifiedName name,
+ MetacatContext metacatContext) {
+ super(name, metacatContext);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameTablePostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameTablePostEvent.java
new file mode 100644
index 000000000..0c1822fd4
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameTablePostEvent.java
@@ -0,0 +1,42 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+import com.netflix.metacat.common.dto.TableDto;
+
+import java.util.Objects;
+
+public class MetacatRenameTablePostEvent extends MetacatEvent {
+ private final TableDto dto;
+
+ public MetacatRenameTablePostEvent(QualifiedName oldName, TableDto dto, MetacatContext metacatContext) {
+ super(oldName, metacatContext);
+ this.dto = dto;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatRenameTablePostEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatRenameTablePostEvent that = (MetacatRenameTablePostEvent) o;
+ return Objects.equals(dto, that.dto);
+ }
+
+ public TableDto getDto() {
+
+ return dto;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(dto);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatRenameTablePostEvent{" +
+ "dto=" + dto +
+ '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameTablePreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameTablePreEvent.java
new file mode 100644
index 000000000..a2b7a5244
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatRenameTablePreEvent.java
@@ -0,0 +1,41 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+import java.util.Objects;
+
+public class MetacatRenameTablePreEvent extends MetacatEvent {
+ private final QualifiedName newName;
+
+ public MetacatRenameTablePreEvent(QualifiedName newName, QualifiedName oldName, MetacatContext metacatContext) {
+ super(oldName, metacatContext);
+ this.newName = newName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatRenameTablePreEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatRenameTablePreEvent that = (MetacatRenameTablePreEvent) o;
+ return Objects.equals(newName, that.newName);
+ }
+
+ public QualifiedName getNewName() {
+
+ return newName;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(newName);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatRenameTablePreEvent{" +
+ "newName=" + newName +
+ '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatSaveMViewPartitionPostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatSaveMViewPartitionPostEvent.java
new file mode 100644
index 000000000..94a7de89d
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatSaveMViewPartitionPostEvent.java
@@ -0,0 +1,42 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+import com.netflix.metacat.common.dto.PartitionDto;
+
+import java.util.List;
+import java.util.Objects;
+
+public class MetacatSaveMViewPartitionPostEvent extends MetacatEvent {
+ private final List partitions;
+
+ public MetacatSaveMViewPartitionPostEvent(QualifiedName name, List partitions, MetacatContext metacatContext) {
+ super( name, metacatContext);
+ this.partitions = partitions;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatSaveMViewPartitionPostEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatSaveMViewPartitionPostEvent that = (MetacatSaveMViewPartitionPostEvent) o;
+ return Objects.equals(partitions, that.partitions);
+ }
+
+ public List getPartitions() {
+ return partitions;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(partitions);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatSaveMViewPartitionPostEvent{" +
+ "partitions=" + partitions +
+ '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatSaveMViewPartitionPreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatSaveMViewPartitionPreEvent.java
new file mode 100644
index 000000000..87b993988
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatSaveMViewPartitionPreEvent.java
@@ -0,0 +1,42 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+import com.netflix.metacat.common.dto.PartitionDto;
+
+import java.util.List;
+import java.util.Objects;
+
+public class MetacatSaveMViewPartitionPreEvent extends MetacatEvent {
+ private final List partitions;
+
+ public MetacatSaveMViewPartitionPreEvent(QualifiedName name, List partitions, MetacatContext metacatContext) {
+ super( name, metacatContext);
+ this.partitions = partitions;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+
+ if (this == o) return true;
+ if (!(o instanceof MetacatSaveMViewPartitionPreEvent)) return false;
+ MetacatSaveMViewPartitionPreEvent that = (MetacatSaveMViewPartitionPreEvent) o;
+ return Objects.equals(partitions, that.partitions);
+ }
+
+ public List getPartitions() {
+ return partitions;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(partitions);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatSaveMViewPartitionPreEvent{" +
+ "partitions=" + partitions +
+ '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatSaveTablePartitionPostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatSaveTablePartitionPostEvent.java
new file mode 100644
index 000000000..3f6326910
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatSaveTablePartitionPostEvent.java
@@ -0,0 +1,42 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+import com.netflix.metacat.common.dto.PartitionDto;
+
+import java.util.List;
+import java.util.Objects;
+
+public class MetacatSaveTablePartitionPostEvent extends MetacatEvent {
+ private final List partitions;
+
+ public MetacatSaveTablePartitionPostEvent(QualifiedName name, List partitions, MetacatContext metacatContext) {
+ super( name, metacatContext);
+ this.partitions = partitions;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatSaveTablePartitionPostEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatSaveTablePartitionPostEvent that = (MetacatSaveTablePartitionPostEvent) o;
+ return Objects.equals(partitions, that.partitions);
+ }
+
+ public List getPartitions() {
+ return partitions;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(partitions);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatSaveTablePartitionPostEvent{" +
+ "partitions=" + partitions +
+ '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatSaveTablePartitionPreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatSaveTablePartitionPreEvent.java
new file mode 100644
index 000000000..2571bf633
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatSaveTablePartitionPreEvent.java
@@ -0,0 +1,42 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+import com.netflix.metacat.common.dto.PartitionDto;
+
+import java.util.List;
+import java.util.Objects;
+
+public class MetacatSaveTablePartitionPreEvent extends MetacatEvent {
+ private final List partitions;
+
+ public MetacatSaveTablePartitionPreEvent(QualifiedName name, List partitions, MetacatContext metacatContext) {
+ super(name, metacatContext);
+ this.partitions = partitions;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatSaveTablePartitionPreEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatSaveTablePartitionPreEvent that = (MetacatSaveTablePartitionPreEvent) o;
+ return Objects.equals(partitions, that.partitions);
+ }
+
+ public List getPartitions() {
+ return partitions;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(partitions);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatSaveTablePartitionPreEvent{" +
+ "partitions=" + partitions +
+ '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateDatabasePostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateDatabasePostEvent.java
new file mode 100644
index 000000000..3813a1a32
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateDatabasePostEvent.java
@@ -0,0 +1,11 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+public class MetacatUpdateDatabasePostEvent extends MetacatEvent {
+ public MetacatUpdateDatabasePostEvent(QualifiedName name,
+ MetacatContext metacatContext) {
+ super(name, metacatContext);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateDatabasePreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateDatabasePreEvent.java
new file mode 100644
index 000000000..5a3db295c
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateDatabasePreEvent.java
@@ -0,0 +1,11 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+
+public class MetacatUpdateDatabasePreEvent extends MetacatEvent {
+ public MetacatUpdateDatabasePreEvent(QualifiedName name,
+ MetacatContext metacatContext) {
+ super(name, metacatContext);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateMViewPostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateMViewPostEvent.java
new file mode 100644
index 000000000..65f7fd9ed
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateMViewPostEvent.java
@@ -0,0 +1,39 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.dto.TableDto;
+
+import java.util.Objects;
+
+public class MetacatUpdateMViewPostEvent extends MetacatEvent {
+ private final TableDto dto;
+
+ public MetacatUpdateMViewPostEvent(TableDto dto, MetacatContext metacatContext) {
+ super( dto!=null?dto.getName():null, metacatContext);
+ this.dto = dto;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatUpdateMViewPostEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatUpdateMViewPostEvent that = (MetacatUpdateMViewPostEvent) o;
+ return Objects.equals(dto, that.dto);
+ }
+
+ public TableDto getDto() {
+
+ return dto;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(dto);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatUpdateMViewPostEvent{dto=" + dto + '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateMViewPreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateMViewPreEvent.java
new file mode 100644
index 000000000..09e03a56f
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateMViewPreEvent.java
@@ -0,0 +1,42 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+import com.netflix.metacat.common.dto.TableDto;
+
+import java.util.Objects;
+
+public class MetacatUpdateMViewPreEvent extends MetacatEvent {
+ private final TableDto dto;
+
+ public MetacatUpdateMViewPreEvent(QualifiedName name, TableDto dto, MetacatContext metacatContext) {
+ super(name, metacatContext);
+ this.dto = dto;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatUpdateMViewPreEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatUpdateMViewPreEvent that = (MetacatUpdateMViewPreEvent) o;
+ return Objects.equals(dto, that.dto);
+ }
+
+ public TableDto getDto() {
+
+ return dto;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(dto);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatUpdateMViewPreEvent{" +
+ "dto=" + dto +
+ '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateTablePostEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateTablePostEvent.java
new file mode 100644
index 000000000..2bbb423c2
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateTablePostEvent.java
@@ -0,0 +1,47 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+import com.netflix.metacat.common.dto.TableDto;
+
+import java.util.Objects;
+
+public class MetacatUpdateTablePostEvent extends MetacatEvent {
+ private TableDto dto;
+
+ public MetacatUpdateTablePostEvent(TableDto dto, MetacatContext metacatContext) {
+ super(dto!=null?dto.getName():null, metacatContext);
+ this.dto = dto;
+ }
+
+ public MetacatUpdateTablePostEvent(QualifiedName name, MetacatContext metacatContext) {
+ super(name, metacatContext);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatUpdateTablePostEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatUpdateTablePostEvent that = (MetacatUpdateTablePostEvent) o;
+ return Objects.equals(dto, that.dto);
+ }
+
+ public TableDto getDto() {
+ return dto;
+ }
+
+ public void setDto(TableDto dto) {
+ this.dto = dto;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash(dto);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatUpdateTablePostEvent{dto=" + dto + '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateTablePreEvent.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateTablePreEvent.java
new file mode 100644
index 000000000..a20d017b7
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/events/MetacatUpdateTablePreEvent.java
@@ -0,0 +1,42 @@
+package com.netflix.metacat.common.server.events;
+
+import com.netflix.metacat.common.MetacatContext;
+import com.netflix.metacat.common.QualifiedName;
+import com.netflix.metacat.common.dto.TableDto;
+
+import java.util.Objects;
+
+public class MetacatUpdateTablePreEvent extends MetacatEvent {
+ private final TableDto table;
+
+ public MetacatUpdateTablePreEvent(QualifiedName name, TableDto table, MetacatContext metacatContext) {
+ super(name, metacatContext);
+ this.table = table;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MetacatUpdateTablePreEvent)) return false;
+ if (!super.equals(o)) return false;
+ MetacatUpdateTablePreEvent that = (MetacatUpdateTablePreEvent) o;
+ return Objects.equals(table, that.table);
+ }
+
+ public TableDto getTable() {
+
+ return table;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Objects.hash( table);
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatUpdateTablePreEvent{" +
+ ", table=" + table +
+ '}';
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/BaseUserMetadataService.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/BaseUserMetadataService.java
new file mode 100644
index 000000000..385535e42
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/BaseUserMetadataService.java
@@ -0,0 +1,67 @@
+package com.netflix.metacat.common.usermetadata;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.netflix.metacat.common.dto.HasDataMetadata;
+import com.netflix.metacat.common.dto.HasDefinitionMetadata;
+import com.netflix.metacat.common.dto.HasMetadata;
+
+import java.util.Optional;
+
+/**
+ * Created by amajumdar on 4/13/15.
+ */
+public abstract class BaseUserMetadataService implements UserMetadataService{
+ public void saveMetadata(String userId, HasMetadata holder, boolean merge) {
+ if (holder instanceof HasDefinitionMetadata) {
+ HasDefinitionMetadata defDto = (HasDefinitionMetadata) holder;
+
+ // If the user is updating the definition metadata do a merge on the existing metadata
+ ObjectNode newMetadata = defDto.getDefinitionMetadata();
+ if (newMetadata != null) {
+ HasDefinitionMetadata definitionDto = (HasDefinitionMetadata) holder;
+ saveDefinitionMetadata(definitionDto.getDefinitionName(), userId, Optional.of(newMetadata), merge);
+ }
+ }
+
+ if (holder instanceof HasDataMetadata) {
+ HasDataMetadata dataDto = (HasDataMetadata) holder;
+
+ // If the user is updating the data metadata and a separate data location exists,
+ // do a merge on the existing metadata
+ ObjectNode newMetadata = dataDto.getDataMetadata();
+ if (newMetadata != null && dataDto.isDataExternal()) {
+ saveDataMetadata(dataDto.getDataUri(), userId, Optional.of(newMetadata), merge);
+ }
+ }
+ }
+
+ public void populateMetadata(HasMetadata holder) {
+ Optional metadata = Optional.empty();
+ if (holder instanceof HasDataMetadata) {
+ HasDataMetadata dataDto = (HasDataMetadata) holder;
+ if (dataDto.isDataExternal()) {
+ metadata = getDataMetadata(dataDto.getDataUri());
+ }
+ }
+ Optional definitionMetadata = Optional.empty();
+ if (holder instanceof HasDefinitionMetadata) {
+ HasDefinitionMetadata definitionDto = (HasDefinitionMetadata) holder;
+ definitionMetadata = getDefinitionMetadata(definitionDto.getDefinitionName());
+ }
+ populateMetadata( holder, definitionMetadata.orElse(null), metadata.orElse(null));
+ }
+
+ public void populateMetadata(HasMetadata holder, ObjectNode definitionMetadata, ObjectNode dataMetadata) {
+ if (holder instanceof HasDefinitionMetadata) {
+ HasDefinitionMetadata defDto = (HasDefinitionMetadata) holder;
+ defDto.setDefinitionMetadata(definitionMetadata);
+ }
+
+ if (holder instanceof HasDataMetadata) {
+ HasDataMetadata dataDto = (HasDataMetadata) holder;
+ if (dataDto.isDataExternal()) {
+ dataDto.setDataMetadata(dataMetadata);
+ }
+ }
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/LookupService.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/LookupService.java
new file mode 100644
index 000000000..0efbbc8ae
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/LookupService.java
@@ -0,0 +1,56 @@
+package com.netflix.metacat.common.usermetadata;
+
+import com.netflix.metacat.common.model.Lookup;
+
+import java.util.Set;
+
+/**
+ * Created by amajumdar on 7/6/15.
+ */
+public interface LookupService {
+ /**
+ * Returns the lookup for the given name
+ * @param name lookup name
+ * @return lookup
+ */
+ Lookup get(String name);
+ /**
+ * Returns the value of the lookup name
+ * @param name lookup name
+ * @return scalar lookup value
+ */
+ String getValue(String name);
+ /**
+ * Returns the list of values of the lookup name
+ * @param name lookup name
+ * @return list of lookup values
+ */
+ Set getValues(String name);
+ /**
+ * Returns the list of values of the lookup name
+ * @param lookupId lookup id
+ * @return list of lookup values
+ */
+ Set getValues(Long lookupId);
+ /**
+ * Saves the lookup value
+ * @param name lookup name
+ * @param values multiple values
+ * @return
+ */
+ Lookup setValues(String name, Set values);
+ /**
+ * Saves the lookup value
+ * @param name lookup name
+ * @param values multiple values
+ * @return
+ */
+ Lookup addValues(String name, Set values);
+ /**
+ * Saves the lookup value
+ * @param name lookup name
+ * @param value lookup value
+ * @return
+ */
+ Lookup setValue(String name, String value);
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/TagService.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/TagService.java
new file mode 100644
index 000000000..9d0d71935
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/TagService.java
@@ -0,0 +1,87 @@
+package com.netflix.metacat.common.usermetadata;
+
+import com.netflix.metacat.common.QualifiedName;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Created by amajumdar on 6/29/15.
+ */
+public interface TagService {
+ /**
+ * Returns the list of tags
+ * @return list of tag names
+ */
+ Set getTags();
+
+ /**
+ * Returns the list of QualifiedName
of items that are tagged by the given includeTags
and
+ * do not contain the given excludeTags
+ * @param includeTags include items that contain tags
+ * @param excludeTags include items that do not contain tags
+ * @param sourceName catalog/source name
+ * @param databaseName database name
+ * @param tableName table name
+ * @return list of qualified names of the items
+ */
+ List list(
+ Set includeTags,
+ Set excludeTags,
+ String sourceName,
+ String databaseName,
+ String tableName);
+
+ /**
+ * Returns the list of QualifiedName
of items that have tags containing the given tag text.
+ * @param tag partial text of a tag
+ * @param sourceName source/catalog name
+ * @param databaseName database name
+ * @param tableName table name
+ * @return list of qualified names of the items
+ */
+ List search(
+ String tag,
+ String sourceName,
+ String databaseName,
+ String tableName);
+
+ /**
+ * Tags the given table with the given tags
+ * @param qualifiedName, table name
+ * @param tags list of tags
+ * @return return the complete list of tags associated with the table
+ */
+ Set setTableTags(
+ QualifiedName qualifiedName,
+ Set tags,
+ boolean updateUserMetadata);
+
+ /**
+ * Removes the tags from the given table
+ * @param qualifiedName table name
+ * @param deleteAll if true, will delete all tags associated with the given table
+ * @param tags list of tags to be removed for the given table
+ */
+ Void removeTableTags(
+ QualifiedName qualifiedName,
+ Boolean deleteAll,
+ Set tags,
+ boolean updateUserMetadata);
+
+ /**
+ * Delete the tag item along with its associated tags.
+ * @param name table name
+ * @return null
+ */
+ Void delete(QualifiedName name,
+ boolean updateUserMetadata);
+
+ /**
+ * Renames the tag item name with the new table name
+ * @param name table qualified name
+ * @param newTableName new table name
+ * @return null
+ */
+ Void rename(QualifiedName name, String newTableName);
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/UserMetadataService.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/UserMetadataService.java
new file mode 100644
index 000000000..fcb87463f
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/UserMetadataService.java
@@ -0,0 +1,60 @@
+package com.netflix.metacat.common.usermetadata;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.netflix.metacat.common.QualifiedName;
+import com.netflix.metacat.common.dto.DefinitionMetadataDto;
+import com.netflix.metacat.common.dto.HasMetadata;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+public interface UserMetadataService {
+ String METACAT_USERMETADATA_CONFIG_LOCATION = "metacat.usermetadata.config.location";
+
+ void deleteDataMetadatas(@Nonnull List uris);
+
+ void deleteDefinitionMetadatas(@Nonnull List names);
+
+ void deleteMetadatas(List holders, boolean force);
+
+ @Nonnull
+ Optional getDataMetadata(@Nonnull String uri);
+
+ @Nonnull
+ Map getDataMetadataMap(@Nonnull List uris);
+
+ @Nonnull
+ Optional getDefinitionMetadata(@Nonnull QualifiedName name);
+
+ @Nonnull
+ Map getDefinitionMetadataMap(@Nonnull List names);
+
+ void saveDataMetadata(@Nonnull String uri, @Nonnull String userId, @Nonnull Optional metadata, boolean merge);
+
+ void saveDefinitionMetadata(@Nonnull QualifiedName name, @Nonnull String userId,
+ @Nonnull Optional metadata, boolean merge);
+
+ void saveMetadata(String userId, HasMetadata holder, boolean merge);
+
+ void populateMetadata(HasMetadata holder);
+
+ void populateMetadata(HasMetadata holder, ObjectNode definitionMetadata, ObjectNode dataMetadata);
+
+ int renameDataMetadataKey(@Nonnull String oldUri, @Nonnull String newUri);
+
+ int renameDefinitionMetadataKey(@Nonnull QualifiedName oldName, @Nonnull QualifiedName newName);
+
+ void start() throws Exception;
+
+ void stop() throws Exception;
+
+ void saveMetadatas(String user, List extends HasMetadata> holders, boolean merge);
+
+ List searchDefinitionMetadatas(Set propertyNames, String type, String name
+ , String sortBy, String sortOrder, Integer offset, Integer limit);
+
+ List searchByOwners(Set owners);
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/UserMetadataServiceException.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/UserMetadataServiceException.java
new file mode 100644
index 000000000..1543be754
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/usermetadata/UserMetadataServiceException.java
@@ -0,0 +1,12 @@
+package com.netflix.metacat.common.usermetadata;
+
+import java.sql.SQLException;
+
+/**
+ * Created by amajumdar on 3/16/16.
+ */
+public class UserMetadataServiceException extends RuntimeException {
+ public UserMetadataServiceException(String m, Exception e) {
+ super(m, e);
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/util/DataSourceManager.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/util/DataSourceManager.java
new file mode 100644
index 000000000..e56b22d8d
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/util/DataSourceManager.java
@@ -0,0 +1,84 @@
+package com.netflix.metacat.common.util;
+
+import com.google.common.collect.Maps;
+import org.apache.tomcat.jdbc.pool.DataSourceFactory;
+import org.apache.tomcat.jdbc.pool.DataSourceProxy;
+
+import javax.annotation.PreDestroy;
+import javax.sql.DataSource;
+import java.sql.Driver;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Created by amajumdar on 4/7/15.
+ */
+public class DataSourceManager {
+ private static final String JDO_PREFIX = "javax.jdo.option.";
+ private Map dataSources = Maps.newConcurrentMap();
+ private static DataSourceManager instance = new DataSourceManager();
+
+ private DataSourceManager(){}
+ //
+ // This method has been provided so that it can be used in the connectors. We could have injected into the plugins.
+ //
+ public static DataSourceManager get(){
+ return instance;
+ }
+
+ public DataSourceManager load(String catalogName, Map properties){
+ if( dataSources.get(catalogName) == null){
+ createDataSource( catalogName, properties);
+ }
+ return this;
+ }
+
+ public DataSourceManager load(String catalogName, Properties properties){
+ if( dataSources.get(catalogName) == null){
+ createDataSource( catalogName, properties);
+ }
+ return this;
+ }
+
+ public DataSource get(String catalogName){
+ return dataSources.get(catalogName);
+ }
+
+ public Driver getDriver(String catalogName, Driver driver){
+ DataSource dataSource = get(catalogName);
+ return dataSource!=null? new JdbcDriver(driver, dataSource):driver;
+ }
+
+ private synchronized void createDataSource(String catalogName, Map props) {
+ if( dataSources.get(catalogName) == null) {
+ Properties dataSourceProperties = new Properties();
+ props.forEach((key, value) -> {
+ String prop = String.valueOf(key);
+ if (prop.startsWith(JDO_PREFIX)) {
+ dataSourceProperties.put(prop.substring(JDO_PREFIX.length()), value);
+ }
+ });
+ if( !dataSourceProperties.isEmpty()) {
+ try {
+ DataSource dataSource = new DataSourceFactory().createDataSource(dataSourceProperties);
+ dataSources.put(catalogName, dataSource);
+ } catch (Exception e) {
+ throw new RuntimeException(String.format("Failed to load the data source for catalog %s with error [%s]", catalogName, e.getMessage()), e);
+ }
+ }
+ }
+ }
+
+ @PreDestroy
+ public void close(){
+ Iterator iter = dataSources.values().iterator();
+ while(iter.hasNext()){
+ DataSourceProxy dataSource = (DataSourceProxy) iter.next();
+ if( dataSource != null) {
+ dataSource.close();
+ }
+ iter.remove();
+ }
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/util/JdbcDriver.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/util/JdbcDriver.java
new file mode 100644
index 000000000..cbb90542d
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/util/JdbcDriver.java
@@ -0,0 +1,60 @@
+package com.netflix.metacat.common.util;
+
+import com.google.common.base.Throwables;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverPropertyInfo;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+/**
+ * Created by amajumdar on 3/15/16.
+ */
+public class JdbcDriver implements Driver {
+ private DataSource datasource;
+ private Driver driver;
+
+ public JdbcDriver(Driver driver, DataSource datasource) {
+ this.driver = driver;
+ this.datasource = datasource;
+ }
+
+ @Override
+ public Connection connect(String url, Properties info) throws SQLException {
+ return datasource.getConnection();
+ }
+
+ @Override
+ public boolean acceptsURL(String url) throws SQLException {
+ return driver.acceptsURL(url);
+ }
+
+ @Override
+ public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
+ return driver.getPropertyInfo( url, info);
+ }
+
+ @Override
+ public int getMajorVersion() {
+ return driver.getMajorVersion();
+ }
+
+ @Override
+ public int getMinorVersion() {
+ return driver.getMinorVersion();
+ }
+
+ @Override
+ public boolean jdbcCompliant() {
+ return driver.jdbcCompliant();
+ }
+
+ @Override
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ return driver.getParentLogger();
+ }
+}
diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/util/MetacatContextManager.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/util/MetacatContextManager.java
new file mode 100644
index 000000000..603d68503
--- /dev/null
+++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/util/MetacatContextManager.java
@@ -0,0 +1,27 @@
+package com.netflix.metacat.common.util;
+
+import com.netflix.metacat.common.MetacatContext;
+
+/**
+ * Created by amajumdar on 8/3/15.
+ */
+public class MetacatContextManager {
+ private static InheritableThreadLocal context = new InheritableThreadLocal();
+
+ public static void removeContext() {
+ context.remove();
+ }
+
+ public static void setContext(MetacatContext context) {
+ MetacatContextManager.context.set(context);
+ }
+
+ public static MetacatContext getContext() {
+ MetacatContext result = context.get();
+ if(result == null) {
+ result = new MetacatContext(null, null, null, null, null);
+ setContext(result);
+ }
+ return result;
+ }
+}
diff --git a/metacat-common-server/src/test/groovy/com/netflix/metacat/common/partition/util/FilterPartitionSpec.groovy b/metacat-common-server/src/test/groovy/com/netflix/metacat/common/partition/util/FilterPartitionSpec.groovy
new file mode 100644
index 000000000..d33f16860
--- /dev/null
+++ b/metacat-common-server/src/test/groovy/com/netflix/metacat/common/partition/util/FilterPartitionSpec.groovy
@@ -0,0 +1,56 @@
+package com.netflix.metacat.common.partition.util
+
+import spock.lang.Shared
+import spock.lang.Specification
+import spock.lang.Unroll
+
+/**
+ * Created by amajumdar on 3/1/16.
+ */
+class FilterPartitionSpec extends Specification{
+ @Shared
+ def filterPartition = new FilterPartition()
+
+ @Unroll
+ def 'evaluate expression #expression for name #name to #result'(){
+ expect:
+ filterPartition.evaluatePartitionExpression( expression, name, null) == result
+ where:
+ name | expression | result
+ "dateint=1" | "dateint>1" | false
+ "dateint=1" | "dateint>=1" | true
+ "dateint=1" | "dateint<1" | false
+ "dateint=1" | "dateint<=1" | true
+ "dateint=1" | "dateint==1" | true
+ "dateint=1" | "dateint!=1" | false
+ "dateint=1" | "(dateint>1) or (dateint<1)" | false
+ "dateint=1" | "(dateint>1) or (dateint<=1)" | true
+ "dateint=1" | "(dateint>1) and (dateint<=1)" | false
+ "dateint=1" | "(dateint==1) and ((dateint<=1) or (dateint>=1))" | true
+ "dateint=1" | "(((dateint>1) or (dateint<=1)) and (dateint==1))" | true
+ "dateint=1" | "('12' < 2)" | false
+ "dateint=1" | "(12 < 2)" | false
+ "dateint=1" | "('12' < '2')" | true
+ "dateint=1" | "(12 < '2')" | true
+ "dateint=1" | "(batchid>=1)" | false
+
+ "dateint=12" | "(dateint < 2)" | false
+ "dateint=12" | "(dateint <= 2)" | false
+ "dateint=12" | "(dateint < '2')" | true
+ "dateint=12" | "(dateint <= '2')" | true
+ "dateint=12" | "(dateint2 != 2)" | false
+ "dateint=12" | "(dateint2 == 12)" | false
+
+ "apath" | "(batchid>=1)" | false
+
+ "dateint=1/batchid=2" | "(batchid>=1)" | true
+ "dateint=1/batchid=2" | "((dateint==1) and (batchid>=1))" | true
+
+ "dateint=1/type=java" | "((dateint==1) and (type=='java'))" | true
+ "dateint=1/type=java" | "((dateint==1) and (type=='bava'))" | false
+
+ "dateint=1/type=java" | "(dateint>1 and type=='java') or (dateint==1 and type=='java')" | true
+ "dateint=1/type=java" | "(dateint>1 or dateint<1) and (type=='bava' or type=='java')" | false
+ "dateint=1/type=java" | "(dateint>1 or dateint<1) or (type=='bava' or type=='java')" | true
+ }
+}
diff --git a/metacat-common-server/src/test/groovy/com/netflix/metacat/common/partition/visitor/PartitionParserEvalSpec.groovy b/metacat-common-server/src/test/groovy/com/netflix/metacat/common/partition/visitor/PartitionParserEvalSpec.groovy
new file mode 100644
index 000000000..2b90152cf
--- /dev/null
+++ b/metacat-common-server/src/test/groovy/com/netflix/metacat/common/partition/visitor/PartitionParserEvalSpec.groovy
@@ -0,0 +1,29 @@
+package com.netflix.metacat.common.partition.visitor
+
+import spock.lang.Shared
+import spock.lang.Specification
+
+/**
+ * Created by amajumdar on 3/2/16.
+ */
+class PartitionParserEvalSpec extends Specification{
+ @Shared def eval = new PartitionParserEval()
+
+ def 'sql #sql to regex #regex'(){
+ expect:
+ eval.sqlLiketoRegexExpression(sql) == regex
+ where:
+ sql | regex
+ "5[%]" | "5%"
+ "[_]n" | "_n"
+ "[a-cdf]" | "[a-cdf]"
+ "[-acdf]" | "[-acdf]"
+ "[[]" | "["
+ "]" | "]"
+ "abc[_]d%" | "abc_d.*"
+ "abc[def]" | "abc[def]"
+ "[def%]" | "[def.*]"
+ "[def_]" | "[def.]"
+ "" | ""
+ }
+}
diff --git a/metacat-common/build.gradle b/metacat-common/build.gradle
new file mode 100644
index 000000000..6f7204f72
--- /dev/null
+++ b/metacat-common/build.gradle
@@ -0,0 +1,18 @@
+apply plugin: 'java'
+
+compileJava {
+ sourceCompatibility = '1.7'
+ targetCompatibility = '1.7'
+}
+
+dependencies {
+ compile "com.fasterxml.jackson.core:jackson-annotations:${jackson_version}"
+ compile "com.fasterxml.jackson.core:jackson-core:${jackson_version}"
+ compile "com.fasterxml.jackson.core:jackson-databind:${jackson_version}"
+ compile 'com.google.code.findbugs:jsr305:3.0.0'
+ compile "com.wordnik:swagger-annotations:${swagger_version}"
+ compile 'javax.ws.rs:jsr311-api:1.1.1'
+ testCompile "com.google.guava:guava:${guava_version}"
+ testCompile 'nl.jqno.equalsverifier:equalsverifier:1.7.2'
+ testCompile 'org.apache.commons:commons-lang3:3.4'
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/MetacatContext.java b/metacat-common/src/main/java/com/netflix/metacat/common/MetacatContext.java
new file mode 100644
index 000000000..1bd6de57b
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/MetacatContext.java
@@ -0,0 +1,51 @@
+package com.netflix.metacat.common;
+
+/**
+ * Created by amajumdar on 8/3/15.
+ */
+public class MetacatContext {
+ public static final String HEADER_KEY_USER_NAME = "X-Netflix.user.name";
+ public static final String HEADER_KEY_CLIENT_APP_NAME = "X-Netflix.client.app.name";
+ public static final String HEADER_KEY_JOB_ID = "X-Netflix.job.id";
+ public static final String HEADER_KEY_DATA_TYPE_CONTEXT = "X-Netflix.data.type.context";
+ private final String userName;
+ private final String clientAppName;
+ private final String clientId;
+ private final String jobId;
+ private final String dataTypeContext;
+ public enum DATA_TYPE_CONTEXTS {hive, pig, presto}
+ public MetacatContext(String userName, String clientAppName, String clientId, String jobId, String dataTypeContext) {
+ this.userName = userName;
+ this.clientAppName = clientAppName;
+ this.clientId = clientId;
+ this.jobId = jobId;
+ this.dataTypeContext = dataTypeContext;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public String getClientAppName() {
+ return clientAppName;
+ }
+
+ public String getJobId() {
+ return jobId;
+ }
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public String getDataTypeContext() {
+ return dataTypeContext;
+ }
+
+ @Override
+ public String toString() {
+ return "MetacatContext{" + "userName='" + userName + '\'' + ", clientAppName='" + clientAppName + '\''
+ + ", clientId='" + clientId + '\'' + ", jobId='" + jobId + '\'' + ", dataTypeContext='"
+ + dataTypeContext + '\'' + '}';
+ }
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/NameDateDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/NameDateDto.java
new file mode 100644
index 000000000..613deabbc
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/NameDateDto.java
@@ -0,0 +1,56 @@
+package com.netflix.metacat.common;
+
+import com.netflix.metacat.common.dto.BaseDto;
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import java.util.Date;
+import java.util.Objects;
+
+public class NameDateDto extends BaseDto {
+ private static final long serialVersionUID = -5713826608609231492L;
+ @ApiModelProperty(value = "The date the entity was created", required = false)
+ private Date createDate;
+ @ApiModelProperty(value = "The date the entity was last updated", required = false)
+ private Date lastUpdated;
+ @ApiModelProperty(value = "The entity's name", required = true)
+ private QualifiedName name;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof NameDateDto)) return false;
+ NameDateDto that = (NameDateDto) o;
+ return Objects.equals(name, that.name) &&
+ Objects.equals(createDate, that.createDate) &&
+ Objects.equals(lastUpdated, that.lastUpdated);
+ }
+
+ public Date getCreateDate() {
+ return createDate;
+ }
+
+ public void setCreateDate(Date createDate) {
+ this.createDate = createDate;
+ }
+
+ public Date getLastUpdated() {
+ return lastUpdated;
+ }
+
+ public void setLastUpdated(Date lastUpdated) {
+ this.lastUpdated = lastUpdated;
+ }
+
+ public QualifiedName getName() {
+ return name;
+ }
+
+ public void setName(QualifiedName name) {
+ this.name = name;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, createDate, lastUpdated);
+ }
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/QualifiedName.java b/metacat-common/src/main/java/com/netflix/metacat/common/QualifiedName.java
new file mode 100644
index 000000000..3b8679ace
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/QualifiedName.java
@@ -0,0 +1,321 @@
+package com.netflix.metacat.common;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.netflix.metacat.common.dto.PartitionDto;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A fully qualified name that references a source of data
+ */
+public class QualifiedName implements Serializable {
+ private final String catalogName;
+ private final String databaseName;
+ private final String partitionName;
+ private final String tableName;
+ private final String viewName;
+
+ private String qualifiedName;
+ private Map qualifiedNameMap;
+
+ private QualifiedName(
+ @Nonnull String catalogName,
+ @Nullable String databaseName,
+ @Nullable String tableName,
+ @Nullable String partitionName,
+ @Nullable String viewName
+ ) {
+ this.catalogName = standardizeRequired("catalogName", catalogName);
+ this.databaseName = standardizeOptional(databaseName, true);
+ this.tableName = standardizeOptional(tableName, true);
+ this.partitionName = standardizeOptional(partitionName, false);
+ this.viewName = standardizeOptional(viewName, true);
+
+ if (this.databaseName.isEmpty() && (!this.tableName.isEmpty() || !this.partitionName.isEmpty())) {
+ throw new IllegalStateException("databaseName is not present but tableName or partitionName are present");
+ } else if (this.tableName.isEmpty() && !this.partitionName.isEmpty()) {
+ throw new IllegalStateException("tableName is not present but partitionName is present");
+ }
+ }
+
+
+ @JsonCreator
+ public static QualifiedName fromJson(JsonNode node) {
+ JsonNode catalogNameNode = node.path("catalogName");
+ if (catalogNameNode.isMissingNode() || catalogNameNode.isNull() || !catalogNameNode.isTextual()) {
+ // If catalogName is not present try to load from the qualifiedName node instead
+ JsonNode nameNode = node.path("qualifiedName");
+ if (!nameNode.isNull() && nameNode.isTextual()) {
+ return fromString(nameNode.asText(), false);
+ } else {
+ // if neither are available throw an exception
+ throw new IllegalStateException("Node '" + node + "' is missing catalogName");
+ }
+ }
+ String catalogName = catalogNameNode.asText();
+ JsonNode databaseNameNode = node.path("databaseName");
+ String databaseName = null;
+ if( databaseNameNode != null){
+ databaseName = databaseNameNode.asText();
+ }
+ JsonNode tableNameNode = node.path("tableName");
+ String tableName = null;
+ if( tableNameNode != null){
+ tableName = tableNameNode.asText();
+ }
+ JsonNode partitionNameNode = node.path("partitionName");
+ String partitionName = null;
+ if( partitionNameNode != null){
+ partitionName = partitionNameNode.asText();
+ }
+ JsonNode viewNameNode = node.path("viewName");
+ String viewName = null;
+ if( viewNameNode != null){
+ viewName = viewNameNode.asText();
+ }
+ return new QualifiedName(catalogName, databaseName, tableName, partitionName, viewName);
+ }
+
+ public static QualifiedName fromString(@Nonnull String s){
+ return fromString( s, false);
+ }
+
+ public static QualifiedName fromString(@Nonnull String s, boolean isView) {
+ //noinspection ConstantConditions
+ String name = s == null ? "" : s.trim();
+ if (name.isEmpty()) {
+ throw new IllegalArgumentException("passed in an empty definition name");
+ }
+
+ String[] parts = name.split("/", 4);
+ switch (parts.length) {
+ case 1:
+ return ofCatalog(parts[0]);
+ case 2:
+ return ofDatabase(parts[0], parts[1]);
+ case 3:
+ return ofTable(parts[0], parts[1], parts[2]);
+ case 4:
+ if( isView){
+ return ofView(parts[0], parts[1], parts[2], parts[3]);
+ } else {
+ return ofPartition(parts[0], parts[1], parts[2], parts[3]);
+ }
+ default:
+ throw new IllegalArgumentException("Unable to convert '" + s + "' into a qualifiedDefinition");
+ }
+ }
+
+ public static QualifiedName ofCatalog(@Nonnull String catalogName) {
+ return new QualifiedName(catalogName, null, null, null, null);
+ }
+
+ public static QualifiedName ofDatabase(@Nonnull String catalogName, @Nonnull String databaseName) {
+ return new QualifiedName(catalogName, databaseName, null, null, null);
+ }
+
+ public static QualifiedName ofView(@Nonnull String catalogName, @Nonnull String databaseName,
+ @Nonnull String tableName, @Nonnull String viewName) {
+ return new QualifiedName( catalogName, databaseName, tableName, null, viewName);
+ }
+
+ public static QualifiedName ofPartition(@Nonnull QualifiedName tableName, @Nonnull PartitionDto partitionDto) {
+ return ofPartition(
+ tableName.tableName,
+ tableName.databaseName,
+ tableName.tableName,
+ partitionDto.getName().getPartitionName()
+ );
+ }
+
+ public static QualifiedName ofPartition(@Nonnull String catalogName, @Nonnull String databaseName,
+ @Nonnull String tableName, @Nonnull String partitionName) {
+ return new QualifiedName(catalogName, databaseName, tableName, partitionName, null);
+ }
+
+ public static QualifiedName ofTable(@Nonnull String catalogName, @Nonnull String databaseName,
+ @Nonnull String tableName) {
+ return new QualifiedName(catalogName, databaseName, tableName, null, null);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof QualifiedName)) return false;
+ QualifiedName that = (QualifiedName) o;
+ return Objects.equals(catalogName, that.catalogName) &&
+ Objects.equals(databaseName, that.databaseName) &&
+ Objects.equals(partitionName, that.partitionName) &&
+ Objects.equals(tableName, that.tableName) &&
+ Objects.equals(viewName, that.viewName);
+ }
+
+ public String getCatalogName() {
+ return catalogName;
+ }
+
+ public String getDatabaseName() {
+ if (databaseName.isEmpty()) {
+ throw new IllegalStateException("This is not a database definition");
+ }
+ return databaseName;
+ }
+
+ public String getPartitionName() {
+ if (partitionName.isEmpty()) {
+ throw new IllegalStateException("This is not a partition definition");
+ }
+ return partitionName;
+ }
+
+ public String getTableName() {
+ if (tableName.isEmpty()) {
+ throw new IllegalStateException("This is not a table definition");
+ }
+ return tableName;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(catalogName, databaseName, partitionName, tableName, viewName);
+ }
+
+ public boolean isCatalogDefinition() {
+ return !catalogName.isEmpty();
+ }
+
+ public boolean isDatabaseDefinition() {
+ return !databaseName.isEmpty();
+ }
+
+ public boolean isPartitionDefinition() {
+ return !partitionName.isEmpty();
+ }
+
+ public boolean isTableDefinition() {
+ return !tableName.isEmpty();
+ }
+
+ private String standardizeOptional(String value, boolean forceLowerCase) {
+ if (value == null) {
+ return "";
+ } else {
+ value = value.trim();
+ if (forceLowerCase) {
+ value = value.toLowerCase();
+ }
+ return value;
+ }
+ }
+
+ private String standardizeRequired(String name, String value) {
+ if (value == null) {
+ throw new IllegalStateException(name + " cannot be null");
+ }
+
+ value = value.trim();
+ if (value.isEmpty()) {
+ throw new IllegalStateException(name + " cannot be an empty string");
+ }
+
+ return value.toLowerCase();
+ }
+
+ @JsonValue
+ public Map toJson() {
+ if( qualifiedNameMap == null) {
+ Map map = new HashMap<>(4);
+ map.put("qualifiedName", toString());
+ map.put("catalogName", catalogName);
+
+ if (!databaseName.isEmpty()) {
+ map.put("databaseName", databaseName);
+ }
+
+ if (!tableName.isEmpty()) {
+ map.put("tableName", tableName);
+ }
+
+ if (!partitionName.isEmpty()) {
+ map.put("partitionName", partitionName);
+ }
+
+ if (!viewName.isEmpty()) {
+ map.put("viewName", viewName);
+ }
+
+ qualifiedNameMap = map;
+ }
+
+ return qualifiedNameMap;
+ }
+
+ public boolean isViewDefinition() {
+ return !viewName.isEmpty();
+ }
+
+ @Override
+ public String toString() {
+ if( qualifiedName == null) {
+ StringBuilder sb = new StringBuilder(catalogName);
+
+ if (!databaseName.isEmpty()) {
+ sb.append('/');
+ sb.append(databaseName);
+ }
+
+ if (!tableName.isEmpty()) {
+ sb.append('/');
+ sb.append(tableName);
+ }
+
+ if (!partitionName.isEmpty()) {
+ sb.append('/');
+ sb.append(partitionName);
+ }
+
+ if (!viewName.isEmpty()) {
+ sb.append('/');
+ sb.append(viewName);
+ }
+ qualifiedName = sb.toString();
+ }
+
+ return qualifiedName;
+ }
+
+ public static String toWildCardString(String sourceName, String databaseName, String tableName){
+ if( sourceName == null && databaseName ==null && tableName == null){
+ return null;
+ }
+ StringBuilder builder = new StringBuilder();
+ if( sourceName != null){
+ builder.append(sourceName);
+ } else {
+ builder.append('%');
+ }
+ if(databaseName != null){
+ builder.append('/').append(databaseName);
+ } else {
+ builder.append("/%");
+ }
+ if(tableName != null){
+ builder.append('/').append(tableName);
+ } else {
+ builder.append("/%");
+ }
+ builder.append('%');
+ return builder.toString();
+ }
+
+ public String getViewName() {
+ return viewName;
+ }
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/api/MetacatV1.java b/metacat-common/src/main/java/com/netflix/metacat/common/api/MetacatV1.java
new file mode 100644
index 000000000..6e251ebb8
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/api/MetacatV1.java
@@ -0,0 +1,497 @@
+package com.netflix.metacat.common.api;
+
+import com.netflix.metacat.common.NameDateDto;
+import com.netflix.metacat.common.dto.CatalogDto;
+import com.netflix.metacat.common.dto.CatalogMappingDto;
+import com.netflix.metacat.common.dto.CreateCatalogDto;
+import com.netflix.metacat.common.dto.DatabaseCreateRequestDto;
+import com.netflix.metacat.common.dto.DatabaseDto;
+import com.netflix.metacat.common.dto.TableDto;
+import com.wordnik.swagger.annotations.Api;
+import com.wordnik.swagger.annotations.ApiOperation;
+import com.wordnik.swagger.annotations.ApiParam;
+import com.wordnik.swagger.annotations.ApiResponse;
+import com.wordnik.swagger.annotations.ApiResponses;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import java.net.HttpURLConnection;
+import java.util.List;
+
+@Path("mds/v1")
+@Api(value = "MetacatV1",
+ description = "Federated metadata operations",
+ produces = MediaType.APPLICATION_JSON,
+ consumes = MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public interface MetacatV1 {
+ @POST
+ @Path("catalog")
+ @ApiOperation(
+ position = 3,
+ value = "Creates a new catalog",
+ notes = "Returns success if there were no errors creating the catalog")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND, message = "No catalogs are registered with the server")
+ })
+ void createCatalog(CreateCatalogDto createCatalogDto);
+
+ @POST
+ @Path("catalog/{catalog-name}/database/{database-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 2,
+ value = "Creates the given database in the given catalog",
+ notes = "Given a catalog and a database name, creates the database in the catalog")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database cannot be located"
+ )
+ })
+ void createDatabase(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The database information", required = false)
+ DatabaseCreateRequestDto databaseCreateRequestDto
+ );
+
+ @POST
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 2,
+ value = "Creates a table",
+ notes = "Creates the given table")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ TableDto createTable(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The table information", required = true)
+ TableDto table
+ );
+
+ @POST
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/mview/{view-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 2,
+ value = "Creates a metacat view. A staging table that can contain partitions referring to the table partition locations.",
+ notes = "Creates the given metacat view. A staging table that can contain partitions referring to the table partition locations.")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ TableDto createMView(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The name of the view", required = true)
+ @PathParam("view-name")
+ String viewName,
+ @ApiParam(value = "To snapshot a list of partitions of the table to this view. If true, it will restore the partitions from the table to this view.", required = false)
+ @DefaultValue("false") @QueryParam("snapshot")
+ Boolean snapshot,
+ @ApiParam(value = "Filter expression string to use", required = false)
+ @QueryParam("filter")
+ String filter
+ );
+
+ @DELETE
+ @Path("catalog/{catalog-name}/database/{database-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 4,
+ value = "Deletes the given database from the given catalog",
+ notes = "Given a catalog and database, deletes the database from the catalog")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database cannot be located"
+ )
+ })
+ void deleteDatabase(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName
+ );
+
+ @DELETE
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 4,
+ value = "Delete table",
+ notes = "Deletes the given table")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ TableDto deleteTable(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName
+ );
+
+ @DELETE
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/mview/{view-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 4,
+ value = "Delete metacat view",
+ notes = "Deletes the given metacat view")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or metacat view cannot be located"
+ )
+ })
+ TableDto deleteMView(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The name of the metacat view", required = true)
+ @PathParam("view-name")
+ String viewName
+ );
+
+ @GET
+ @Path("catalog/{catalog-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 2,
+ value = "Databases for the requested catalog",
+ notes = "The list of databases that belong to the given catalog")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND, message = "The requested catalog cannot be located")
+ })
+ CatalogDto getCatalog(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName
+ );
+
+ @GET
+ @Path("catalog")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 1,
+ value = "List registered catalogs",
+ notes = "The names and types of all catalogs registered with this server")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND, message = "No catalogs are registered with the server")
+ })
+ List getCatalogNames();
+
+ @GET
+ @Path("catalog/{catalog-name}/database/{database-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 1,
+ value = "Tables for the requested database",
+ notes = "The list of tables that belong to the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database cannot be located"
+ )
+ })
+ DatabaseDto getDatabase(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "Whether to include user metadata information to the response", required = false)
+ @DefaultValue("true") @QueryParam("includeUserMetadata")
+ Boolean includeUserMetadata
+ );
+
+ @GET
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 1,
+ value = "Table information",
+ notes = "Table information for the given table name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ TableDto getTable(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "Whether to include the core information about the table (location, serde, columns) in " +
+ "the response. You would only say false here if you only want metadata.", required = false)
+ @DefaultValue("true") @QueryParam("includeInfo")
+ Boolean includeInfo,
+ @ApiParam(value = "Whether to include user definition metadata information to the response", required = false)
+ @DefaultValue("true") @QueryParam("includeDefinitionMetadata")
+ Boolean includeDefinitionMetadata,
+ @ApiParam(value = "Whether to include user data metadata information to the response", required = false)
+ @DefaultValue("true") @QueryParam("includeDataMetadata")
+ Boolean includeDataMetadata
+ );
+
+ @GET
+ @Path("catalog/{catalog-name}/mviews")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 1,
+ value = "List of metacat views",
+ notes = "List of metacat views for a catalog")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog cannot be located"
+ )
+ })
+ List getMViews(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName
+ );
+
+ @GET
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/mviews")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 1,
+ value = "List of metacat views",
+ notes = "List of metacat views for a catalog")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog cannot be located"
+ )
+ })
+ List getMViews(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName
+ );
+
+ @GET
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/mview/{view-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 1,
+ value = "Metacat View information",
+ notes = "View information for the given view name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ TableDto getMView(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The name of the view", required = true)
+ @PathParam("view-name")
+ String viewName
+ );
+
+ @POST
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/rename")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 3,
+ value = "Rename table",
+ notes = "Renames the given table with the new name")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ void renameTable(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The name of the table", required = true)
+ @QueryParam("newTableName")
+ String newTableName
+ );
+
+ @PUT
+ @Path("catalog/{catalog-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 4,
+ value = "Updates an existing catalog",
+ notes = "Returns success if there were no errors updating the catalog")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND, message = "No catalogs are registered with the server")
+ })
+ void updateCatalog(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ CreateCatalogDto createCatalogDto
+ );
+
+ @PUT
+ @Path("catalog/{catalog-name}/database/{database-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 3,
+ value = "Updates the given database in the given catalog",
+ notes = "Given a catalog and a database name, creates the database in the catalog")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database cannot be located"
+ )
+ })
+ void updateDatabase(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The database information", required = false)
+ DatabaseCreateRequestDto databaseUpdateRequestDto
+ );
+
+ @PUT
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/mview/{view-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 3,
+ value = "Update mview",
+ notes = "Updates the given mview")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ TableDto updateMView(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The name of the view", required = true)
+ @PathParam("view-name")
+ String viewName,
+ @ApiParam(value = "The view information", required = true)
+ TableDto table
+ );
+
+ @PUT
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 3,
+ value = "Update table",
+ notes = "Updates the given table")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ TableDto updateTable(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The table information", required = true)
+ TableDto table
+ );
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/api/MetadataV1.java b/metacat-common/src/main/java/com/netflix/metacat/common/api/MetadataV1.java
new file mode 100644
index 000000000..d2d591259
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/api/MetadataV1.java
@@ -0,0 +1,83 @@
+package com.netflix.metacat.common.api;
+
+import com.netflix.metacat.common.QualifiedName;
+import com.netflix.metacat.common.dto.DataMetadataDto;
+import com.netflix.metacat.common.dto.DataMetadataGetRequestDto;
+import com.netflix.metacat.common.dto.DefinitionMetadataDto;
+import com.netflix.metacat.common.dto.SortOrder;
+import com.wordnik.swagger.annotations.Api;
+import com.wordnik.swagger.annotations.ApiOperation;
+import com.wordnik.swagger.annotations.ApiParam;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+import java.util.Set;
+
+@Path("mds/v1/metadata")
+@Api(value = "MetadataV1",
+ description = "Federated user metadata operations",
+ produces = MediaType.APPLICATION_JSON,
+ consumes = MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public interface MetadataV1 {
+ @POST
+ @Path("data")
+ @ApiOperation(
+ position = 1,
+ value = "Returns the data metadata",
+ notes = "Returns the data metadata")
+ DataMetadataDto getDataMetadata(DataMetadataGetRequestDto metadataGetRequestDto);
+
+ @GET
+ @Path("definition/list")
+ @ApiOperation(
+ position = 2,
+ value = "Returns the definition metadata",
+ notes = "Returns the definition metadata")
+ List getDefinitionMetadataList(
+ @ApiParam(value = "Sort the list by this value", required = false)
+ @QueryParam("sortBy")
+ String sortBy,
+ @ApiParam(value = "Sorting order to use", required = false)
+ @QueryParam("sortOrder")
+ SortOrder sortOrder,
+ @ApiParam(value = "Offset of the list returned", required = false)
+ @QueryParam("offset")
+ Integer offset,
+ @ApiParam(value = "Size of the list", required = false)
+ @QueryParam("limit")
+ Integer limit,
+ @ApiParam(value = "has lifetime set", required = false)
+ @DefaultValue("false") @QueryParam("lifetime")
+ Boolean lifetime,
+ @ApiParam(value = "Type of the metadata item. Values: database, table, partition", required = false)
+ @QueryParam("type")
+ String type,
+ @ApiParam(value = "Text that matches the name of the metadata (accepts sql wildcards)", required = false)
+ @QueryParam("name")
+ String name,
+ @ApiParam(value = "Set of data property names. Filters the returned list that only contains the given property names", required = false)
+ @QueryParam("data-property")
+ Set dataProperties
+ );
+
+ @GET
+ @Path("searchByOwners")
+ @ApiOperation(
+ position = 3,
+ value = "Returns the qualified names owned by the given owners",
+ notes = "Returns the qualified names owned by the given owners")
+ List searchByOwners(
+ @ApiParam(value = "Set of owners", required = true)
+ @QueryParam("owner")
+ Set owners
+ );
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/api/PartitionV1.java b/metacat-common/src/main/java/com/netflix/metacat/common/api/PartitionV1.java
new file mode 100644
index 000000000..bc67b2a2c
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/api/PartitionV1.java
@@ -0,0 +1,726 @@
+package com.netflix.metacat.common.api;
+
+import com.netflix.metacat.common.dto.GetPartitionsRequestDto;
+import com.netflix.metacat.common.dto.PartitionDto;
+import com.netflix.metacat.common.dto.PartitionsSaveRequestDto;
+import com.netflix.metacat.common.dto.PartitionsSaveResponseDto;
+import com.netflix.metacat.common.dto.SortOrder;
+import com.wordnik.swagger.annotations.Api;
+import com.wordnik.swagger.annotations.ApiOperation;
+import com.wordnik.swagger.annotations.ApiParam;
+import com.wordnik.swagger.annotations.ApiResponse;
+import com.wordnik.swagger.annotations.ApiResponses;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import java.net.HttpURLConnection;
+import java.util.List;
+
+/**
+ * Created by amajumdar on 6/17/15.
+ */
+@Path("mds/v1/partition")
+@Api(value = "PartitionV1",
+ description = "Federated partition metadata operations",
+ produces = MediaType.APPLICATION_JSON,
+ consumes = MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public interface PartitionV1 {
+ @DELETE
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "Delete named partitions from a table",
+ notes = "List of partitions names of the given table name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ ),
+ @ApiResponse(code = HttpURLConnection.HTTP_BAD_REQUEST,
+ message = "The list of partitionNames is not present"
+ )
+ })
+ void deletePartitions(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "partitionId of the partitions to be deleted from this table", required = true)
+ List partitionIds
+ );
+
+
+ @DELETE
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/mview/{view-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "Delete partitions for the given view",
+ notes = "Delete partitions for the given view")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or metacat view cannot be located"
+ ),
+ @ApiResponse(code = HttpURLConnection.HTTP_BAD_REQUEST,
+ message = "The list of partitionNames is not present"
+ )
+ })
+ void deletePartitions(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The name of the metacat view", required = true)
+ @PathParam("view-name")
+ String viewName,
+ @ApiParam(value = "partitionId of the partitions to be deleted from this table", required = true)
+ List partitionIds
+ );
+
+ @GET
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "List of partitions for a table",
+ notes = "List of partitions for the given table name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ List getPartitions(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "Filter expression string to use", required = false)
+ @QueryParam("filter")
+ String filter,
+ @ApiParam(value = "Sort the partition list by this value", required = false)
+ @QueryParam("sortBy")
+ String sortBy,
+ @ApiParam(value = "Sorting order to use", required = false)
+ @QueryParam("sortOrder")
+ SortOrder sortOrder,
+ @ApiParam(value = "Offset of the list returned", required = false)
+ @QueryParam("offset")
+ Integer offset,
+ @ApiParam(value = "Size of the partition list", required = false)
+ @QueryParam("limit")
+ Integer limit,
+ @ApiParam(value = "Whether to include user metadata information to the response", required = false)
+ @DefaultValue("false") @QueryParam("includeUserMetadata")
+ Boolean includeUserMetadata
+ );
+
+ @GET
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/mview/{view-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "List of partitions for a metacat view",
+ notes = "List of partitions for the given view name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or metacat view cannot be located"
+ )
+ })
+ List getPartitions(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The name of the metacat view", required = true)
+ @PathParam("view-name")
+ String viewName,
+ @ApiParam(value = "Filter expression string to use", required = false)
+ @QueryParam("filter")
+ String filter,
+ @ApiParam(value = "Sort the partition list by this value", required = false)
+ @QueryParam("sortBy")
+ String sortBy,
+ @ApiParam(value = "Sorting order to use", required = false)
+ @QueryParam("sortOrder")
+ SortOrder sortOrder,
+ @ApiParam(value = "Offset of the list returned", required = false)
+ @QueryParam("offset")
+ Integer offset,
+ @ApiParam(value = "Size of the partition list", required = false)
+ @QueryParam("limit")
+ Integer limit,
+ @ApiParam(value = "Whether to include user metadata information to the response", required = false)
+ @DefaultValue("false") @QueryParam("includeUserMetadata")
+ Boolean includeUserMetadata
+ );
+
+ @POST
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/request")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "List of partitions for a table",
+ notes = "List of partitions for the given table name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ List getPartitionsForRequest(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "Sort the partition list by this value", required = false)
+ @QueryParam("sortBy")
+ String sortBy,
+ @ApiParam(value = "Sorting order to use", required = false)
+ @QueryParam("sortOrder")
+ SortOrder sortOrder,
+ @ApiParam(value = "Offset of the list returned", required = false)
+ @QueryParam("offset")
+ Integer offset,
+ @ApiParam(value = "Size of the partition list", required = false)
+ @QueryParam("limit")
+ Integer limit,
+ @ApiParam(value = "Whether to include user metadata information to the response", required = false)
+ @DefaultValue("false") @QueryParam("includeUserMetadata")
+ Boolean includeUserMetadata,
+ @ApiParam(value = "Request containing the filter expression for the partitions", required = false)
+ GetPartitionsRequestDto getPartitionsRequestDto
+ );
+
+ @POST
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/mview/{view-name}/request")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "List of partitions for a metacat view",
+ notes = "List of partitions for the given view name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or metacat view cannot be located"
+ )
+ })
+ List getPartitionsForRequest(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The name of the metacat view", required = true)
+ @PathParam("view-name")
+ String viewName,
+ @ApiParam(value = "Sort the partition list by this value", required = false)
+ @QueryParam("sortBy")
+ String sortBy,
+ @ApiParam(value = "Sorting order to use", required = false)
+ @QueryParam("sortOrder")
+ SortOrder sortOrder,
+ @ApiParam(value = "Offset of the list returned", required = false)
+ @QueryParam("offset")
+ Integer offset,
+ @ApiParam(value = "Size of the partition list", required = false)
+ @QueryParam("limit")
+ Integer limit,
+ @ApiParam(value = "Whether to include user metadata information to the response", required = false)
+ @DefaultValue("false") @QueryParam("includeUserMetadata")
+ Boolean includeUserMetadata,
+ @ApiParam(value = "Request containing the filter expression for the partitions", required = false)
+ GetPartitionsRequestDto getPartitionsRequestDto
+ );
+
+ @GET
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/keys")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "List of partition keys for a table",
+ notes = "List of partition keys for the given table name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ List getPartitionKeys(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "Filter expression string to use", required = false)
+ @QueryParam("filter")
+ String filter,
+ @ApiParam(value = "Sort the partition list by this value", required = false)
+ @QueryParam("sortBy")
+ String sortBy,
+ @ApiParam(value = "Sorting order to use", required = false)
+ @QueryParam("sortOrder")
+ SortOrder sortOrder,
+ @ApiParam(value = "Offset of the list returned", required = false)
+ @QueryParam("offset")
+ Integer offset,
+ @ApiParam(value = "Size of the partition list", required = false)
+ @QueryParam("limit")
+ Integer limit,
+ @ApiParam(value = "Whether to include user metadata information to the response", required = false)
+ @DefaultValue("false") @QueryParam("includeUserMetadata")
+ Boolean includeUserMetadata
+ );
+
+ @GET
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/mview/{view-name}/keys")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "List of partition keys for a metacat view",
+ notes = "List of partition keys for the given view name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or metacat view cannot be located"
+ )
+ })
+ List getPartitionKeys(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The name of the metacat view", required = true)
+ @PathParam("view-name")
+ String viewName,
+ @ApiParam(value = "Filter expression string to use", required = false)
+ @QueryParam("filter")
+ String filter,
+ @ApiParam(value = "Sort the partition list by this value", required = false)
+ @QueryParam("sortBy")
+ String sortBy,
+ @ApiParam(value = "Sorting order to use", required = false)
+ @QueryParam("sortOrder")
+ SortOrder sortOrder,
+ @ApiParam(value = "Offset of the list returned", required = false)
+ @QueryParam("offset")
+ Integer offset,
+ @ApiParam(value = "Size of the partition list", required = false)
+ @QueryParam("limit")
+ Integer limit,
+ @ApiParam(value = "Whether to include user metadata information to the response", required = false)
+ @DefaultValue("false") @QueryParam("includeUserMetadata")
+ Boolean includeUserMetadata
+ );
+
+ @POST
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/keys-request")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "List of partition keys for a table",
+ notes = "List of partition keys for the given table name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ List getPartitionKeysForRequest(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "Sort the partition list by this value", required = false)
+ @QueryParam("sortBy")
+ String sortBy,
+ @ApiParam(value = "Sorting order to use", required = false)
+ @QueryParam("sortOrder")
+ SortOrder sortOrder,
+ @ApiParam(value = "Offset of the list returned", required = false)
+ @QueryParam("offset")
+ Integer offset,
+ @ApiParam(value = "Size of the partition list", required = false)
+ @QueryParam("limit")
+ Integer limit,
+ @ApiParam(value = "Whether to include user metadata information to the response", required = false)
+ @DefaultValue("false") @QueryParam("includeUserMetadata")
+ Boolean includeUserMetadata,
+ @ApiParam(value = "Request containing the filter expression for the partitions", required = false)
+ GetPartitionsRequestDto getPartitionsRequestDto
+ );
+
+ @POST
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/mview/{view-name}/keys-request")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "List of partition keys for a metacat view",
+ notes = "List of partition keys for the given view name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or metacat view cannot be located"
+ )
+ })
+ List getPartitionKeysForRequest(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The name of the metacat view", required = true)
+ @PathParam("view-name")
+ String viewName,
+ @ApiParam(value = "Sort the partition list by this value", required = false)
+ @QueryParam("sortBy")
+ String sortBy,
+ @ApiParam(value = "Sorting order to use", required = false)
+ @QueryParam("sortOrder")
+ SortOrder sortOrder,
+ @ApiParam(value = "Offset of the list returned", required = false)
+ @QueryParam("offset")
+ Integer offset,
+ @ApiParam(value = "Size of the partition list", required = false)
+ @QueryParam("limit")
+ Integer limit,
+ @ApiParam(value = "Whether to include user metadata information to the response", required = false)
+ @DefaultValue("false") @QueryParam("includeUserMetadata")
+ Boolean includeUserMetadata,
+ @ApiParam(value = "Request containing the filter expression for the partitions", required = false)
+ GetPartitionsRequestDto getPartitionsRequestDto
+ );
+
+ @GET
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/uris")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "List of partition uris for a table",
+ notes = "List of partition uris for the given table name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ List getPartitionUris(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "Filter expression string to use", required = false)
+ @QueryParam("filter")
+ String filter,
+ @ApiParam(value = "Sort the partition list by this value", required = false)
+ @QueryParam("sortBy")
+ String sortBy,
+ @ApiParam(value = "Sorting order to use", required = false)
+ @QueryParam("sortOrder")
+ SortOrder sortOrder,
+ @ApiParam(value = "Offset of the list returned", required = false)
+ @QueryParam("offset")
+ Integer offset,
+ @ApiParam(value = "Size of the partition list", required = false)
+ @QueryParam("limit")
+ Integer limit,
+ @ApiParam(value = "Whether to include user metadata information to the response", required = false)
+ @DefaultValue("false") @QueryParam("includeUserMetadata")
+ Boolean includeUserMetadata
+ );
+
+ @GET
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/mview/{view-name}/uris")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "List of partition uris for a metacat view",
+ notes = "List of partition uris for the given view name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or metacat view cannot be located"
+ )
+ })
+ List getPartitionUris(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The name of the metacat view", required = true)
+ @PathParam("view-name")
+ String viewName,
+ @ApiParam(value = "Filter expression string to use", required = false)
+ @QueryParam("filter")
+ String filter,
+ @ApiParam(value = "Sort the partition list by this value", required = false)
+ @QueryParam("sortBy")
+ String sortBy,
+ @ApiParam(value = "Sorting order to use", required = false)
+ @QueryParam("sortOrder")
+ SortOrder sortOrder,
+ @ApiParam(value = "Offset of the list returned", required = false)
+ @QueryParam("offset")
+ Integer offset,
+ @ApiParam(value = "Size of the partition list", required = false)
+ @QueryParam("limit")
+ Integer limit,
+ @ApiParam(value = "Whether to include user metadata information to the response", required = false)
+ @DefaultValue("false") @QueryParam("includeUserMetadata")
+ Boolean includeUserMetadata
+ );
+
+ @POST
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/uris-request")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "List of partition uris for a table",
+ notes = "List of partition uris for the given table name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ List getPartitionUrisForRequest(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "Sort the partition list by this value", required = false)
+ @QueryParam("sortBy")
+ String sortBy,
+ @ApiParam(value = "Sorting order to use", required = false)
+ @QueryParam("sortOrder")
+ SortOrder sortOrder,
+ @ApiParam(value = "Offset of the list returned", required = false)
+ @QueryParam("offset")
+ Integer offset,
+ @ApiParam(value = "Size of the partition list", required = false)
+ @QueryParam("limit")
+ Integer limit,
+ @ApiParam(value = "Whether to include user metadata information to the response", required = false)
+ @DefaultValue("false") @QueryParam("includeUserMetadata")
+ Boolean includeUserMetadata,
+ @ApiParam(value = "Request containing the filter expression for the partitions", required = false)
+ GetPartitionsRequestDto getPartitionsRequestDto
+ );
+
+ @POST
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/mview/{view-name}/uris-request")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ value = "List of partition uris for a metacat view",
+ notes = "List of partition uris for the given view name under the given catalog and database")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or metacat view cannot be located"
+ )
+ })
+ List getPartitionUrisForRequest(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The name of the metacat view", required = true)
+ @PathParam("view-name")
+ String viewName,
+ @ApiParam(value = "Sort the partition list by this value", required = false)
+ @QueryParam("sortBy")
+ String sortBy,
+ @ApiParam(value = "Sorting order to use", required = false)
+ @QueryParam("sortOrder")
+ SortOrder sortOrder,
+ @ApiParam(value = "Offset of the list returned", required = false)
+ @QueryParam("offset")
+ Integer offset,
+ @ApiParam(value = "Size of the partition list", required = false)
+ @QueryParam("limit")
+ Integer limit,
+ @ApiParam(value = "Whether to include user metadata information to the response", required = false)
+ @DefaultValue("false") @QueryParam("includeUserMetadata")
+ Boolean includeUserMetadata,
+ @ApiParam(value = "Request containing the filter expression for the partitions", required = false)
+ GetPartitionsRequestDto getPartitionsRequestDto
+ );
+
+
+ @POST
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 5,
+ value = "Add/update partitions to the given table",
+ notes = "Add/update partitions to the given table")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ PartitionsSaveResponseDto savePartitions(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "Request containing the list of partitions", required = true)
+ PartitionsSaveRequestDto partitionsSaveRequestDto
+ );
+
+ @POST
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/mview/{view-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 5,
+ value = "Add/update partitions to the given table",
+ notes = "Add/update partitions to the given table")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ PartitionsSaveResponseDto savePartitions(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The name of the view", required = true)
+ @PathParam("view-name")
+ String viewName,
+ @ApiParam(value = "Request containing the list of partitions", required = true)
+ PartitionsSaveRequestDto partitionsSaveRequestDto
+ );
+
+ @GET
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/count")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 5,
+ value = "Partition count for the given table",
+ notes = "Partition count for the given table")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ Integer getPartitionCount(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName
+ );
+
+ @GET
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}/mview/{view-name}/count")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 5,
+ value = "Partition count for the given table",
+ notes = "Partition count for the given table")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ Integer getPartitionCount(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "The name of the view", required = true)
+ @PathParam("view-name")
+ String viewName
+ );
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/api/SearchMetacatV1.java b/metacat-common/src/main/java/com/netflix/metacat/common/api/SearchMetacatV1.java
new file mode 100644
index 000000000..f5f4f3e8d
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/api/SearchMetacatV1.java
@@ -0,0 +1,24 @@
+package com.netflix.metacat.common.api;
+
+import com.netflix.metacat.common.dto.TableDto;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+@Path("mds/v1/search")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public interface SearchMetacatV1 {
+ @GET
+ @Path("table")
+ @Consumes(MediaType.APPLICATION_JSON)
+ List searchTables(
+ @QueryParam("q")
+ String searchString
+ );
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/api/TagV1.java b/metacat-common/src/main/java/com/netflix/metacat/common/api/TagV1.java
new file mode 100644
index 000000000..ae6293fb1
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/api/TagV1.java
@@ -0,0 +1,147 @@
+package com.netflix.metacat.common.api;
+
+import com.netflix.metacat.common.QualifiedName;
+import com.wordnik.swagger.annotations.Api;
+import com.wordnik.swagger.annotations.ApiOperation;
+import com.wordnik.swagger.annotations.ApiParam;
+import com.wordnik.swagger.annotations.ApiResponse;
+import com.wordnik.swagger.annotations.ApiResponses;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import java.net.HttpURLConnection;
+import java.util.List;
+import java.util.Set;
+
+@Path("mds/v1/tag")
+@Api(value = "TagV1",
+ description = "Federated metadata tag operations",
+ produces = MediaType.APPLICATION_JSON,
+ consumes = MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public interface TagV1 {
+ @GET
+ @Path("tags")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 1,
+ value = "Returns the tags",
+ notes = "Returns the tags")
+ Set getTags();
+
+ @GET
+ @Path("list")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 1,
+ value = "Returns the list of qualified names that are tagged with the given tags. Qualified names will be excluded if the contained tags matches the excluded tags",
+ notes = "Returns the list of qualified names that are tagged with the given tags. Qualified names will be excluded if the contained tags matches the excluded tags")
+ List list(
+ @ApiParam(value = "Set of matching tags", required = false)
+ @QueryParam("include")
+ Set includeTags,
+ @ApiParam(value = "Set of un-matching tags", required = false)
+ @QueryParam("exclude")
+ Set excludeTags,
+ @ApiParam(value = "Prefix of the source name", required = false)
+ @QueryParam("sourceName")
+ String sourceName,
+ @ApiParam(value = "Prefix of the database name", required = false)
+ @QueryParam("databaseName")
+ String databaseName,
+ @ApiParam(value = "Prefix of the table name", required = false)
+ @QueryParam("tableName")
+ String tableName
+ );
+
+ @GET
+ @Path("search")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 1,
+ value = "Returns the list of qualified names that are tagged with tags containing the given tagText",
+ notes = "Returns the list of qualified names that are tagged with tags containing the given tagText")
+ List search(
+ @ApiParam(value = "Tag partial text", required = false)
+ @QueryParam("tag")
+ String tag,
+ @ApiParam(value = "Prefix of the source name", required = false)
+ @QueryParam("sourceName")
+ String sourceName,
+ @ApiParam(value = "Prefix of the database name", required = false)
+ @QueryParam("databaseName")
+ String databaseName,
+ @ApiParam(value = "Prefix of the table name", required = false)
+ @QueryParam("tableName")
+ String tableName
+ );
+
+ @POST
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 2,
+ value = "Sets the tags on the given table",
+ notes = "Sets the tags on the given table")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ Set setTableTags(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "Set of tags", required = true)
+ Set tags
+ );
+
+ @DELETE
+ @Path("catalog/{catalog-name}/database/{database-name}/table/{table-name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @ApiOperation(
+ position = 4,
+ value = "Remove the tags from the given table",
+ notes = "Remove the tags from the given table")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND,
+ message = "The requested catalog or database or table cannot be located"
+ )
+ })
+ void removeTableTags(
+ @ApiParam(value = "The name of the catalog", required = true)
+ @PathParam("catalog-name")
+ String catalogName,
+ @ApiParam(value = "The name of the database", required = true)
+ @PathParam("database-name")
+ String databaseName,
+ @ApiParam(value = "The name of the table", required = true)
+ @PathParam("table-name")
+ String tableName,
+ @ApiParam(value = "True if all tags need to be removed", required = false)
+ @DefaultValue("false") @QueryParam("all")
+ Boolean deleteAll,
+ @ApiParam(value = "Tags to be removed from the given table", required = false)
+ Set tags
+ );
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/AuditDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/AuditDto.java
new file mode 100644
index 000000000..369ec0010
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/AuditDto.java
@@ -0,0 +1,73 @@
+package com.netflix.metacat.common.dto;
+
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import java.util.Date;
+import java.util.Objects;
+
+@SuppressWarnings("unused")
+public class AuditDto extends BaseDto {
+ private static final long serialVersionUID = 9221109874202093789L;
+
+ /* Created By */
+ @ApiModelProperty(value = "User name who created the table", required = false)
+ private String createdBy;
+ /* Created date */
+ @ApiModelProperty(value = "Creation date", required = false)
+ private Date createdDate;
+ /* Last modified by */
+ @ApiModelProperty(value = "User name who last modified the table", required = false)
+ private String lastModifiedBy;
+ /* Last modified date */
+ @ApiModelProperty(value = "Last modified date", required = false)
+ private Date lastModifiedDate;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof AuditDto)) return false;
+ AuditDto auditDto = (AuditDto) o;
+ return Objects.equals(createdBy, auditDto.createdBy) &&
+ Objects.equals(createdDate, auditDto.createdDate) &&
+ Objects.equals(lastModifiedBy, auditDto.lastModifiedBy) &&
+ Objects.equals(lastModifiedDate, auditDto.lastModifiedDate);
+ }
+
+ public String getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(String createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public Date getCreatedDate() {
+ return createdDate;
+ }
+
+ public void setCreatedDate(Date createdDate) {
+ this.createdDate = createdDate;
+ }
+
+ public String getLastModifiedBy() {
+ return lastModifiedBy;
+ }
+
+ public void setLastModifiedBy(String lastModifiedBy) {
+ this.lastModifiedBy = lastModifiedBy;
+ }
+
+ public Date getLastModifiedDate() {
+ return lastModifiedDate;
+ }
+
+ public void setLastModifiedDate(Date lastModifiedDate) {
+ this.lastModifiedDate = lastModifiedDate;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(createdBy, createdDate, lastModifiedBy, lastModifiedDate);
+ }
+
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/BaseDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/BaseDto.java
new file mode 100644
index 000000000..b8d31fcb8
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/BaseDto.java
@@ -0,0 +1,28 @@
+package com.netflix.metacat.common.dto;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.netflix.metacat.common.json.MetacatJsonLocator;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+public abstract class BaseDto implements Serializable {
+ @Nullable
+ public static ObjectNode deserializeObjectNode(@Nonnull ObjectInputStream inputStream) throws IOException {
+ return MetacatJsonLocator.INSTANCE.deserializeObjectNode(inputStream);
+ }
+
+ public static void serializeObjectNode(@Nonnull ObjectOutputStream outputStream, @Nullable ObjectNode json)
+ throws IOException {
+ MetacatJsonLocator.INSTANCE.serializeObjectNode(outputStream, json);
+ }
+
+ @Override
+ public String toString() {
+ return MetacatJsonLocator.INSTANCE.toJsonString(this);
+ }
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/CatalogDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/CatalogDto.java
new file mode 100644
index 000000000..4599160a1
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/CatalogDto.java
@@ -0,0 +1,118 @@
+package com.netflix.metacat.common.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.netflix.metacat.common.QualifiedName;
+import com.wordnik.swagger.annotations.ApiModel;
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Information about a catalog
+ */
+@ApiModel("Information about a catalog")
+@SuppressWarnings("unused")
+public class CatalogDto extends BaseDto implements HasDefinitionMetadata {
+ private static final long serialVersionUID = -5713826608609231492L;
+
+ @ApiModelProperty(value = "a list of the names of the databases that belong to this catalog", required = true)
+ private List databases;
+ // Marked as transient because we serialize it manually, however as a JsonProperty because Jackson does serialize it
+ @ApiModelProperty(value = "metadata attached to the logical catalog")
+ @JsonProperty
+ private transient ObjectNode definitionMetadata;
+ @ApiModelProperty(value = "the name of this entity", required = true)
+ @JsonProperty
+ private QualifiedName name;
+ @ApiModelProperty(value = "the type of the connector of this catalog", required = true)
+ private String type;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof CatalogDto)) return false;
+ CatalogDto that = (CatalogDto) o;
+ return Objects.equals(databases, that.databases) &&
+ Objects.equals(definitionMetadata, that.definitionMetadata) &&
+ Objects.equals(name, that.name) &&
+ Objects.equals(type, that.type);
+ }
+
+ /**
+ * @return the list of the names of the databases under the catalog
+ */
+ public List getDatabases() {
+ return databases;
+ }
+
+ /**
+ * @param databases the list of the names of the databases under this catalog
+ */
+ public void setDatabases(List databases) {
+ this.databases = databases;
+ }
+
+ @Override
+ public ObjectNode getDefinitionMetadata() {
+ return definitionMetadata;
+ }
+
+ @Override
+ public void setDefinitionMetadata(ObjectNode metadata) {
+ this.definitionMetadata = metadata;
+ }
+
+ @JsonIgnore
+ public QualifiedName getDefinitionName() {
+ return name;
+ }
+
+ /**
+ * @return name of the catalog
+ */
+ public QualifiedName getName() {
+ return name;
+ }
+
+ /**
+ * @param name The name of this catalog
+ */
+ public void setName(QualifiedName name) {
+ this.name = name;
+ }
+
+ /**
+ * @return the name of the connector
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * @param type the name of the connector used by this catalog
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(databases, definitionMetadata, name, type);
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ definitionMetadata = deserializeObjectNode(in);
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ serializeObjectNode(out, definitionMetadata);
+ }
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/CatalogMappingDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/CatalogMappingDto.java
new file mode 100644
index 000000000..d2005b1cd
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/CatalogMappingDto.java
@@ -0,0 +1,56 @@
+package com.netflix.metacat.common.dto;
+
+import com.wordnik.swagger.annotations.ApiModel;
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import java.util.Objects;
+
+@ApiModel(description = "The name and type of a catalog")
+@SuppressWarnings("unused")
+public class CatalogMappingDto extends BaseDto {
+ private static final long serialVersionUID = -1223516438943164936L;
+
+ @ApiModelProperty(value = "The name of the catalog", required = true)
+ private String catalogName;
+ @ApiModelProperty(value = "The connector type of the catalog", required = true)
+ private String connectorName;
+
+ public CatalogMappingDto() {
+ }
+
+ public CatalogMappingDto(String catalogName, String connectorName) {
+ this.catalogName = catalogName;
+ this.connectorName = connectorName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof CatalogMappingDto)) return false;
+ CatalogMappingDto that = (CatalogMappingDto) o;
+ return Objects.equals(catalogName, that.catalogName) &&
+ Objects.equals(connectorName, that.connectorName);
+ }
+
+ public String getCatalogName() {
+ return catalogName;
+ }
+
+ public void setCatalogName(String catalogName) {
+ this.catalogName = catalogName;
+ }
+
+ public String getConnectorName() {
+ return connectorName;
+ }
+
+ public void setConnectorName(String connectorName) {
+ this.connectorName = connectorName;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(catalogName, connectorName);
+ }
+
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/CreateCatalogDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/CreateCatalogDto.java
new file mode 100644
index 000000000..4e4ddff1d
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/CreateCatalogDto.java
@@ -0,0 +1,45 @@
+package com.netflix.metacat.common.dto;
+
+import com.wordnik.swagger.annotations.ApiModel;
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import java.util.Objects;
+
+/**
+ * Information required to create a new catalog
+ */
+@ApiModel("Information required to create a new catalog")
+public class CreateCatalogDto extends BaseDto {
+ private static final long serialVersionUID = -5037037662666608796L;
+
+ @ApiModelProperty(value = "the type of the connector of this catalog", required = true)
+ private String type;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof CreateCatalogDto)) return false;
+ CreateCatalogDto that = (CreateCatalogDto) o;
+ return Objects.equals(type, that.type);
+ }
+
+ /**
+ * @return the name of the connector
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * @param type the name of the connector used by this catalog
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type);
+ }
+
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/DataMetadataDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/DataMetadataDto.java
new file mode 100644
index 000000000..f8e383be2
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/DataMetadataDto.java
@@ -0,0 +1,72 @@
+package com.netflix.metacat.common.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+/**
+ * Created by amajumdar on 5/28/15.
+ */
+public class DataMetadataDto extends BaseDto implements HasDataMetadata{
+ private static final long serialVersionUID = -874750260731085106L;
+ private String uri;
+ // Marked as transient because we serialize it manually, however as a JsonProperty because Jackson does serialize it
+ @ApiModelProperty(value = "metadata")
+ @JsonProperty
+ private transient ObjectNode dataMetadata;
+
+ public String getUri() {
+ return uri;
+ }
+
+ public void setUri(String uri) {
+ this.uri = uri;
+ }
+
+ public ObjectNode getDataMetadata() {
+ return dataMetadata;
+ }
+
+ public void setDataMetadata(ObjectNode dataMetadata) {
+ this.dataMetadata = dataMetadata;
+ }
+
+ /**
+ * @return The uri that points to the location of the external data
+ * @throws IllegalStateException if this instance does not have external data
+ */
+ @Nonnull
+ @Override
+ @JsonIgnore
+ public String getDataUri() {
+ return uri;
+ }
+
+ /**
+ * @return true if this particular instance points to external data
+ */
+ @Override
+ public boolean isDataExternal() {
+ return false;
+ }
+
+ @SuppressWarnings("EmptyMethod")
+ public void setDataExternal(boolean ignored) {
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ dataMetadata = deserializeObjectNode(in);
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ serializeObjectNode(out, dataMetadata);
+ }
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/DataMetadataGetRequestDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/DataMetadataGetRequestDto.java
new file mode 100644
index 000000000..16dba3369
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/DataMetadataGetRequestDto.java
@@ -0,0 +1,16 @@
+package com.netflix.metacat.common.dto;
+
+/**
+ * Created by amajumdar on 6/26/15.
+ */
+public class DataMetadataGetRequestDto extends BaseDto{
+ private String uri;
+
+ public String getUri() {
+ return uri;
+ }
+
+ public void setUri(String uri) {
+ this.uri = uri;
+ }
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/DatabaseCreateRequestDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/DatabaseCreateRequestDto.java
new file mode 100644
index 000000000..627bcf7e5
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/DatabaseCreateRequestDto.java
@@ -0,0 +1,38 @@
+package com.netflix.metacat.common.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+/**
+ * Created by amajumdar on 5/5/15.
+ */
+public class DatabaseCreateRequestDto extends BaseDto{
+ private static final long serialVersionUID = 6308417213106650174L;
+ // Marked as transient because we serialize it manually, however as a JsonProperty because Jackson does serialize it
+ @ApiModelProperty(value = "metadata attached to the physical data")
+ @JsonProperty
+ private transient ObjectNode definitionMetadata;
+
+ public ObjectNode getDefinitionMetadata() {
+ return definitionMetadata;
+ }
+
+ public void setDefinitionMetadata(ObjectNode definitionMetadata) {
+ this.definitionMetadata = definitionMetadata;
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ definitionMetadata = deserializeObjectNode(in);
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ serializeObjectNode(out, definitionMetadata);
+ }
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/DatabaseDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/DatabaseDto.java
new file mode 100644
index 000000000..81894f330
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/DatabaseDto.java
@@ -0,0 +1,140 @@
+package com.netflix.metacat.common.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.netflix.metacat.common.QualifiedName;
+import com.wordnik.swagger.annotations.ApiModel;
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+@ApiModel("Tables and other information about the given database")
+@SuppressWarnings("unused")
+public class DatabaseDto extends BaseDto implements HasDefinitionMetadata {
+ private static final long serialVersionUID = -4530516372664788451L;
+ private Date dateCreated;
+ // Marked as transient because we serialize it manually, however as a JsonProperty because Jackson does serialize it
+ @ApiModelProperty(value = "metadata attached to the logical database")
+ @JsonProperty
+ private transient ObjectNode definitionMetadata;
+ private Date lastUpdated;
+ @ApiModelProperty(value = "the name of this entity", required = true)
+ @JsonProperty
+ private QualifiedName name;
+ @ApiModelProperty(value = "Names of the tables in this database", required = true)
+ private List tables;
+ @ApiModelProperty(value = "Connector type of this catalog", required = true)
+ private String type;
+ @ApiModelProperty(value = "Any extra metadata properties of the database", required = false)
+ private Map metadata;
+ @ApiModelProperty(value = "URI of the database. Only applies to certain data sources like hive, S3", required = false)
+ private String uri;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof DatabaseDto)) return false;
+ DatabaseDto that = (DatabaseDto) o;
+ return Objects.equals(definitionMetadata, that.definitionMetadata) &&
+ Objects.equals(name, that.name) &&
+ Objects.equals(tables, that.tables) &&
+ Objects.equals(type, that.type) &&
+ Objects.equals(lastUpdated, that.lastUpdated) &&
+ Objects.equals(dateCreated, that.dateCreated) &&
+ Objects.equals(metadata, that.metadata) &&
+ Objects.equals(uri, that.uri);
+ }
+
+ public Date getDateCreated() {
+ return dateCreated;
+ }
+
+ public void setDateCreated(Date dateCreated) {
+ this.dateCreated = dateCreated;
+ }
+
+ @Override
+ public ObjectNode getDefinitionMetadata() {
+ return definitionMetadata;
+ }
+
+ @Override
+ public void setDefinitionMetadata(ObjectNode metadata) {
+ this.definitionMetadata = metadata;
+ }
+
+ @JsonIgnore
+ public QualifiedName getDefinitionName() {
+ return name;
+ }
+
+ public Date getLastUpdated() {
+ return lastUpdated;
+ }
+
+ public void setLastUpdated(Date lastUpdated) {
+ this.lastUpdated = lastUpdated;
+ }
+
+ public QualifiedName getName() {
+ return name;
+ }
+
+ public void setName(QualifiedName name) {
+ this.name = name;
+ }
+
+ public List getTables() {
+ return tables;
+ }
+
+ public void setTables(List tables) {
+ this.tables = tables;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public Map getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(Map metadata) {
+ this.metadata = metadata;
+ }
+
+ public String getUri() {
+ return uri;
+ }
+
+ public void setUri(String uri) {
+ this.uri = uri;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(definitionMetadata, name, tables, type, lastUpdated, dateCreated, metadata, uri);
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ definitionMetadata = deserializeObjectNode(in);
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ serializeObjectNode(out, definitionMetadata);
+ }
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/DefinitionMetadataDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/DefinitionMetadataDto.java
new file mode 100644
index 000000000..47a00d0d9
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/DefinitionMetadataDto.java
@@ -0,0 +1,57 @@
+package com.netflix.metacat.common.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.netflix.metacat.common.QualifiedName;
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+/**
+ * Created by amajumdar on 5/28/15.
+ */
+public class DefinitionMetadataDto extends BaseDto implements HasDefinitionMetadata{
+ private static final long serialVersionUID = 3826462875655878L;
+ private QualifiedName name;
+ // Marked as transient because we serialize it manually, however as a JsonProperty because Jackson does serialize it
+ @ApiModelProperty(value = "metadata")
+ @JsonProperty
+ private transient ObjectNode definitionMetadata;
+
+ public QualifiedName getName() {
+ return name;
+ }
+
+ public void setName(QualifiedName name) {
+ this.name = name;
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ definitionMetadata = deserializeObjectNode(in);
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ serializeObjectNode(out, definitionMetadata);
+ }
+
+ @Override
+ public ObjectNode getDefinitionMetadata() {
+ return definitionMetadata;
+ }
+
+ @Override
+ public void setDefinitionMetadata(ObjectNode definitionMetadata) {
+ this.definitionMetadata = definitionMetadata;
+ }
+
+ @Override
+ @JsonIgnore
+ public QualifiedName getDefinitionName() {
+ return name;
+ }
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/FieldDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/FieldDto.java
new file mode 100644
index 000000000..a799ae234
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/FieldDto.java
@@ -0,0 +1,146 @@
+package com.netflix.metacat.common.dto;
+
+import com.wordnik.swagger.annotations.ApiModel;
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import java.util.Objects;
+
+@ApiModel(value = "Table field/column metadata")
+@SuppressWarnings("unused")
+public class FieldDto extends BaseDto {
+ private static final long serialVersionUID = 9096928516299407324L;
+
+ @ApiModelProperty(value = "Comment of the field/column", required = false)
+ private String comment;
+ @ApiModelProperty(value = "Name of the field/column", required = true)
+ private String name;
+ @ApiModelProperty(value = "Is it a partition Key. If true, it is a partition key.", required = false)
+ private boolean partition_key;
+ @ApiModelProperty(value = "Position of the field/column", required = true)
+ private Integer pos;
+ @ApiModelProperty(value = "Source type of the field/column", required = false)
+ private String source_type;
+ @ApiModelProperty(value = "Type of the field/column", required = true)
+ private String type;
+ @ApiModelProperty(value = "Can the field/column be null", required = false)
+ private Boolean isNullable;
+ @ApiModelProperty(value = "Size of the field/column", required = false)
+ private Integer size;
+ @ApiModelProperty(value = "Default value of the column", required = false)
+ private String defaultValue;
+ @ApiModelProperty(value = "Is the column a sorted key", required = false)
+ private Boolean isSortKey;
+ @ApiModelProperty(value = "Is the column an index key", required = false)
+ private Boolean isIndexKey;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof FieldDto)) return false;
+ FieldDto fieldDto = (FieldDto) o;
+ return Objects.equals(partition_key, fieldDto.partition_key) &&
+ Objects.equals(pos, fieldDto.pos) &&
+ Objects.equals(comment, fieldDto.comment) &&
+ Objects.equals(name, fieldDto.name) &&
+ Objects.equals(source_type, fieldDto.source_type) &&
+ Objects.equals(type, fieldDto.type) &&
+ Objects.equals(isNullable, fieldDto.isNullable) &&
+ Objects.equals(size, fieldDto.size) &&
+ Objects.equals(defaultValue, fieldDto.defaultValue) &&
+ Objects.equals(isSortKey, fieldDto.isSortKey) &&
+ Objects.equals(isIndexKey, fieldDto.isIndexKey);
+ }
+
+ public String getComment() {
+ return comment;
+ }
+
+ public void setComment(String comment) {
+ this.comment = comment;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getPos() {
+ return pos;
+ }
+
+ public void setPos(Integer pos) {
+ this.pos = pos;
+ }
+
+ public String getSource_type() {
+ return source_type;
+ }
+
+ public void setSource_type(String source_type) {
+ this.source_type = source_type;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(comment, name, partition_key, pos, source_type, type, isNullable, size, defaultValue, isSortKey, isIndexKey);
+ }
+
+ public boolean isPartition_key() {
+ return partition_key;
+ }
+
+ public void setPartition_key(boolean partition_key) {
+ this.partition_key = partition_key;
+ }
+
+ public Boolean getIsNullable() {
+ return isNullable;
+ }
+
+ public void setIsNullable(Boolean isNullable) {
+ this.isNullable = isNullable;
+ }
+
+ public Integer getSize() {
+ return size;
+ }
+
+ public void setSize(Integer size) {
+ this.size = size;
+ }
+
+ public String getDefaultValue() {
+ return defaultValue;
+ }
+
+ public void setDefaultValue(String defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ public Boolean getIsSortKey() {
+ return isSortKey;
+ }
+
+ public void setIsSortKey(Boolean isSortKey) {
+ this.isSortKey = isSortKey;
+ }
+
+ public Boolean getIsIndexKey() {
+ return isIndexKey;
+ }
+
+ public void setIsIndexKey(Boolean isIndexKey) {
+ this.isIndexKey = isIndexKey;
+ }
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/GetPartitionsRequestDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/GetPartitionsRequestDto.java
new file mode 100644
index 000000000..c21a00081
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/GetPartitionsRequestDto.java
@@ -0,0 +1,36 @@
+package com.netflix.metacat.common.dto;
+
+import java.util.List;
+
+/**
+ * Created by amajumdar on 5/28/15.
+ */
+public class GetPartitionsRequestDto extends BaseDto{
+ String filter;
+ List partitionNames;
+ Boolean includePartitionDetails = false;
+
+ public String getFilter() {
+ return filter;
+ }
+
+ public void setFilter(String filter) {
+ this.filter = filter;
+ }
+
+ public List getPartitionNames() {
+ return partitionNames;
+ }
+
+ public void setPartitionNames(List partitionNames) {
+ this.partitionNames = partitionNames;
+ }
+
+ public Boolean getIncludePartitionDetails() {
+ return includePartitionDetails!=null?includePartitionDetails:false;
+ }
+
+ public void setIncludePartitionDetails(Boolean includePartitionDetails) {
+ this.includePartitionDetails = includePartitionDetails;
+ }
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/HasDataMetadata.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/HasDataMetadata.java
new file mode 100644
index 000000000..9af6bca78
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/HasDataMetadata.java
@@ -0,0 +1,26 @@
+package com.netflix.metacat.common.dto;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Marker interface for objects with data metadata
+ */
+public interface HasDataMetadata extends HasMetadata {
+ ObjectNode getDataMetadata();
+
+ void setDataMetadata(ObjectNode metadata);
+
+ /**
+ * @return The uri that points to the location of the external data
+ * @throws IllegalStateException if this instance does not have external data
+ */
+ @Nonnull
+ String getDataUri();
+
+ /**
+ * @return true if this particular instance points to external data
+ */
+ boolean isDataExternal();
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/HasDefinitionMetadata.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/HasDefinitionMetadata.java
new file mode 100644
index 000000000..7e2d6dc6a
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/HasDefinitionMetadata.java
@@ -0,0 +1,15 @@
+package com.netflix.metacat.common.dto;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.netflix.metacat.common.QualifiedName;
+
+/**
+ * Marker interface for objects with data metadata
+ */
+public interface HasDefinitionMetadata extends HasMetadata {
+ ObjectNode getDefinitionMetadata();
+
+ void setDefinitionMetadata(ObjectNode metadata);
+
+ QualifiedName getDefinitionName();
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/HasMetadata.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/HasMetadata.java
new file mode 100644
index 000000000..163b70bd1
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/HasMetadata.java
@@ -0,0 +1,9 @@
+package com.netflix.metacat.common.dto;
+
+import java.io.Serializable;
+
+/**
+ * Marker interface for objects with metadata
+ */
+public interface HasMetadata extends Serializable {
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/PartitionDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/PartitionDto.java
new file mode 100644
index 000000000..2df4e5ce2
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/PartitionDto.java
@@ -0,0 +1,145 @@
+package com.netflix.metacat.common.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.netflix.metacat.common.QualifiedName;
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Map;
+import java.util.Objects;
+
+@SuppressWarnings("unused")
+public class PartitionDto extends BaseDto implements HasDataMetadata, HasDefinitionMetadata {
+ private static final long serialVersionUID = 783462697901395508L;
+ @ApiModelProperty(value = "audit information about the partition")
+ private AuditDto audit;
+ // Marked as transient because we serialize it manually, however as a JsonProperty because Jackson does serialize it
+ @ApiModelProperty(value = "metadata attached to this partition")
+ @JsonProperty
+ private transient ObjectNode dataMetadata;
+ // Marked as transient because we serialize it manually, however as a JsonProperty because Jackson does serialize it
+ @ApiModelProperty(value = "metadata attached to the physical data")
+ @JsonProperty
+ private transient ObjectNode definitionMetadata;
+ @ApiModelProperty(value = "the name of this entity", required = true)
+ @JsonProperty
+ private QualifiedName name;
+ @ApiModelProperty(value = "Storage/Serialization/Deserialization info of the partition ")
+ private StorageDto serde;
+ @ApiModelProperty(value = "Any extra metadata properties of the partition", required = false)
+ private Map metadata;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof PartitionDto)) return false;
+ PartitionDto that = (PartitionDto) o;
+ return Objects.equals(audit, that.audit) &&
+ Objects.equals(dataMetadata, that.dataMetadata) &&
+ Objects.equals(definitionMetadata, that.definitionMetadata) &&
+ Objects.equals(name, that.name) &&
+ Objects.equals(serde, that.serde) &&
+ Objects.equals(metadata, that.metadata);
+ }
+
+ public AuditDto getAudit() {
+ return audit;
+ }
+
+ public void setAudit(AuditDto audit) {
+ this.audit = audit;
+ }
+
+ @Override
+ public ObjectNode getDataMetadata() {
+ return dataMetadata;
+ }
+
+ @Override
+ public void setDataMetadata(ObjectNode metadata) {
+ this.dataMetadata = metadata;
+ }
+
+ @Nonnull
+ @Override
+ @JsonIgnore
+ public String getDataUri() {
+ String uri = serde != null ? serde.getUri() : null;
+ if (uri == null || uri.isEmpty()) {
+ throw new IllegalStateException("This instance does not have external data");
+ }
+
+ return uri;
+ }
+
+ @Override
+ public ObjectNode getDefinitionMetadata() {
+ return definitionMetadata;
+ }
+
+ @Override
+ public void setDefinitionMetadata(ObjectNode metadata) {
+ this.definitionMetadata = metadata;
+ }
+
+ public QualifiedName getName() {
+ return name;
+ }
+
+ public void setName(QualifiedName name) {
+ this.name = name;
+ }
+
+ @JsonIgnore
+ public QualifiedName getDefinitionName() {
+ return name;
+ }
+
+ public StorageDto getSerde() {
+ return serde;
+ }
+
+ public void setSerde(StorageDto serde) {
+ this.serde = serde;
+ }
+
+ public Map getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(Map metadata) {
+ this.metadata = metadata;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(audit, dataMetadata, definitionMetadata, name, serde, metadata);
+ }
+
+ @Override
+ @JsonProperty
+ public boolean isDataExternal() {
+ return serde != null && serde.getUri() != null && !serde.getUri().isEmpty();
+ }
+
+ @SuppressWarnings("EmptyMethod")
+ public void setDataExternal(boolean ignored) {
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ dataMetadata = deserializeObjectNode(in);
+ definitionMetadata = deserializeObjectNode(in);
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ serializeObjectNode(out, dataMetadata);
+ serializeObjectNode(out, definitionMetadata);
+ }
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/PartitionsSaveRequestDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/PartitionsSaveRequestDto.java
new file mode 100644
index 000000000..ef9f4bd88
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/PartitionsSaveRequestDto.java
@@ -0,0 +1,85 @@
+package com.netflix.metacat.common.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.wordnik.swagger.annotations.ApiModelProperty;
+import com.wordnik.swagger.annotations.ApiParam;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.List;
+
+/**
+ * Created by amajumdar on 5/4/15.
+ */
+public class PartitionsSaveRequestDto extends BaseDto{
+ private static final long serialVersionUID = -5922699691074685961L;
+ // Marked as transient because we serialize it manually, however as a JsonProperty because Jackson does serialize it
+ @ApiModelProperty(value = "metadata attached to this table")
+ @JsonProperty
+ private transient ObjectNode dataMetadata;
+ // Marked as transient because we serialize it manually, however as a JsonProperty because Jackson does serialize it
+ @ApiModelProperty(value = "metadata attached to the physical data")
+ @JsonProperty
+ private transient ObjectNode definitionMetadata;
+ // List of partitions
+ @ApiParam(value = "List of partitions", required = true)
+ private List partitions;
+ // List of partition ids/names for deletes
+ private List partitionIdsForDeletes;
+ // If true, we check if partition exists and drop it before adding it back. If false, we do not check and just add.
+ private Boolean checkIfExists = true;
+
+ public ObjectNode getDataMetadata() {
+ return dataMetadata;
+ }
+
+ public void setDataMetadata(ObjectNode dataMetadata) {
+ this.dataMetadata = dataMetadata;
+ }
+
+ public ObjectNode getDefinitionMetadata() {
+ return definitionMetadata;
+ }
+
+ public void setDefinitionMetadata(ObjectNode definitionMetadata) {
+ this.definitionMetadata = definitionMetadata;
+ }
+
+ public List getPartitions() {
+ return partitions;
+ }
+
+ public void setPartitions(List partitions) {
+ this.partitions = partitions;
+ }
+
+ public List getPartitionIdsForDeletes() {
+ return partitionIdsForDeletes;
+ }
+
+ public void setPartitionIdsForDeletes(List partitionNamesForDeletes) {
+ this.partitionIdsForDeletes = partitionNamesForDeletes;
+ }
+
+ public Boolean getCheckIfExists() {
+ return checkIfExists;
+ }
+
+ public void setCheckIfExists(Boolean checkIfExists) {
+ this.checkIfExists = checkIfExists;
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ dataMetadata = deserializeObjectNode(in);
+ definitionMetadata = deserializeObjectNode(in);
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ serializeObjectNode(out, dataMetadata);
+ serializeObjectNode(out, definitionMetadata);
+ }
+}
diff --git a/metacat-common/src/main/java/com/netflix/metacat/common/dto/PartitionsSaveResponseDto.java b/metacat-common/src/main/java/com/netflix/metacat/common/dto/PartitionsSaveResponseDto.java
new file mode 100644
index 000000000..e06312b65
--- /dev/null
+++ b/metacat-common/src/main/java/com/netflix/metacat/common/dto/PartitionsSaveResponseDto.java
@@ -0,0 +1,37 @@
+package com.netflix.metacat.common.dto;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by amajumdar on 5/28/15.
+ */
+public class PartitionsSaveResponseDto extends BaseDto{
+ List added;
+ List