blob: edc3afc710f8ff8fe4a0ede579ecd89c2f9d1580 [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.sentry.hdfs;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import com.google.common.annotations.VisibleForTesting;
import org.apache.sentry.hdfs.service.thrift.TPathChanges;
import org.apache.sentry.hdfs.service.thrift.TPathsUpdate;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.conf.Configuration;
import org.apache.http.client.utils.URIBuilder;
import org.apache.thrift.TException;
import static org.apache.sentry.hdfs.service.thrift.sentry_hdfs_serviceConstants.UNUSED_PATH_UPDATE_IMG_NUM;
/**
* A wrapper class over the TPathsUpdate thrift generated class. Please see
* {@link Updateable.Update} for more information
*/
public class PathsUpdate implements Updateable.Update {
public static final String ALL_PATHS = "__ALL_PATHS__";
private static final Configuration CONF = new Configuration();
private static String DEFAULT_SCHEME = FileSystem.getDefaultUri(CONF).getScheme();
private static final String SUPPORTED_SCHEME = "hdfs";
private final TPathsUpdate tPathsUpdate;
public PathsUpdate() {
this(0, false);
}
public PathsUpdate(TPathsUpdate tPathsUpdate) {
this.tPathsUpdate = tPathsUpdate;
}
public PathsUpdate(long seqNum, boolean hasFullImage) {
this(seqNum, UNUSED_PATH_UPDATE_IMG_NUM, hasFullImage);
}
public PathsUpdate(long seqNum, long imgNum, boolean hasFullImage) {
tPathsUpdate = new TPathsUpdate(hasFullImage, seqNum, new ArrayList<TPathChanges>());
tPathsUpdate.setImgNum(imgNum);
}
@Override
public boolean hasFullImage() {
return tPathsUpdate.isHasFullImage();
}
public TPathChanges newPathChange(String authzObject) {
TPathChanges pathChanges = new TPathChanges(authzObject,
new ArrayList<List<String>>(), new ArrayList<List<String>>());
tPathsUpdate.addToPathChanges(pathChanges);
return pathChanges;
}
List<TPathChanges> getPathChanges() {
return tPathsUpdate.getPathChanges();
}
@Override
public long getSeqNum() {
return tPathsUpdate.getSeqNum();
}
@Override
public void setSeqNum(long seqNum) {
tPathsUpdate.setSeqNum(seqNum);
}
@Override
public long getImgNum() {
return tPathsUpdate.getImgNum();
}
@Override
public void setImgNum(long imgNum) {
tPathsUpdate.setImgNum(imgNum);
}
public TPathsUpdate toThrift() {
return tPathsUpdate;
}
/**
* Only used for testing.
* @param scheme new default scheme
*/
@VisibleForTesting
public static void setDefaultScheme(String scheme) {
DEFAULT_SCHEME = scheme;
}
/**
* Convert URI to path, trimming leading slash.
* @param path HDFS location in one of the forms:
* <ul>
* <li>hdfs://hostname:port/path
* <li>hdfs:///path
* <li>/path, in which case, scheme will be constructed from FileSystem.getDefaultURI
* <li>URIs with non hdfs schemee will just be ignored
* </ul>
* @return Path with scheme/ authority stripped off.
* Returns null if a non HDFS path or if path is null/empty.
*/
public static String parsePath(String path) throws SentryMalformedPathException {
if (StringUtils.isEmpty(path)) {
return null;
}
URI uri;
try {
// Below converts unescaped path to escaped string and the constructs a URI from it.
uri = new URI(StringUtils.stripStart(new URIBuilder().setPath(path).toString(), "/"));
} catch (URISyntaxException e) {
throw new SentryMalformedPathException("Incomprehensible path [" + path + "]", e);
}
String scheme = uri.getScheme();
if (scheme == null) {
scheme = DEFAULT_SCHEME;
if(scheme == null) {
throw new SentryMalformedPathException(
"Scheme is missing and could not be constructed from configuration");
}
}
// Non-HDFS paths are skipped.
if(!scheme.equalsIgnoreCase(SUPPORTED_SCHEME)) {
return null;
}
String uriPath = uri.getPath();
if(uriPath == null) {
throw new SentryMalformedPathException("Path is empty. uri=" + uri);
}
if (!uriPath.startsWith("/")) {
throw new SentryMalformedPathException("Path part of uri does not seem right, was expecting a non empty path" +
": path = " + uriPath + ", uri=" + uri);
}
// Reduce multiple consecutive forward slashes to one.
// It's probably a rare case, so use indexOf() before expensive regex.
if (uriPath.indexOf("//") >= 0) {
uriPath = uriPath.replaceAll("//*", "/");
}
// Remove leading and trailing slashes
return StringUtils.strip(uriPath, "/");
}
@Override
public byte[] serialize() throws IOException {
return ThriftSerializer.serialize(tPathsUpdate);
}
@Override
public void deserialize(byte[] data) throws IOException {
ThriftSerializer.deserialize(tPathsUpdate, data);
}
@Override
public void JSONDeserialize(String update) throws TException {
ThriftSerializer.deserializeFromJSON(tPathsUpdate, update);
}
@Override
public String JSONSerialize() throws TException {
return ThriftSerializer.serializeToJSON(tPathsUpdate);
}
@Override
public int hashCode() {
return (tPathsUpdate == null) ? 0 : tPathsUpdate.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (getClass() != obj.getClass()) {
return false;
}
PathsUpdate other = (PathsUpdate) obj;
if (tPathsUpdate == null) {
return other.tPathsUpdate == null;
}
return tPathsUpdate.equals(other.tPathsUpdate);
}
@Override
public String toString() {
// TPathsUpdate implements toString() perfectly; null tPathsUpdate is ok
return getClass().getSimpleName() + "(" + tPathsUpdate + ")";
}
}