From b69e6bf0f418ad585283db61424afc5cfbe7ae22 Mon Sep 17 00:00:00 2001 From: AnuGayan Date: Thu, 26 Oct 2023 10:05:37 +0530 Subject: [PATCH 1/3] Add file rename function support (cherry picked from commit d1882a4b0e9e5783f73991b32ee2ae31724c606d) --- .../execution/file/FileRenameExtension.java | 200 ++++++++++++++++++ .../io/file/metrics/FileRenameMetrics.java | 49 +++++ 2 files changed, 249 insertions(+) create mode 100644 component/src/main/java/io/siddhi/extension/execution/file/FileRenameExtension.java create mode 100644 component/src/main/java/io/siddhi/extension/io/file/metrics/FileRenameMetrics.java diff --git a/component/src/main/java/io/siddhi/extension/execution/file/FileRenameExtension.java b/component/src/main/java/io/siddhi/extension/execution/file/FileRenameExtension.java new file mode 100644 index 00000000..15f9bc14 --- /dev/null +++ b/component/src/main/java/io/siddhi/extension/execution/file/FileRenameExtension.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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 io.siddhi.extension.execution.file; + +import io.siddhi.annotation.Example; +import io.siddhi.annotation.Extension; +import io.siddhi.annotation.Parameter; +import io.siddhi.annotation.ParameterOverload; +import io.siddhi.annotation.ReturnAttribute; +import io.siddhi.annotation.util.DataType; +import io.siddhi.core.config.SiddhiQueryContext; +import io.siddhi.core.exception.SiddhiAppRuntimeException; +import io.siddhi.core.executor.ConstantExpressionExecutor; +import io.siddhi.core.executor.ExpressionExecutor; +import io.siddhi.core.query.processor.stream.function.StreamFunctionProcessor; +import io.siddhi.core.util.config.ConfigReader; +import io.siddhi.core.util.snapshot.state.StateFactory; +import io.siddhi.extension.io.file.metrics.FileRenameMetrics; +import io.siddhi.extension.io.file.util.Constants; +import io.siddhi.extension.util.Utils; +import io.siddhi.query.api.definition.AbstractDefinition; +import io.siddhi.query.api.definition.Attribute; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.Selectors; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.wso2.carbon.si.metrics.core.internal.MetricsDataHolder; + +import java.util.ArrayList; +import java.util.List; + +/** + * + **/ +@Extension( + name = "rename", + namespace = "file", + description = "Rename file/folder in a particular path", + parameters = { + @Parameter( + name = "uri", + description = "Absolute path of the file or the directory to be rename.", + type = DataType.STRING, + dynamic = true + ), + @Parameter( + name = "new.destination.name", + description = "Absolute path of the new file/folder", + type = DataType.STRING, + dynamic = true + ), + @Parameter( + name = "file.system.options", + description = "The file options in key:value pairs separated by commas. \n" + + "eg:'USER_DIR_IS_ROOT:false,PASSIVE_MODE:true,AVOID_PERMISSION_CHECK:true," + + "IDENTITY:/wso2/server/' directory>," + + "IDENTITY_PASS_PHRASE:wso2carbon'\n" + + "Note: when IDENTITY is used, use a RSA PRIVATE KEY", + type = DataType.STRING, + optional = true, + defaultValue = "" + ) + }, + parameterOverloads = { + @ParameterOverload( + parameterNames = {"uri", "new.destination.name"} + ), + }, + returnAttributes = { + @ReturnAttribute( + name = "isSuccess", + description = "Status of the file rename operation (true if success)", + type = DataType.BOOL + ) + }, + examples = { + @Example( + syntax = "InputStream#" + + "file:rename('/User/wso2/source/', 'User/wso2/destination/')", + description = "Rename the file resides in 'source' folder to 'destination' folder." + ), + @Example( + syntax = "InputStream#" + + "file:rename('/User/wso2/folder/old.csv', 'User/wso2/folder/new.txt')", + description = "Rename 'old.csv' file resides in folder to 'new.txt'" + ) + } +) +public class FileRenameExtension extends StreamFunctionProcessor { + private static final Logger log = LogManager.getLogger(FileRenameExtension.class); + private String fileSystemOptions = null; + + private FileRenameMetrics fileRenameMetrics; + + @Override + protected Object[] process(Object[] objects) { + return renameFileOrFolder((String) objects[0], (String) objects[1]); + } + + @Override + protected Object[] process(Object o) { + return new Object[0]; + } + + @Override + protected StateFactory init(AbstractDefinition abstractDefinition, ExpressionExecutor[] expressionExecutors, + ConfigReader configReader, boolean outputExpectsExpiredEvents, + SiddhiQueryContext siddhiQueryContext) { + if (attributeExpressionExecutors.length == 3) { + fileSystemOptions = ((ConstantExpressionExecutor) attributeExpressionExecutors[2]).getValue().toString(); + } + if (MetricsDataHolder.getInstance().getMetricService() != null && + MetricsDataHolder.getInstance().getMetricManagementService().isEnabled()) { + try { + if (MetricsDataHolder.getInstance().getMetricManagementService().isReporterRunning( + Constants.PROMETHEUS_REPORTER_NAME)) { + String siddhiAppName = siddhiQueryContext.getSiddhiAppContext().getName(); + fileRenameMetrics = new FileRenameMetrics(siddhiAppName); + } + } catch (IllegalArgumentException e) { + log.debug("Prometheus reporter is not running. Hence file metrics will not be initialized."); + } + } + return null; + + } + + @Override + public List getReturnAttributes() { + List attributes = new ArrayList<>(); + attributes.add(new Attribute("isSuccess", Attribute.Type.BOOL)); + return attributes; + } + + @Override + public void start() { + + } + + @Override + public void stop() { + + } + + private Object[] renameFileOrFolder(String oldFileOrFolderName, String newFileOrFolderName) { + + if (fileRenameMetrics != null) { + fileRenameMetrics.setSource(oldFileOrFolderName); + fileRenameMetrics.setTime(System.currentTimeMillis()); + } + FileObject oldFileObject = Utils.getFileObject(oldFileOrFolderName, fileSystemOptions); + FileObject newFileObject = Utils.getFileObject(newFileOrFolderName, fileSystemOptions); + try { + oldFileObject.canRenameTo(newFileObject); + + newFileObject.copyFrom(oldFileObject, Selectors.SELECT_ALL); + + } catch (FileSystemException e) { + log.error("Error while copying the content from " + oldFileOrFolderName + " to " + + newFileOrFolderName, e); + if (fileRenameMetrics != null) { + fileRenameMetrics.getRenameMetric(0); + } + throw new SiddhiAppRuntimeException("Error while copying the content from " + + oldFileOrFolderName + " to " + newFileOrFolderName, e); + } + + try { + oldFileObject.delete(Selectors.SELECT_ALL); + } catch (FileSystemException e) { + log.error("Error while deleting the content from " + oldFileOrFolderName, e); + if (fileRenameMetrics != null) { + fileRenameMetrics.getRenameMetric(0); + } + throw new SiddhiAppRuntimeException("Error while deleting the file " + oldFileObject.getName() + " from " + + oldFileOrFolderName, e); + } + if (fileRenameMetrics != null) { + fileRenameMetrics.getRenameMetric(1); + } + return new Object[0]; + } +} diff --git a/component/src/main/java/io/siddhi/extension/io/file/metrics/FileRenameMetrics.java b/component/src/main/java/io/siddhi/extension/io/file/metrics/FileRenameMetrics.java new file mode 100644 index 00000000..777d7c98 --- /dev/null +++ b/component/src/main/java/io/siddhi/extension/io/file/metrics/FileRenameMetrics.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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 io.siddhi.extension.io.file.metrics; + +import org.wso2.carbon.metrics.core.Level; +import org.wso2.carbon.si.metrics.core.internal.MetricsDataHolder; + +/** + * Class which is holds the metrics to monitor rename file operations. + */ +public class FileRenameMetrics extends Metrics { + + private String source; + private long time; + + public FileRenameMetrics(String siddhiAppName) { + super(siddhiAppName); + } + + public void getRenameMetric(int status) { + MetricsDataHolder.getInstance().getMetricService() + .gauge(String.format("io.siddhi.SiddhiApps.%s.Siddhi.File.Operations.Rename.%s.%s", + siddhiAppName, time + ".time", source + ".source"), Level.INFO, () -> status); + } + + public void setSource(String source) { + this.source = source; + } + + public void setTime(long time) { + this.time = time; + } +} From ff43a5b7faff60e62b6d185389ca151698462468 Mon Sep 17 00:00:00 2001 From: AnuGayan Date: Thu, 26 Oct 2023 18:55:07 +0530 Subject: [PATCH 2/3] Add file rename function support --- .../execution/file/FileRenameExtension.java | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/component/src/main/java/io/siddhi/extension/execution/file/FileRenameExtension.java b/component/src/main/java/io/siddhi/extension/execution/file/FileRenameExtension.java index 15f9bc14..c400321d 100644 --- a/component/src/main/java/io/siddhi/extension/execution/file/FileRenameExtension.java +++ b/component/src/main/java/io/siddhi/extension/execution/file/FileRenameExtension.java @@ -39,8 +39,7 @@ import org.apache.commons.vfs2.FileObject; import org.apache.commons.vfs2.FileSystemException; import org.apache.commons.vfs2.Selectors; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.apache.log4j.Logger; import org.wso2.carbon.si.metrics.core.internal.MetricsDataHolder; import java.util.ArrayList; @@ -52,7 +51,12 @@ @Extension( name = "rename", namespace = "file", - description = "Rename file/folder in a particular path", + description = "This method can be used to rename a file/folder in a particular path, move a file from to a " + + "different path. \n" + + "Ex- \n" + + " file:rename('/User/wso2/source', 'User/wso2/destination') \n" + + " file:rename('/User/wso2/source/file.csv', 'User/wso2/source/newFile.csv') \n " + + " file:rename('/User/wso2/source/file.csv', 'User/wso2/destination/file.csv')", parameters = { @Parameter( name = "uri", @@ -104,7 +108,7 @@ } ) public class FileRenameExtension extends StreamFunctionProcessor { - private static final Logger log = LogManager.getLogger(FileRenameExtension.class); + private static final Logger log = Logger.getLogger(FileRenameExtension.class); private String fileSystemOptions = null; private FileRenameMetrics fileRenameMetrics; @@ -167,34 +171,35 @@ private Object[] renameFileOrFolder(String oldFileOrFolderName, String newFileOr } FileObject oldFileObject = Utils.getFileObject(oldFileOrFolderName, fileSystemOptions); FileObject newFileObject = Utils.getFileObject(newFileOrFolderName, fileSystemOptions); - try { - oldFileObject.canRenameTo(newFileObject); - newFileObject.copyFrom(oldFileObject, Selectors.SELECT_ALL); - - } catch (FileSystemException e) { - log.error("Error while copying the content from " + oldFileOrFolderName + " to " - + newFileOrFolderName, e); - if (fileRenameMetrics != null) { - fileRenameMetrics.getRenameMetric(0); + if (oldFileObject.canRenameTo(newFileObject)) { + try { + newFileObject.copyFrom(oldFileObject, Selectors.SELECT_ALL); + } catch (FileSystemException e) { + log.error("Error while copying the content from " + oldFileOrFolderName + " to " + + newFileOrFolderName + ": " + e.getMessage()); + if (fileRenameMetrics != null) { + fileRenameMetrics.getRenameMetric(0); + } + return new Object[]{false}; } - throw new SiddhiAppRuntimeException("Error while copying the content from " - + oldFileOrFolderName + " to " + newFileOrFolderName, e); - } - try { - oldFileObject.delete(Selectors.SELECT_ALL); - } catch (FileSystemException e) { - log.error("Error while deleting the content from " + oldFileOrFolderName, e); - if (fileRenameMetrics != null) { - fileRenameMetrics.getRenameMetric(0); + try { + oldFileObject.delete(Selectors.SELECT_ALL); + } catch (FileSystemException e) { + log.error("Error while deleting the file " + oldFileOrFolderName + " after renaming ", + e); + if (fileRenameMetrics != null) { + fileRenameMetrics.getRenameMetric(0); + } } - throw new SiddhiAppRuntimeException("Error while deleting the file " + oldFileObject.getName() + " from " + - oldFileOrFolderName, e); + } else { + log.error("Cannot rename the given file " + oldFileOrFolderName + " to " + newFileOrFolderName); + return new Object[]{false}; } if (fileRenameMetrics != null) { fileRenameMetrics.getRenameMetric(1); } - return new Object[0]; + return new Object[]{true}; } } From 89c2e8f2c96a23a1acf9a97ed60050ac8f14f19b Mon Sep 17 00:00:00 2001 From: Anusha Jayasundara Date: Thu, 26 Oct 2023 15:00:08 +0000 Subject: [PATCH 3/3] Remove unused import --- .../io/siddhi/extension/execution/file/FileRenameExtension.java | 1 - 1 file changed, 1 deletion(-) diff --git a/component/src/main/java/io/siddhi/extension/execution/file/FileRenameExtension.java b/component/src/main/java/io/siddhi/extension/execution/file/FileRenameExtension.java index c400321d..54c08e97 100644 --- a/component/src/main/java/io/siddhi/extension/execution/file/FileRenameExtension.java +++ b/component/src/main/java/io/siddhi/extension/execution/file/FileRenameExtension.java @@ -25,7 +25,6 @@ import io.siddhi.annotation.ReturnAttribute; import io.siddhi.annotation.util.DataType; import io.siddhi.core.config.SiddhiQueryContext; -import io.siddhi.core.exception.SiddhiAppRuntimeException; import io.siddhi.core.executor.ConstantExpressionExecutor; import io.siddhi.core.executor.ExpressionExecutor; import io.siddhi.core.query.processor.stream.function.StreamFunctionProcessor;