/* * 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.synapse.transport.vfs; import org.apache.axis2.AxisFault; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.description.AxisService; import org.apache.axis2.description.ParameterInclude; import org.apache.axis2.transport.base.AbstractPollTableEntry; import org.apache.axis2.transport.base.ParamUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.synapse.commons.crypto.CryptoUtil; import org.apache.synapse.commons.vfs.VFSConstants; import org.apache.synapse.commons.vfs.VFSUtils; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Map; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Holds information about an entry in the VFS transport poll table used by the * VFS Transport Listener */ public class PollTableEntry extends AbstractPollTableEntry { // operation after scan public static final int DELETE = 0; public static final int MOVE = 1; public static final int NONE = 2; /** File or Directory to scan */ private String fileURI; /** The URI to send replies to. May be null. */ private String replyFileURI; /** file name pattern for a directory or compressed file entry */ private String fileNamePattern; /** Content-Type to use for the message */ private String contentType; /** action to take after a successful poll */ private int actionAfterProcess = DELETE; /** action to take after a poll with errors */ private int actionAfterErrors = DELETE; /** action to take after a failed poll */ private int actionAfterFailure = DELETE; /** where to move the file after processing */ private String moveAfterProcess; /** where to move the file after encountering some errors */ private String moveAfterErrors; /** where to move the file after total failure */ private String moveAfterFailure; /** moved file will have this formatted timestamp prefix */ private DateFormat moveTimestampFormat; private boolean streaming; private int maxRetryCount; private long reconnectTimeout; private boolean fileLocking; private CryptoUtil cryptoUtil; private Properties secureVaultProperties; /** * Only files smaller than this limit will get processed, it can be configured with param * "transport.vfs.FileSizeLimit", and this will have default value -1 which means unlimited file size * This should be specified in bytes */ private double fileSizeLimit = VFSConstants.DEFAULT_TRANSPORT_FILE_SIZE_LIMIT; private String moveAfterMoveFailure; private int nextRetryDurationForFailedMove; private String failedRecordFileName; private String failedRecordFileDestination; private String failedRecordTimestampFormat; private Integer fileProcessingInterval; private Integer fileProcessingCount; private Map<String, String> vfsSchemeProperties; private boolean autoLockRelease; private Long autoLockReleaseInterval; private Boolean autoLockReleaseSameNode; private boolean distributedLock; private String fileSortParam; private boolean fileSortAscending; private boolean forceCreateFolder; private String subfolderTimestamp; private Long distributedLockTimeout; private volatile boolean canceled; private boolean clusterAware; private static final Log log = LogFactory.getLog(PollTableEntry.class); public PollTableEntry(boolean fileLocking) { this.fileLocking = fileLocking; } @Override public EndpointReference[] getEndpointReferences(AxisService service, String ip) { return new EndpointReference[] { new EndpointReference("vfs:" + fileURI) }; } public String getFileURI() { return fileURI; } public String getReplyFileURI() { return replyFileURI; } public String getFileNamePattern() { return fileNamePattern; } public String getContentType() { return contentType; } public int getActionAfterProcess() { return actionAfterProcess; } public int getActionAfterErrors() { return actionAfterErrors; } public int getActionAfterFailure() { return actionAfterFailure; } public String getMoveAfterProcess() { return moveAfterProcess; } public String getMoveAfterMoveFailure() { return moveAfterMoveFailure; } public int getNextRetryDuration() { return nextRetryDurationForFailedMove; } public String getFailedRecordFileName() { return failedRecordFileName; } public String getFailedRecordFileDestination() { return failedRecordFileDestination; } public String getFailedRecordTimestampFormat() { return failedRecordTimestampFormat; } public Integer getFileProcessingInterval() { return fileProcessingInterval; } public Integer getFileProcessingCount() { return fileProcessingCount; } private void setMoveAfterProcess(String moveAfterProcess) { if (moveAfterProcess == null) { this.moveAfterProcess = null; } else if (moveAfterProcess.startsWith(VFSConstants.VFS_PREFIX)) { // to recover a good directory location if user entered with the vfs: prefix // because transport uris are given like that this.moveAfterProcess = moveAfterProcess.substring(VFSConstants.VFS_PREFIX.length()); } else { this.moveAfterProcess = moveAfterProcess; } } public String getMoveAfterErrors() { return moveAfterErrors; } private void setMoveAfterErrors(String moveAfterErrors) { if (moveAfterErrors == null) { this.moveAfterErrors = null; } else if (moveAfterErrors.startsWith(VFSConstants.VFS_PREFIX)) { this.moveAfterErrors = moveAfterErrors.substring(VFSConstants.VFS_PREFIX.length()); } else { this.moveAfterErrors = moveAfterErrors; } } public String getMoveAfterFailure() { return moveAfterFailure; } private void setMoveAfterFailure(String moveAfterFailure) { if (moveAfterFailure == null) { this.moveAfterFailure = null; } else if (moveAfterFailure.startsWith(VFSConstants.VFS_PREFIX)) { this.moveAfterFailure = moveAfterFailure.substring(VFSConstants.VFS_PREFIX.length()); } else { this.moveAfterFailure = moveAfterFailure; } } public boolean isStreaming() { return streaming; } public int getMaxRetryCount() { return maxRetryCount; } public boolean isFileLockingEnabled() { return fileLocking; } public void setSecureVaultProperties(Properties secureVaultProperties) { this.secureVaultProperties = secureVaultProperties; } public double getFileSizeLimit() { return fileSizeLimit; } public long getReconnectTimeout() { return reconnectTimeout; } public DateFormat getMoveTimestampFormat() { return moveTimestampFormat; } /** * @return the autoLockRelease */ public Boolean getAutoLockRelease() { return autoLockRelease; } /** * @param autoLockRelease the autoLockRelease to set */ public void setAutoLockRelease(Boolean autoLockRelease) { this.autoLockRelease = autoLockRelease; } /** * @return the autoLockReleaseInterval */ public Long getAutoLockReleaseInterval() { return autoLockReleaseInterval; } /** * @param autoLockReleaseInterval the autoLockReleaseInterval to set */ public void setAutoLockReleaseInterval(Long autoLockReleaseInterval) { this.autoLockReleaseInterval = autoLockReleaseInterval; } /** * @return the autoLockReleaseSameNode */ public Boolean getAutoLockReleaseSameNode() { return autoLockReleaseSameNode; } /** * @param autoLockReleaseSameNode the autoLockReleaseSameNode to set */ public void setAutoLockReleaseSameNode(Boolean autoLockReleaseSameNode) { this.autoLockReleaseSameNode = autoLockReleaseSameNode; } /** * @return the distributedLock */ public boolean isDistributedLock() { return distributedLock; } /** * @return the fileSortParam */ public String getFileSortParam() { return fileSortParam; } /** * @param fileSortParam the fileSortParam to set */ public void setFileSortParam(String fileSortParam) { this.fileSortParam = fileSortParam; } /** * @return the fileSortAscending */ public boolean isFileSortAscending() { return fileSortAscending; } /** * @param fileSortAscending the fileSortAscending to set */ public void setFileSortAscending(boolean fileSortAscending) { this.fileSortAscending = fileSortAscending; } /** * @return the distributedLockTimeout */ public Long getDistributedLockTimeout() { return distributedLockTimeout; } public boolean isCanceled() { return canceled; } public void setCanceled(boolean canceled) { this.canceled = canceled; } public boolean isClusterAware() { return clusterAware; } public void setClusterAware(boolean clusterAware) { this.clusterAware = clusterAware; } public Map<String, String> getVfsSchemeProperties() { return vfsSchemeProperties; } public void setVfsSchemeProperties(Map<String, String> vfsSchemeProperties) { this.vfsSchemeProperties = vfsSchemeProperties; } /** * @return the forceCreateFolder */ public boolean isForceCreateFolder() { return forceCreateFolder; } /** * @param forceCreateFolder the forceCreateFolder to set */ public void setForceCreateFolder(boolean forceCreateFolder) { this.forceCreateFolder = forceCreateFolder; } /** * @return the subfolderTimestamp */ public String getSubfolderTimestamp() { return subfolderTimestamp; } /** * @param subfolderTimestamp the subfolderTimestamp to set */ public void setSubfolderTimestamp(String subfolderTimestamp) { this.subfolderTimestamp = subfolderTimestamp; } @Override public boolean loadConfiguration(ParameterInclude params) throws AxisFault { fileURI = ParamUtils.getOptionalParam(params, VFSConstants.TRANSPORT_FILE_FILE_URI); fileURI = decryptIfRequired(fileURI); if (fileURI == null) { log.warn("transport.vfs.FileURI parameter is missing in the proxy service configuration"); return false; } else { if (fileURI.startsWith(VFSConstants.VFS_PREFIX)) { fileURI = fileURI.substring(VFSConstants.VFS_PREFIX.length()); } replyFileURI = ParamUtils.getOptionalParam(params, VFSConstants.REPLY_FILE_URI); replyFileURI = decryptIfRequired(replyFileURI); fileNamePattern = ParamUtils.getOptionalParam(params, VFSConstants.TRANSPORT_FILE_FILE_NAME_PATTERN); contentType = ParamUtils.getRequiredParam(params, VFSConstants.TRANSPORT_FILE_CONTENT_TYPE); String option = ParamUtils.getOptionalParam( params, VFSConstants.TRANSPORT_FILE_ACTION_AFTER_PROCESS); if (option == null) { option = VFSTransportListener.DELETE; } switch (option) { case VFSTransportListener.MOVE : actionAfterProcess = PollTableEntry.MOVE; break; case VFSTransportListener.DELETE : actionAfterProcess = PollTableEntry.DELETE; break; case VFSTransportListener.NONE : actionAfterProcess = PollTableEntry.NONE; break; default: actionAfterProcess = PollTableEntry.DELETE; } option = ParamUtils.getOptionalParam( params, VFSConstants.TRANSPORT_FILE_ACTION_AFTER_ERRORS); actionAfterErrors = VFSTransportListener.MOVE.equals(option) ? PollTableEntry.MOVE : PollTableEntry.DELETE; option = ParamUtils.getOptionalParam( params, VFSConstants.TRANSPORT_FILE_ACTION_AFTER_FAILURE); if (option == null) { option = VFSTransportListener.DELETE; } switch (option) { case VFSTransportListener.MOVE : actionAfterFailure = PollTableEntry.MOVE; break; case VFSTransportListener.DELETE : actionAfterFailure = PollTableEntry.DELETE; break; case VFSTransportListener.NONE : actionAfterFailure = PollTableEntry.NONE; break; default: actionAfterFailure = PollTableEntry.DELETE; } String moveDirectoryAfterProcess = ParamUtils.getOptionalParam( params, VFSConstants.TRANSPORT_FILE_MOVE_AFTER_PROCESS); moveDirectoryAfterProcess = decryptIfRequired(moveDirectoryAfterProcess); setMoveAfterProcess(moveDirectoryAfterProcess); String moveDirectoryAfterErrors = ParamUtils.getOptionalParam( params, VFSConstants.TRANSPORT_FILE_MOVE_AFTER_ERRORS); moveDirectoryAfterErrors = decryptIfRequired(moveDirectoryAfterErrors); setMoveAfterErrors(moveDirectoryAfterErrors); String moveDirectoryAfterFailure = ParamUtils.getOptionalParam( params, VFSConstants.TRANSPORT_FILE_MOVE_AFTER_FAILURE); moveDirectoryAfterFailure = decryptIfRequired(moveDirectoryAfterFailure); setMoveAfterFailure(moveDirectoryAfterFailure); String moveFileTimestampFormat = ParamUtils.getOptionalParam( params, VFSConstants.TRANSPORT_FILE_MOVE_TIMESTAMP_FORMAT); if(moveFileTimestampFormat != null) { moveTimestampFormat = new SimpleDateFormat(moveFileTimestampFormat); } setVfsSchemeProperties(VFSUtils.parseSchemeFileOptions(fileURI, params)); String strStreaming = ParamUtils.getOptionalParam(params, VFSConstants.STREAMING); if (strStreaming != null) { streaming = Boolean.parseBoolean(strStreaming); } String strMaxRetryCount = ParamUtils.getOptionalParam( params, VFSConstants.MAX_RETRY_COUNT); maxRetryCount = strMaxRetryCount != null ? Integer.parseInt(strMaxRetryCount) : VFSConstants.DEFAULT_MAX_RETRY_COUNT; String strReconnectTimeout = ParamUtils.getOptionalParam( params, VFSConstants.RECONNECT_TIMEOUT); reconnectTimeout = strReconnectTimeout != null ? Integer.parseInt(strReconnectTimeout) * 1000 : VFSConstants.DEFAULT_RECONNECT_TIMEOUT; String strFileLocking = ParamUtils.getOptionalParam( params, VFSConstants.TRANSPORT_FILE_LOCKING); if (VFSConstants.TRANSPORT_FILE_LOCKING_ENABLED.equals(strFileLocking)) { fileLocking = true; } else if (VFSConstants.TRANSPORT_FILE_LOCKING_DISABLED.equals(strFileLocking)) { fileLocking = false; } String strFileSizeLimit = ParamUtils.getOptionalParam( params, VFSConstants.TRANSPORT_FILE_SIZE_LIMIT); try { fileSizeLimit = strFileSizeLimit != null ? Double.parseDouble(strFileSizeLimit) : VFSConstants.DEFAULT_TRANSPORT_FILE_SIZE_LIMIT; } catch (Exception e) { log.warn("Error parsing specified file size limit - " + strFileSizeLimit + ", using default - unlimited"); } moveAfterMoveFailure = ParamUtils.getOptionalParam(params, VFSConstants.TRANSPORT_FILE_MOVE_AFTER_FAILED_MOVE); moveAfterMoveFailure = decryptIfRequired(moveAfterMoveFailure); String nextRetryDuration = ParamUtils.getOptionalParam( params, VFSConstants.TRANSPORT_FAILED_RECORD_NEXT_RETRY_DURATION); nextRetryDurationForFailedMove = nextRetryDuration != null ? Integer.parseInt(nextRetryDuration) : VFSConstants.DEFAULT_NEXT_RETRY_DURATION; failedRecordFileName = ParamUtils.getOptionalParam(params, VFSConstants.TRANSPORT_FAILED_RECORDS_FILE_NAME); if (failedRecordFileName == null) { failedRecordFileName = VFSConstants.DEFAULT_FAILED_RECORDS_FILE_NAME; } failedRecordFileDestination = ParamUtils.getOptionalParam(params, VFSConstants.TRANSPORT_FAILED_RECORDS_FILE_DESTINATION); if (failedRecordFileDestination == null) { failedRecordFileDestination = VFSConstants.DEFAULT_FAILED_RECORDS_FILE_DESTINATION; } failedRecordTimestampFormat = ParamUtils.getOptionalParam(params, VFSConstants.TRANSPORT_FAILED_RECORD_TIMESTAMP_FORMAT); if (failedRecordTimestampFormat == null) { failedRecordTimestampFormat = VFSConstants.DEFAULT_TRANSPORT_FAILED_RECORD_TIMESTAMP_FORMAT; } String strFileProcessingInterval = ParamUtils.getOptionalParam(params, VFSConstants.TRANSPORT_FILE_INTERVAL); fileProcessingInterval = null; if (strFileProcessingInterval != null) { try{ fileProcessingInterval = Integer.parseInt(strFileProcessingInterval); }catch(NumberFormatException nfe){ log.warn("VFS File Processing Interval not set correctly. Current value is : " + strFileProcessingInterval , nfe); } } String strFileProcessingCount = ParamUtils.getOptionalParam(params, VFSConstants.TRANSPORT_FILE_COUNT); fileProcessingCount = null; if (strFileProcessingCount != null) { try{ fileProcessingCount = Integer.parseInt(strFileProcessingCount); }catch(NumberFormatException nfe){ log.warn("VFS File Processing Count not set correctly. Current value is : " + strFileProcessingCount , nfe); } } String strAutoLock = ParamUtils.getOptionalParam(params, VFSConstants.TRANSPORT_AUTO_LOCK_RELEASE); autoLockRelease = false; autoLockReleaseSameNode = true; autoLockReleaseInterval = null; if (strAutoLock != null) { try { autoLockRelease = Boolean.parseBoolean(strAutoLock); } catch (Exception e) { autoLockRelease = false; log.warn("VFS Auto lock removal not set properly. Current value is : " + strAutoLock, e); } if (autoLockRelease) { String strAutoLockInterval = ParamUtils.getOptionalParam(params, VFSConstants.TRANSPORT_AUTO_LOCK_RELEASE_INTERVAL); if (strAutoLockInterval != null) { try { autoLockReleaseInterval = Long.parseLong(strAutoLockInterval); } catch (Exception e) { autoLockReleaseInterval = null; log.warn( "VFS Auto lock removal property not set properly. Current value is : " + strAutoLockInterval, e); } } String strAutoLockReleaseSameNode = ParamUtils.getOptionalParam(params, VFSConstants.TRANSPORT_AUTO_LOCK_RELEASE_SAME_NODE); if (strAutoLockReleaseSameNode != null) { try { autoLockReleaseSameNode = Boolean .parseBoolean(strAutoLockReleaseSameNode); } catch (Exception e) { autoLockReleaseSameNode = true; log.warn( "VFS Auto lock removal property not set properly. Current value is : " + autoLockReleaseSameNode, e); } } } } distributedLock = false; distributedLockTimeout = null; String strDistributedLock = ParamUtils.getOptionalParam(params, VFSConstants.TRANSPORT_DISTRIBUTED_LOCK); if(strDistributedLock != null){ try { distributedLock = Boolean.parseBoolean(strDistributedLock); } catch (Exception e) { autoLockRelease = false; log.warn("VFS Distributed lock not set properly. Current value is : " + strDistributedLock, e); } if(distributedLock){ String strDistributedLockTimeout = ParamUtils.getOptionalParam(params, VFSConstants.TRANSPORT_DISTRIBUTED_LOCK_TIMEOUT); if (strDistributedLockTimeout != null) { try { distributedLockTimeout = Long.parseLong(strDistributedLockTimeout); } catch (Exception e) { distributedLockTimeout = null; log.warn( "VFS Distributed lock timeout property not set properly. Current value is : " + strDistributedLockTimeout, e); } } } } fileSortParam = ParamUtils.getOptionalParam(params, VFSConstants.FILE_SORT_PARAM); fileSortAscending = true; if (fileSortParam != null && ParamUtils.getOptionalParam(params, VFSConstants.FILE_SORT_ORDER) != null) { try { fileSortAscending = Boolean.parseBoolean(ParamUtils.getOptionalParam(params, VFSConstants.FILE_SORT_ORDER)); } catch (Exception e) { fileSortAscending = true; } } String strForceCreateFolder = ParamUtils.getOptionalParam(params, VFSConstants.FORCE_CREATE_FOLDER); forceCreateFolder = false; if (strForceCreateFolder != null && "true".equals(strForceCreateFolder.toLowerCase())) { forceCreateFolder = true; } subfolderTimestamp = ParamUtils.getOptionalParam(params, VFSConstants.SUBFOLDER_TIMESTAMP); this.clusterAware = ParamUtils.getOptionalParamBoolean(params, VFSConstants.CLUSTER_AWARE, false); return super.loadConfiguration(params); } } /** * Helper method to decrypt parameters if required. * If the parameter is defined as - {wso2:vault-decrypt('Parameter')}, then this method will treat it as deryption * required and do the relevant decryption for that part. * * @param parameter * @return parameter * @throws AxisFault */ private String decryptIfRequired(String parameter) throws AxisFault { if (parameter != null && !parameter.isEmpty()) { // Create a Pattern object Pattern r = Pattern.compile("\\{wso2:vault-decrypt\\('(.*?)'\\)\\}"); // Now create matcher object. Matcher m = r.matcher(parameter); if (m.find()) { if (cryptoUtil == null) { cryptoUtil = new CryptoUtil(secureVaultProperties); } if (!cryptoUtil.isInitialized()) { throw new AxisFault("Error initialising cryptoutil"); } String toDecrypt = m.group(1); toDecrypt = new String(cryptoUtil.decrypt(toDecrypt.getBytes())); parameter = m.replaceFirst(toDecrypt); } } return parameter; } }