/* * 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.ranger.plugin.store.file; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.PathFilter; import org.apache.ranger.plugin.model.RangerPolicy; import org.apache.ranger.plugin.model.RangerService; import org.apache.ranger.plugin.model.RangerServiceDef; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class FileStoreUtil { private static final Log LOG = LogFactory.getLog(FileStoreUtil.class); private Gson gsonBuilder; private String dataDir; private static final String FILE_SUFFIX_JSON = ".json"; public void initStore(String dataDir) { this.dataDir = dataDir; try { gsonBuilder = new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z").setPrettyPrinting().create(); } catch(Throwable excp) { LOG.fatal("FileStoreUtil.init(): failed to create GsonBuilder object", excp); } } public String getDataDir() { return dataDir; } public String getDataFile(String filePrefix, Long id) { String filePath = dataDir + Path.SEPARATOR + filePrefix + id + FILE_SUFFIX_JSON; return filePath; } public String getDataFile(String filePrefix, Long parentId, Long objectId) { String filePath = dataDir + Path.SEPARATOR + filePrefix + parentId + "-" + objectId + FILE_SUFFIX_JSON; return filePath; } public <T> T loadFromResource(String resource, Class<T> cls) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> FileStoreUtil.loadFromResource(" + resource + ")"); } InputStream inStream = this.getClass().getResourceAsStream(resource); T ret = loadFromStream(inStream, cls); if(LOG.isDebugEnabled()) { LOG.debug("<== FileStoreUtil.loadFromResource(" + resource + "): " + ret); } return ret; } public <T> T loadFromStream(InputStream inStream, Class<T> cls) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> FileStoreUtil.loadFromStream()"); } InputStreamReader reader = new InputStreamReader(inStream); T ret = gsonBuilder.fromJson(reader, cls); if(LOG.isDebugEnabled()) { LOG.debug("<== FileStoreUtil.loadFromStream(): " + ret); } return ret; } public <T> T loadFromFile(Path filePath, Class<T> cls) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> FileStoreUtil.loadFromFile(" + filePath + ")"); } T ret = null; InputStreamReader reader = null; try { FileSystem fileSystem = getFileSystem(filePath); FSDataInputStream inStream = fileSystem.open(filePath); ret = loadFromStream(inStream, cls); } finally { close(reader); } if(LOG.isDebugEnabled()) { LOG.debug("<== FileStoreUtil.loadFromFile(" + filePath + "): " + ret); } return ret; } public <T> List<T> loadFromDir(Path dirPath, final String filePrefix, Class<T> cls) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> FileStoreUtil.loadFromDir()"); } List<T> ret = new ArrayList<>(); try { FileSystem fileSystem = getFileSystem(dirPath); if(fileSystem.exists(dirPath) && fileSystem.isDirectory(dirPath)) { PathFilter filter = new PathFilter() { @Override public boolean accept(Path path) { return path.getName().startsWith(filePrefix) && path.getName().endsWith(FILE_SUFFIX_JSON); } }; FileStatus[] sdFiles = fileSystem.listStatus(dirPath, filter); if(sdFiles != null) { for(FileStatus sdFile : sdFiles) { T obj = loadFromFile(sdFile.getPath(), cls); if(obj != null) { ret.add(obj); } } } } else { LOG.error(dirPath + ": does not exists or not a directory"); } } catch(IOException excp) { LOG.warn("error loading service-def in directory " + dirPath, excp); } if(LOG.isDebugEnabled()) { LOG.debug("<== FileStoreUtil.loadFromDir(): count=" + (ret == null ? 0 : ret.size())); } return ret; } public <T> T saveToFile(T obj, Path filePath, boolean overWrite) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> FileStoreUtil.saveToFile(" + filePath + ")"); } OutputStreamWriter writer = null; try { FileSystem fileSystem = getFileSystem(filePath); FSDataOutputStream outStream = fileSystem.create(filePath, overWrite); writer = new OutputStreamWriter(outStream); gsonBuilder.toJson(obj, writer); } finally { close(writer); } if(LOG.isDebugEnabled()) { LOG.debug("<== FileStoreUtil.saveToFile(" + filePath + "): " + obj); } return obj; } public boolean deleteFile(Path filePath) throws Exception { LOG.debug("==> FileStoreUtil.deleteFile(" + filePath + ")"); FileSystem fileSystem = getFileSystem(filePath); boolean ret = false; if(fileSystem.exists(filePath)) { ret = fileSystem.delete(filePath, false); } else { ret = true; // nothing to delete } LOG.debug("<== FileStoreUtil.deleteFile(" + filePath + "): " + ret); return ret; } public boolean renamePath(Path oldPath, Path newPath) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> FileStoreUtil.renamePath(" + oldPath + "," + newPath + ")"); } FileSystem fileSystem = getFileSystem(oldPath); boolean ret = false; if(fileSystem.exists(oldPath)) { if(! fileSystem.exists(newPath)) { ret = fileSystem.rename(oldPath, newPath); } else { LOG.warn("target of rename '" + newPath + "' already exists"); } } if(LOG.isDebugEnabled()) { LOG.debug("<== FileStoreUtil.renamePath(" + oldPath + "," + newPath + "): " + ret); } return ret; } public RangerServiceDef saveToFile(RangerServiceDef serviceDef, String filePrefix, boolean overWrite) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> FileStoreUtil.saveToFile(" + serviceDef + "," + overWrite + ")"); } Path filePath = new Path(getDataFile(filePrefix, serviceDef.getId())); RangerServiceDef ret = saveToFile(serviceDef, filePath, overWrite); if(LOG.isDebugEnabled()) { LOG.debug("<== FileStoreUtil.saveToFile(" + serviceDef + "," + overWrite + "): "); } return ret; } public RangerService saveToFile(RangerService service, String filePrefix,boolean overWrite) throws Exception { Path filePath = new Path(getDataFile(filePrefix, service.getId())); RangerService ret = saveToFile(service, filePath, overWrite); return ret; } public RangerPolicy saveToFile(RangerPolicy policy, String filePrefix, long serviceId, boolean overWrite) throws Exception { Path filePath = new Path(getDataFile(filePrefix, serviceId, policy.getId())); RangerPolicy ret = saveToFile(policy, filePath, overWrite); return ret; } public FileSystem getFileSystem(Path filePath) throws Exception { Configuration conf = new Configuration(); FileSystem fileSystem = filePath.getFileSystem(conf); return fileSystem; } protected void close(FileSystem fs) { if(fs != null) { try { fs.close(); } catch(IOException excp) { // ignore } } } protected void close(InputStreamReader reader) { if(reader != null) { try { reader.close(); } catch(IOException excp) { // ignore } } } protected void close(OutputStreamWriter writer) { if(writer != null) { try { writer.close(); } catch(IOException excp) { // ignore } } } }