blob: 5ecc2d13313c68c9c2421fb1cf1e4e74d6a87a97 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.parquet.hive;
import java.lang.reflect.Method;
import org.apache.parquet.hive.internal.Hive010Binding;
import org.apache.parquet.hive.internal.Hive012Binding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Factory for creating HiveBinding objects based on the version of Hive
* available in the classpath. This class does not provide static methods
* to enable mocking.
*/
public class HiveBindingFactory {
private static final Logger LOG = LoggerFactory.getLogger(HiveBindingFactory.class);
private static final String HIVE_VERSION_CLASS_NAME = "org.apache.hive.common.util.HiveVersionInfo";
private static final String HIVE_VERSION_METHOD_NAME = "getVersion";
private static final String HIVE_UTILITIES_CLASS_NAME = "org.apache.hadoop.hive.ql.exec.Utilities";
private static final String HIVE_012_INDICATOR_UTILITIES_GETMAPWORK = "getMapWork";
private static final String HIVE_VERSION_NULL = "<null>";
private static final Class<? extends HiveBinding> LATEST_BINDING = Hive012Binding.class;
static final String HIVE_VERSION_UNKNOWN = "Unknown";
static final String HIVE_VERSION_010 = "0.10";
static final String HIVE_VERSION_011 = "0.11";
static final String HIVE_VERSION_012 = "0.12";
static final String HIVE_VERSION_013 = "0.13";
/**
* @return HiveBinding based on the Hive version in the classpath
*/
public HiveBinding create() {
Class<? extends HiveBinding> bindingClazz = create(HiveBindingFactory.class
.getClassLoader());
try {
return bindingClazz.newInstance();
} catch (Exception e) {
throw new HiveBindingInstantiationError("Unexpected error creating instance"
+ " of " + bindingClazz.getCanonicalName(), e);
}
}
/**
* Internal method visible for testing purposes
*/
@SuppressWarnings("rawtypes")
Class<? extends HiveBinding> create(ClassLoader classLoader) {
// HiveVersionInfo was added in 0.11, if the class does
// not exist then return the hive binding for 0.10
Class hiveVersionInfo;
try {
hiveVersionInfo = Class.forName(HIVE_VERSION_CLASS_NAME, true, classLoader);
} catch (ClassNotFoundException e) {
LOG.debug("Class " + HIVE_VERSION_CLASS_NAME + ", not found, returning {}",
Hive010Binding.class.getSimpleName());
return Hive010Binding.class;
}
return createInternal(hiveVersionInfo);
}
/**
* Internal method visible for testing purposes
*/
@SuppressWarnings({"unchecked", "rawtypes"})
Class<? extends HiveBinding> createInternal(Class hiveVersionInfo) {
String hiveVersion;
try {
Method getVersionMethod = hiveVersionInfo.
getMethod(HIVE_VERSION_METHOD_NAME, (Class[])null);
String rawVersion = (String)getVersionMethod.invoke(null, (Object[])null);
LOG.debug("Raw Version from {} is '{}'", hiveVersionInfo.getSimpleName(), rawVersion);
hiveVersion = trimVersion(rawVersion);
} catch (Exception e) {
throw new UnexpectedHiveVersionProviderError("Unexpected error whilst " +
"determining Hive version", e);
}
if(hiveVersion.equalsIgnoreCase(HIVE_VERSION_UNKNOWN)) {
LOG.debug("Unknown hive version, attempting to guess");
return createBindingForUnknownVersion();
}
if(hiveVersion.startsWith(HIVE_VERSION_010)) {
LOG.debug("Hive version {}, returning {}", hiveVersion, Hive010Binding.class.getSimpleName());
return Hive010Binding.class;
} else if(hiveVersion.startsWith(HIVE_VERSION_011)) {
LOG.debug("Hive version " + hiveVersion + ", returning " +
Hive010Binding.class.getSimpleName() + " as it's expected the 0.10 " +
"binding will work with 0.11");
return Hive010Binding.class;
} else if(hiveVersion.startsWith(HIVE_VERSION_013)) {
throw new HiveBindingInstantiationError("Hive 0.13 contains native Parquet support " +
"and the parquet-hive jars from the parquet project should not be included " +
"in Hive's classpath.");
}
LOG.debug("Hive version {}, returning {}", hiveVersion,
Hive012Binding.class.getSimpleName());
// as of 11/26/2013 it looks like the 0.12 binding will work for 0.13
return Hive012Binding.class;
}
private Class<? extends HiveBinding> createBindingForUnknownVersion() {
try {
Class<?> utilitiesClass = Class.forName(HIVE_UTILITIES_CLASS_NAME);
for(Method method : utilitiesClass.getDeclaredMethods()) {
if(HIVE_012_INDICATOR_UTILITIES_GETMAPWORK.equals(method.getName())) {
LOG.debug("Found " + HIVE_UTILITIES_CLASS_NAME + "." +
HIVE_012_INDICATOR_UTILITIES_GETMAPWORK + " returning 0.12 binding");
return Hive012Binding.class;
}
}
// if the getMapWork method does not exist then it must be 0.10 or 0.11
return Hive010Binding.class;
} catch (ClassNotFoundException e) {
LOG.debug("Could not find " + HIVE_UTILITIES_CLASS_NAME + ", returning" +
" the latest binding since this class existed in 0.10, 0.11, and 0.12");
return LATEST_BINDING;
}
}
private static String trimVersion(String s) {
if(s == null) {
return HIVE_VERSION_NULL;
}
return s.trim();
}
static class HiveBindingInstantiationError extends Error {
private static final long serialVersionUID = -9348060142128L;
public HiveBindingInstantiationError(String msg) {
super(msg);
}
public HiveBindingInstantiationError(String msg, Exception e) {
super(msg, e);
}
}
static class UnexpectedHiveVersionProviderError extends Error {
private static final long serialVersionUID = -7344858060142118L;
public UnexpectedHiveVersionProviderError(String msg, Exception e) {
super(msg, e);
}
}
}