This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit 4dfad46f0ebe44f0394184436ca7faea6ed7607b Author: Guillaume Nodet <[email protected]> AuthorDate: Thu Jan 30 16:35:13 2020 +0100 [CAMEL-14451] Fix jdk >= 9 compilation issue --- .../camel/component/file/GenericFileEndpoint.java | 342 +++++++++++++++++---- .../file/remote/RemoteFileConfiguration.java | 63 ++-- .../component/file/remote/RemoteFileEndpoint.java | 25 +- .../tools/apt/EndpointAnnotationProcessor.java | 2 +- 4 files changed, 347 insertions(+), 85 deletions(-) diff --git a/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java b/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java index 0b1e959..f73a881 100644 --- a/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java +++ b/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java @@ -68,134 +68,356 @@ public abstract class GenericFileEndpoint<T> extends ScheduledPollEndpoint imple // common options - @UriParam(label = "advanced", defaultValue = "true") + @UriParam(label = "advanced", defaultValue = "true", description = "Automatically create missing directories in " + + "the file's pathname. For the file consumer, that means creating the starting directory. For the file " + + "producer, it means the directory the files should be written to.") protected boolean autoCreate = true; - @UriParam(label = "advanced", defaultValue = "" + FileUtil.BUFFER_SIZE) + @UriParam(label = "advanced", defaultValue = "" + FileUtil.BUFFER_SIZE, description = "Buffer size in bytes used " + + "for writing files (or in case of FTP for downloading and uploading files).") protected int bufferSize = FileUtil.BUFFER_SIZE; - @UriParam + @UriParam(description = "This option is used to specify the encoding of the file. You can use this on the " + + "consumer, to specify the encodings of the files, which allow Camel to know the charset it should load " + + "the file content in case the file content is being accessed. Likewise when writing a file, you can use " + + "this option to specify which charset to write the file as well. Do mind that when writing the file " + + "Camel may have to read the message content into memory to be able to convert the data into the " + + "configured charset, so do not use this if you have big messages.") protected String charset; - @UriParam(javaType = "java.lang.String") + @UriParam(javaType = "java.lang.String", description = "Use Expression such as File Language to dynamically set " + + "the filename. For consumers, it's used as a filename filter. For producers, it's used to evaluate the " + + "filename to write. If an expression is set, it take precedence over the CamelFileName header. (Note: " + + "The header itself can also be an Expression). The expression options support both String and Expression " + + "types. If the expression is a String type, it is always evaluated using the File Language. If the " + + "expression is an Expression type, the specified Expression type is used - this allows you, for " + + "instance, to use OGNL expressions. For the consumer, you can use it to filter filenames, so you can " + + "for instance consume today's file using the File Language syntax: mydata-${date:now:yyyyMMdd}.txt. The " + + "producers support the CamelOverruleFileName header which takes precedence over any existing " + + "CamelFileName header; the CamelOverruleFileName is a header that is used only once, and makes it easier " + + "as this avoids to temporary store CamelFileName and have to restore it afterwards.") protected Expression fileName; - @UriParam + @UriParam(description = "Producer: If provided, then Camel will write a 2nd done file when the original file has " + + "been written. The done file will be empty. This option configures what file name to use. Either you can " + + "specify a fixed name. Or you can use dynamic placeholders. The done file will always be written in the " + + "same folder as the original file.<p/> Consumer: If provided, Camel will only consume files if a done " + + "file exists. This option configures what file name to use. Either you can specify a fixed name. Or you " + + "can use dynamic placeholders.The done file is always expected in the same folder as the original " + + "file.<p/> Only ${file.name} and ${file.name.next} is supported as dynamic placeholders.") protected String doneFileName; // producer options - @UriParam(label = "producer") + @UriParam(label = "producer", description = "Flatten is used to flatten the file name path to strip any leading " + + "paths, so it's just the file name. This allows you to consume recursively into sub-directories, but " + + "when you eg write the files to another directory they will be written in a single directory. " + + "Setting this to true on the producer enforces that any file name in CamelFileName header will be " + + "stripped for any leading paths.") protected boolean flatten; - @UriParam(label = "producer", defaultValue = "Override") + @UriParam(label = "producer", defaultValue = "Override", description = "What to do if a file already exists with " + + "the same name. Override, which is the default, replaces the existing file.<p/>" + + " - Append - adds content to the existing file.<p/> " + + " - Fail - throws a GenericFileOperationException, indicating that there is already an existing file.<p/> " + + " - Ignore - silently ignores the problem and does not override the existing file, " + + "but assumes everything is okay.<p/> " + + " - Move - option requires to use the moveExisting option to be configured as well. The option " + + "eagerDeleteTargetFile can be used to control what to do if an moving the file, and there " + + "exists already an existing file, otherwise causing the move operation to fail. The Move option will move " + + "any existing files, before writing the target file.<p/> " + + " - TryRename is only applicable if tempFileName option is in use. This allows to try renaming the file " + + "from the temporary name to the actual name, without doing any exists check. This check may be faster on " + + "some file systems and especially FTP servers.") protected GenericFileExist fileExist = GenericFileExist.Override; - @UriParam(label = "producer") + @UriParam(label = "producer", description = "This option is used to write the file using a temporary name and " + + "then, after the write is complete, rename it to the real name. Can be used to identify files being " + + "written and also avoid consumers (not using exclusive read locks) reading in progress files. Is often " + + "used by FTP when uploading big files.") protected String tempPrefix; - @UriParam(label = "producer", javaType = "java.lang.String") + @UriParam(label = "producer", javaType = "java.lang.String", description = "The same as tempPrefix option but " + + "offering a more fine grained control on the naming of the temporary filename as it uses the File " + + "Language. The location for tempFilename is relative to the final file location in the option " + + "'fileName', not the target directory in the base uri. For example if option fileName includes a " + + "directory prefix: dir/finalFilename then tempFileName is relative to that subdirectory dir.") protected Expression tempFileName; - @UriParam(label = "producer,advanced", defaultValue = "true") + @UriParam(label = "producer,advanced", defaultValue = "true", description = "Whether or not to eagerly delete " + + "any existing target file. This option only applies when you use fileExists=Override and the " + + "tempFileName option as well. You can use this to disable (set it to false) deleting the target " + + "file before the temp file is written. For example you may write big files and want the target file " + + "to exists during the temp file is being written. This ensure the target file is only deleted until " + + "the very last moment, just before the temp file is being renamed to the target filename. This option " + + "is also used to control whether to delete any existing files when fileExist=Move is enabled, and an " + + "existing file exists. If this option copyAndDeleteOnRenameFails false, then an exception will be thrown " + + "if an existing file existed, if its true, then the existing file is deleted before the move operation.") protected boolean eagerDeleteTargetFile = true; - @UriParam(label = "producer,advanced") + @UriParam(label = "producer,advanced", description = "Will keep the last modified timestamp from the source file " + + "(if any). Will use the Exchange.FILE_LAST_MODIFIED header to located the timestamp. This header can " + + "contain either a java.util.Date or long with the timestamp. If the timestamp exists and the option is " + + "enabled it will set this timestamp on the written file. Note: This option only applies to the file " + + "producer. You cannot use this option with any of the ftp producers.") protected boolean keepLastModified; - @UriParam(label = "producer,advanced") + @UriParam(label = "producer,advanced", description = "Used to specify if a null body is allowed during file " + + "writing. If set to true then an empty file will be created, when set to false, and attempting to send" + + " a null body to the file component, a GenericFileWriteException of 'Cannot write null body to file.' " + + "will be thrown. If the `fileExist` option is set to 'Override', then the file will be truncated, and " + + "if set to `append` the file will remain unchanged.") protected boolean allowNullBody; - @UriParam(label = "producer", defaultValue = "true") + @UriParam(label = "producer", defaultValue = "true", description = "Used for jailing (restricting) writing files " + + "to the starting directory (and sub) only. This is enabled by default to not allow Camel to write files " + + "to outside directories (to be more secured out of the box). You can turn this off to allow writing " + + "files to directories outside the starting directory, such as parent or root folders.") protected boolean jailStartingDirectory = true; - @UriParam(label = "producer") + @UriParam(label = "producer", description = "Used to append characters (text) after writing files. This can for " + + "example be used to add new lines or other separators when writing and appending to existing files. <p/> " + + "To specify new-line (slash-n or slash-r) or tab (slash-t) characters then escape with an extra slash, " + + "eg slash-slash-n.") protected String appendChars; // consumer options @UriParam protected GenericFileConfiguration configuration; - @UriParam(label = "consumer,advanced") + @UriParam(label = "consumer,advanced", description = "A pluggable " + + "org.apache.camel.component.file.GenericFileProcessStrategy " + + "allowing you to implement your own readLock option or similar. Can also be used when special conditions " + + "must be met before a file can be consumed, such as a special ready file exists. If this option is set " + + "then the readLock option does not apply.") protected GenericFileProcessStrategy<T> processStrategy; - @UriParam(label = "consumer,advanced") + @UriParam(label = "consumer,advanced", description = "A pluggable in-progress repository " + + "org.apache.camel.spi.IdempotentRepository. The in-progress repository is used to account the current in " + + "progress files being consumed. By default a memory based repository is used.") protected IdempotentRepository inProgressRepository = MemoryIdempotentRepository.memoryIdempotentRepository(DEFAULT_IN_PROGRESS_CACHE_SIZE); - @UriParam(label = "consumer,advanced") + @UriParam(label = "consumer,advanced", description = "When consuming, a local work directory can be used to " + + "store the remote file content directly in local files, to avoid loading the content into memory. This " + + "is beneficial, if you consume a very big remote file and thus can conserve memory.") protected String localWorkDirectory; - @UriParam(label = "consumer") + @UriParam(label = "consumer", description = "If true, the file is not moved or deleted in any way. This option " + + "is good for readonly data, or for ETL type requirements. If noop=true, Camel will set idempotent=true " + + "as well, to avoid consuming the same files over and over again.") protected boolean noop; - @UriParam(label = "consumer") + @UriParam(label = "consumer", description = "If a directory, will look for files in all the sub-directories as well.") protected boolean recursive; - @UriParam(label = "consumer") + @UriParam(label = "consumer", description = "If true, the file will be deleted after it is processed successfully.") protected boolean delete; - @UriParam(label = "consumer") + @UriParam(label = "consumer", description = "When pre-sort is enabled then the consumer will sort the file and " + + "directory names during polling, that was retrieved from the file system. You may want to do this in " + + "case you need to operate on the files in a sorted order. The pre-sort is executed before the consumer " + + "starts to filter, and accept files to process by Camel. This option is default=false meaning disabled.") protected boolean preSort; - @UriParam(label = "consumer,filter") + @UriParam(label = "consumer,filter", description = "To define a maximum messages to gather per poll. By default " + + "no maximum is set. Can be used to set a limit of e.g. 1000 to avoid when starting up the server that " + + "there are thousands of files. Set a value of 0 or negative to disabled it. Notice: If this option is " + + "in use then the File and FTP components will limit before any sorting. For example if you have 100000 " + + "files and use maxMessagesPerPoll=500, then only the first 500 files will be picked up, and then sorted. " + + "You can use the eagerMaxMessagesPerPoll option and set this to false to allow to scan all files first " + + "and then sort afterwards.") protected int maxMessagesPerPoll; - @UriParam(label = "consumer,filter", defaultValue = "true") + @UriParam(label = "consumer,filter", defaultValue = "true", description = "Allows for controlling whether the " + + "limit from maxMessagesPerPoll is eager or not. If eager then the limit is during the scanning of files. " + + "Where as false would scan all files, and then perform sorting. Setting this option to false allows for " + + "sorting all files first, and then limit the poll. Mind that this requires a higher memory usage as all " + + "file details are in memory to perform the sorting.") protected boolean eagerMaxMessagesPerPoll = true; - @UriParam(label = "consumer,filter", defaultValue = "" + Integer.MAX_VALUE) + @UriParam(label = "consumer,filter", defaultValue = "" + Integer.MAX_VALUE, description = "The maximum depth to " + + "traverse when recursively processing a directory.") protected int maxDepth = Integer.MAX_VALUE; - @UriParam(label = "consumer,filter") + @UriParam(label = "consumer,filter", description = "The minimum depth to start processing when recursively " + + "processing a directory. Using minDepth=1 means the base directory. Using minDepth=2 means the first " + + "sub directory.") protected int minDepth; - @UriParam(label = "consumer,filter") + @UriParam(label = "consumer,filter", description = "Is used to include files, if filename matches the regex " + + "pattern (matching is case in-sensitive). <p/> Notice if you use symbols such as plus sign and others " + + "you would need to configure this using the RAW() syntax if configuring this as an endpoint uri. See " + + "more details at <a href=\"http://camel.apache.org/how-do-i-configure-endpoints.html\">configuring " + + "endpoint uris</a>") protected String include; - @UriParam(label = "consumer,filter") + @UriParam(label = "consumer,filter", description = "Is used to exclude files, if filename matches the regex " + + "pattern (matching is case in-senstive). <p/> Notice if you use symbols such as plus sign and others " + + "you would need to configure this using the RAW() syntax if configuring this as an endpoint uri. See " + + "more details at <a href=\"http://camel.apache.org/how-do-i-configure-endpoints.html\">configuring " + + "" + + "endpoint uris</a>") protected String exclude; - @UriParam(label = "consumer,filter", javaType = "java.lang.String") + @UriParam(label = "consumer,filter", javaType = "java.lang.String", description = "Expression (such as Simple " + + "Language) used to dynamically set the filename when moving it after processing. To move files into " + + "a .done subdirectory just enter .done.") protected Expression move; - @UriParam(label = "consumer", javaType = "java.lang.String") + @UriParam(label = "consumer", javaType = "java.lang.String", description = "Sets the move failure expression " + + "based on Simple language. For example, to move files into a .error subdirectory use: .error. Note: " + + "When moving the files to the fail location Camel will handle the error and will not pick up the " + + "file again.") protected Expression moveFailed; - @UriParam(label = "consumer", javaType = "java.lang.String") + @UriParam(label = "consumer", javaType = "java.lang.String", description = "Expression (such as File Language) " + + "used to dynamically set the filename when moving it before processing. For example to move in-progress " + + "files into the order directory set this value to order.") protected Expression preMove; - @UriParam(label = "producer", javaType = "java.lang.String") + @UriParam(label = "producer", javaType = "java.lang.String", description = "Expression (such as File Language) " + + "used to compute file name to use when fileExist=Move is configured. To move files into a backup " + + "subdirectory just enter backup. This option only supports the following File Language tokens: " + + "\"file:name\", \"file:name.ext\", \"file:name.noext\", \"file:onlyname\", \"file:onlyname.noext\", " + + "\"file:ext\", and \"file:parent\". Notice the \"file:parent\" is not supported by the FTP component, " + + "as the FTP component can only move any existing files to a relative directory based on current dir " + + "as base.") protected Expression moveExisting; - @UriParam(label = "producer,advanced") + @UriParam(label = "producer,advanced", description = "Strategy (Custom Strategy) used to move file with special " + + "naming token to use when fileExist=Move is configured. By default, there is an implementation used if " + + "no custom strategy is provided") protected FileMoveExistingStrategy moveExistingFileStrategy; - @UriParam(label = "consumer,filter", defaultValue = "false") + @UriParam(label = "consumer,filter", defaultValue = "false", description = "Option to use the Idempotent " + + "Consumer EIP pattern to let Camel skip already processed files. Will by default use a memory based " + + "LRUCache that holds 1000 entries. If noop=true then idempotent will be enabled as well to avoid " + + "consuming the same files over and over again.") protected Boolean idempotent; - @UriParam(label = "consumer,filter", javaType = "java.lang.String") + @UriParam(label = "consumer,filter", javaType = "java.lang.String", description = "To use a custom idempotent " + + "key. By default the absolute path of the file is used. You can use the File Language, for example to " + + "use the file name and file size, you can do: idempotentKey=${file:name}-${file:size}") protected Expression idempotentKey; - @UriParam(label = "consumer,filter") + @UriParam(label = "consumer,filter", description = "A pluggable repository org.apache.camel.spi.IdempotentRepository " + + "which by default use MemoryMessageIdRepository if none is specified and idempotent is true.") protected IdempotentRepository idempotentRepository; - @UriParam(label = "consumer,filter") + @UriParam(label = "consumer,filter", description = "Pluggable filter as a org.apache.camel.component.file.GenericFileFilter " + + "class. Will skip files if filter returns false in its accept() method.") protected GenericFileFilter<T> filter; - @UriParam(label = "consumer,filter", javaType = "java.lang.String") + @UriParam(label = "consumer,filter", javaType = "java.lang.String", description = "Filters the directory based on " + + "Simple language. For example to filter on current date, you can use a simple date pattern such as " + + "${date:now:yyyMMdd}") protected Predicate filterDirectory; - @UriParam(label = "consumer,filter", javaType = "java.lang.String") + @UriParam(label = "consumer,filter", javaType = "java.lang.String", description = "Filters the file based on " + + "Simple language. For example to filter on file size, you can use ${file:size} > 5000") protected Predicate filterFile; - @UriParam(label = "consumer,filter", defaultValue = "true") + @UriParam(label = "consumer,filter", defaultValue = "true", description = "Sets case sensitive flag on ant filter.") protected boolean antFilterCaseSensitive = true; protected volatile AntPathMatcherGenericFileFilter<T> antFilter; - @UriParam(label = "consumer,filter") + @UriParam(label = "consumer,filter", description = "Ant style filter inclusion. Multiple inclusions may be " + + "specified in comma-delimited format.") protected String antInclude; - @UriParam(label = "consumer,filter") + @UriParam(label = "consumer,filter", description = "Ant style filter exclusion. If both antInclude and antExclude are used, antExclude takes precedence over antInclude. Multiple exclusions may be specified in comma-delimited format.") protected String antExclude; - @UriParam(label = "consumer,sort") + @UriParam(label = "consumer,sort", description = "Pluggable sorter as a " + + "java.util.Comparator<org.apache.camel.component.file.GenericFile> class.") protected Comparator<GenericFile<T>> sorter; - @UriParam(label = "consumer,sort", javaType = "java.lang.String") + @UriParam(label = "consumer,sort", javaType = "java.lang.String", description = "Built-in sort by using the " + + "File Language. Supports nested sorts, so you can have a sort by file name and as a 2nd group sort " + + "by modified date.") protected Comparator<Exchange> sortBy; - @UriParam(label = "consumer,sort") + @UriParam(label = "consumer,sort", description = "To shuffle the list of files (sort in random order)") protected boolean shuffle; - @UriParam(label = "consumer,lock", defaultValue = "none", enums = "none,markerFile,fileLock,rename,changed,idempotent,idempotent-changed,idempotent-rename") + @UriParam(label = "consumer,lock", defaultValue = "none", enums = "none,markerFile,fileLock,rename,changed,idempotent,idempotent-changed,idempotent-rename", + description = "Used by consumer, to only poll the files if it has exclusive read-lock on the file (i.e. " + + "the file is not in-progress or being written). Camel will wait until the file lock is granted. " + + "This option provides the build in strategies:<p/>" + + " - none - No read lock is in use<p/>" + + " - markerFile - Camel creates a marker file (fileName.camelLock) and then holds a lock on it. " + + "This option is not available for the FTP component<p/>" + + " - changed - Changed is using file length/modification timestamp to detect whether the file " + + "is currently being copied or not. Will at least use 1 sec to determine this, so this option " + + "cannot consume files as fast as the others, but can be more reliable as the JDK IO API " + + "cannot always determine whether a file is currently being used by another process. The option " + + "readLockCheckInterval can be used to set the check frequency.<p/>" + + " - fileLock - is for using java.nio.channels.FileLock. This option is not avail for Windows OS " + + "and the FTP component. This approach should be avoided when accessing a remote file system via " + + "a mount/share unless that file system supports distributed file locks.<p/>" + + " - rename - rename is for using a try to rename the file as a test if we can get exclusive " + + "read-lock.<p/>" + + " - idempotent - (only for file component) idempotent is for using a idempotentRepository " + + "as the read-lock. This allows to use read locks that supports clustering if the idempotent " + + "repository implementation supports that.<p/>" + + " - idempotent-changed - (only for file component) idempotent-changed is for using a " + + "idempotentRepository and changed as the combined read-lock. This allows to use read locks " + + "that supports clustering if the idempotent repository implementation supports that.<p/>" + + " - idempotent-rename - (only for file component) idempotent-rename is for using a " + + "idempotentRepository and rename as the combined read-lock. This allows to use read locks " + + "that supports clustering if the idempotent repository implementation supports that.<p/>" + + "Notice: The various read locks is not all suited to work in clustered mode, where concurrent " + + "consumers on different nodes is competing for the same files on a shared file system. The " + + "markerFile using a close to atomic operation to create the empty marker file, but its not " + + "guaranteed to work in a cluster. The fileLock may work better but then the file system need " + + "to support distributed file locks, and so on. Using the idempotent read lock can support " + + "clustering if the idempotent repository supports clustering, such as Hazelcast Component or " + + "Infinispan.") protected String readLock = "none"; - @UriParam(label = "consumer,lock", defaultValue = "1000") + @UriParam(label = "consumer,lock", defaultValue = "1000", description = "Interval in millis for the read-lock, " + + "if supported by the read lock. This interval is used for sleeping between attempts to acquire the read " + + "lock. For example when using the changed read lock, you can set a higher interval period to cater for " + + "slow writes. The default of 1 sec. may be too fast if the producer is very slow writing the file. <p/>" + + "Notice: For FTP the default readLockCheckInterval is 5000. <p/> The readLockTimeout value must be " + + "higher than readLockCheckInterval, but a rule of thumb is to have a timeout that is at least 2 or more " + + "times higher than the readLockCheckInterval. This is needed to ensure that amble time is allowed for " + + "the read lock process to try to grab the lock before the timeout was hit.") protected long readLockCheckInterval = 1000; - @UriParam(label = "consumer,lock", defaultValue = "10000") + @UriParam(label = "consumer,lock", defaultValue = "10000", description = "Optional timeout in millis for the " + + "read-lock, if supported by the read-lock. If the read-lock could not be granted and the timeout " + + "triggered, then Camel will skip the file. At next poll Camel, will try the file again, and this time " + + "maybe the read-lock could be granted. Use a value of 0 or lower to indicate forever. Currently " + + "fileLock, changed and rename support the timeout. <p/> Notice: For FTP the default readLockTimeout " + + "value is 20000 instead of 10000. <p/> The readLockTimeout value must be higher than " + + "readLockCheckInterval, but a rule of thumb is to have a timeout that is at least 2 or more times " + + "higher than the readLockCheckInterval. This is needed to ensure that amble time is allowed for the " + + "read lock process to try to grab the lock before the timeout was hit.") protected long readLockTimeout = 10000; - @UriParam(label = "consumer,lock", defaultValue = "true") + @UriParam(label = "consumer,lock", defaultValue = "true", description = "Whether to use marker file with the " + + "changed, rename, or exclusive read lock types. By default a marker file is used as well to guard " + + "against other processes picking up the same files. This behavior can be turned off by setting this " + + "option to false. For example if you do not want to write marker files to the file systems by the " + + "Camel application.") protected boolean readLockMarkerFile = true; - @UriParam(label = "consumer,lock", defaultValue = "true") + @UriParam(label = "consumer,lock", defaultValue = "true", description = "Whether or not read lock with marker " + + "files should upon startup delete any orphan read lock files, which may have been left on the file " + + "system, if Camel was not properly shutdown (such as a JVM crash). <p/> If turning this option to " + + "<tt>false</tt> then any orphaned lock file will cause Camel to not attempt to pickup that file, this " + + "could also be due another node is concurrently reading files from the same shared directory.") protected boolean readLockDeleteOrphanLockFiles = true; - @UriParam(label = "consumer,lock", defaultValue = "DEBUG") + @UriParam(label = "consumer,lock", defaultValue = "DEBUG", description = "Logging level used when a read lock " + + "could not be acquired. By default a DEBUG is logged. You can change this level, for example to OFF to " + + "not have any logging. This option is only applicable for readLock of types: changed, fileLock, " + + "idempotent, idempotent-changed, idempotent-rename, rename.") protected LoggingLevel readLockLoggingLevel = LoggingLevel.DEBUG; - @UriParam(label = "consumer,lock", defaultValue = "1") + @UriParam(label = "consumer,lock", defaultValue = "1", description = "This option is applied only for " + + "readLock=changed. It allows you to configure a minimum file length. By default Camel expects the file " + + "to contain data, and thus the default value is 1. You can set this option to zero, to allow consuming " + + "zero-length files.") protected long readLockMinLength = 1; - @UriParam(label = "consumer,lock", defaultValue = "0") + @UriParam(label = "consumer,lock", defaultValue = "0", description = "This option is applied only for " + + "readLock=changed. It allows to specify a minimum age the file must be before attempting to acquire " + + "the read lock. For example use readLockMinAge=300s to require the file is at last 5 minutes old. This " + + "can speedup the changed read lock as it will only attempt to acquire files which are at least " + + "that given age.") protected long readLockMinAge; - @UriParam(label = "consumer,lock", defaultValue = "true") + @UriParam(label = "consumer,lock", defaultValue = "true", description = "This option is applied only for " + + "readLock=idempotent. It allows to specify whether to remove the file name entry from the idempotent " + + "repository when processing the file failed and a rollback happens. If this option is false, then the " + + "file name entry is confirmed (as if the file did a commit).") protected boolean readLockRemoveOnRollback = true; - @UriParam(label = "consumer,lock") + @UriParam(label = "consumer,lock", description = "This option is applied only for readLock=idempotent. It allows " + + "to specify whether to remove the file name entry from the idempotent repository when processing the " + + "file is succeeded and a commit happens. <p/> By default the file is not removed which ensures that " + + "any race-condition do not occur so another active node may attempt to grab the file. Instead the " + + "idempotent repository may support eviction strategies that you can configure to evict the file name " + + "entry after X minutes - this ensures no problems with race conditions. <p/> See more details at the " + + "readLockIdempotentReleaseDelay option.") protected boolean readLockRemoveOnCommit; - @UriParam(label = "consumer,lock") + @UriParam(label = "consumer,lock", description = "Whether to delay the release task for a period of millis. <p/> " + + "This can be used to delay the release tasks to expand the window when a file is regarded as " + + "read-locked, in an active/active cluster scenario with a shared idempotent repository, to ensure " + + "other nodes cannot potentially scan and acquire the same file, due to race-conditions. By expanding " + + "the time-window of the release tasks helps prevents these situations. Note delaying is only needed " + + "if you have configured readLockRemoveOnCommit to true.") protected int readLockIdempotentReleaseDelay; - @UriParam(label = "consumer,lock") + @UriParam(label = "consumer,lock", description = "Whether the delayed release task should be synchronous or " + + "asynchronous. <p/> See more details at the readLockIdempotentReleaseDelay option.") protected boolean readLockIdempotentReleaseAsync; - @UriParam(label = "consumer,lock") + @UriParam(label = "consumer,lock", description = "The number of threads in the scheduled thread pool when using " + + "asynchronous release tasks. Using a default of 1 core threads should be sufficient in almost all " + + "use-cases, only set this to a higher value if either updating the idempotent repository is slow, or " + + "there are a lot of files to process. This option is not in-use if you use a shared thread pool by " + + "configuring the readLockIdempotentReleaseExecutorService option. <p/> See more details at the " + + "readLockIdempotentReleaseDelay option.") protected int readLockIdempotentReleaseAsyncPoolSize; - @UriParam(label = "consumer,lock") + @UriParam(label = "consumer,lock", description = "To use a custom and shared thread pool for asynchronous " + + "release tasks. <p/> See more details at the readLockIdempotentReleaseDelay option.") protected ScheduledExecutorService readLockIdempotentReleaseExecutorService; - @UriParam(label = "consumer,lock") + @UriParam(label = "consumer,lock", description = "Pluggable read-lock as a org.apache.camel.component.file.GenericFileExclusiveReadLockStrategy implementation.") protected GenericFileExclusiveReadLockStrategy<T> exclusiveReadLockStrategy; - @UriParam(label = "consumer,advanced") + @UriParam(label = "consumer,advanced", description = "To use a custom " + + "{@link org.apache.camel.spi.ExceptionHandler} to handle any thrown exceptions that happens during " + + "the file on completion process where the consumer does either a commit or rollback. The default " + + "implementation will log any exception at WARN level and ignore.") protected ExceptionHandler onCompletionExceptionHandler; private Pattern includePattern; diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConfiguration.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConfiguration.java index dc0de9a..4ec44e5 100644 --- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConfiguration.java +++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConfiguration.java @@ -41,41 +41,68 @@ public abstract class RemoteFileConfiguration extends GenericFileConfiguration { // component name is implied as the protocol, eg ftp/ftps etc private String protocol; - @UriPath @Metadata(required = true) + @UriPath(description = "Hostname of the FTP server") @Metadata(required = true) private String host; - @UriPath + @UriPath(description = "Port of the FTP server") private int port; - @UriPath(name = "directoryName") + @UriPath(name = "directoryName", description = "The starting directory") private String directoryName; - @UriParam(label = "security", secret = true) + @UriParam(label = "security", secret = true, description = "Username to use for login") private String username; - @UriParam(label = "security", secret = true) + @UriParam(label = "security", secret = true, description = "Password to use for login") private String password; - @UriParam + @UriParam(description = "Specifies the file transfer mode, BINARY or ASCII. Default is ASCII (false).") private boolean binary; - @UriParam + @UriParam(description = "Sets passive mode connections.<br/> Default is active mode connections.") private boolean passiveMode; - @UriParam(defaultValue = "10000", label = "advanced") + @UriParam(defaultValue = "10000", label = "advanced", description = "Sets the connect timeout for waiting " + + "for a connection to be established <p/> Used by both FTPClient and JSCH") private int connectTimeout = 10000; - @UriParam(defaultValue = "30000", label = "advanced") + @UriParam(defaultValue = "30000", label = "advanced", description = "Sets the data timeout for waiting for " + + "reply <p/> Used only by FTPClient") private int timeout = 30000; - @UriParam(defaultValue = "300000", label = "advanced") + @UriParam(defaultValue = "300000", label = "advanced", description = "Sets the so timeout <p/> FTP and FTPS " + + "Only for Camel 2.4. SFTP for Camel 2.14.3/2.15.3/2.16 onwards. Is the SocketOptions.SO_TIMEOUT value " + + "in millis. Recommended option is to set this to 300000 so as not have a hanged connection. On SFTP this " + + "option is set as timeout on the JSCH Session instance.") private int soTimeout = 300000; - @UriParam(label = "advanced") + @UriParam(label = "advanced", description = "Should an exception be thrown if connection failed (exhausted) <p/> " + + "By default exception is not thrown and a <tt>WARN</tt> is logged. You can use this to enable exception " + + "being thrown and handle the thrown exception from the {@link " + + "org.apache.camel.spi.PollingConsumerPollStrategy} rollback method.") private boolean throwExceptionOnConnectFailed; - @UriParam(label = "advanced") + @UriParam(label = "advanced", description = "Sets optional site command(s) to be executed after successful " + + "login. <p/> Multiple site commands can be separated using a new line character.") private String siteCommand; - @UriParam(defaultValue = "true", label = "advanced") + @UriParam(defaultValue = "true", label = "advanced", description = "Sets whether we should stepwise change " + + "directories while traversing file structures when downloading files, or as well when uploading a file " + + "to a directory. <p/> You can disable this if you for example are in a situation where you cannot change " + + "directory on the FTP server due security reasons. @param stepwise whether to use change directory or not") private boolean stepwise = true; - @UriParam(defaultValue = "UNIX") + @UriParam(defaultValue = "UNIX", description = "Sets the path separator to be used. <p/> UNIX = Uses unix style " + + "path separator Windows = Uses windows style path separator Auto = (is default) Use existing path " + + "separator in file name") private PathSeparator separator = PathSeparator.UNIX; - @UriParam(label = "consumer") + @UriParam(label = "consumer", description = "Sets the download method to use when not using a local working " + + "directory. If set to true, the remote files are streamed to the route as they are read. When set to " + + "false, the remote files are loaded into memory before being sent into the route.") private boolean streamDownload; - @UriParam(defaultValue = "true", label = "consumer,advanced") + @UriParam(defaultValue = "true", label = "consumer,advanced", description = "Whether to allow using LIST " + + "command when downloading a file. <p/> Default is <tt>true</tt>. In some use cases you may want to " + + "download a specific file and are not allowed to use the LIST command, and therefore you can set " + + "this option to <tt>false</tt>. Notice when using this option, then the specific file to download " + + "does <b>not</b> include meta-data information such as file size, timestamp, permissions etc, because " + + "those information is only possible to retrieve when LIST command is in use.") private boolean useList = true; - @UriParam(label = "consumer,advanced") + @UriParam(label = "consumer,advanced", description = "Whether to ignore when (trying to list files in " + + "directories or when downloading a file), which does not exist or due to permission error. <p/> " + + "By default when a directory or file does not exists or insufficient permission, then an exception " + + "is thrown. Setting this option to <tt>true</tt> allows to ignore that instead.") private boolean ignoreFileNotFoundOrPermissionError; - @UriParam(label = "producer,advanced", defaultValue = "true") + @UriParam(label = "producer,advanced", defaultValue = "true", description = "Whether to send a noop command " + + "as a pre-write check before uploading files to the FTP server. <p/> This is enabled by default as " + + "a validation of the connection is still valid, which allows to silently re-connect to be able to " + + "upload the file. However if this causes problems, you can turn this option off.") private boolean sendNoop = true; public RemoteFileConfiguration() { diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileEndpoint.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileEndpoint.java index fdf7646..eed2033 100644 --- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileEndpoint.java +++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileEndpoint.java @@ -39,17 +39,30 @@ public abstract class RemoteFileEndpoint<T> extends GenericFileEndpoint<T> { private static final Logger LOG = LoggerFactory.getLogger(RemoteFileEndpoint.class); - @UriParam(label = "advanced") + @UriParam(label = "advanced", description = "Specifies the maximum reconnect attempts Camel performs when it " + + "tries to connect to the remote FTP server. Use 0 to disable this behavior.") private int maximumReconnectAttempts = 3; - @UriParam(label = "advanced") + @UriParam(label = "advanced", description = "Delay in millis Camel will wait before performing a reconnect attempt.") private long reconnectDelay = 1000; - @UriParam(label = "common") + @UriParam(label = "common", description = "Whether or not to disconnect from remote FTP server right after use. " + + "Disconnect will only disconnect the current connection to the FTP server. If you have a consumer which " + + "you want to stop, then you need to stop the consumer/route instead.") private boolean disconnect; - @UriParam(label = "producer,advanced") + @UriParam(label = "producer,advanced", description = "Whether or not to disconnect from remote FTP server right " + + "after a Batch upload is complete. disconnectOnBatchComplete will only disconnect the current connection " + + "to the FTP server.") private boolean disconnectOnBatchComplete; - @UriParam(label = "common,advanced") + @UriParam(label = "common,advanced", description = "If set this option to be true, camel-ftp will use the list " + + "file directly to check if the file exists. Since some FTP server may not support to list the file " + + "directly, if the option is false, camel-ftp will use the old way to list the directory and check if the " + + "file exists. This option also influences readLock=changed to control whether it performs a fast check " + + "to update file information or not. This can be used to speed up the process if the FTP server has a lot " + + "of files.") private boolean fastExistsCheck; - @UriParam(label = "consumer,advanced") + @UriParam(label = "consumer,advanced", description = "Whether the FTP consumer should download the file. If this " + + "option is set to false, then the message body will be null, but the consumer will still trigger a Camel " + + "Exchange that has details about the file such as file name, file size, etc. It's just that the file will " + + "not be downloaded.") private boolean download = true; public RemoteFileEndpoint() { diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java index 6a9c3b0..36975ac 100644 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java @@ -215,7 +215,7 @@ public class EndpointAnnotationProcessor extends AbstractCamelAnnotationProcesso option.setDescription(doc); if (isNullOrEmpty(doc)) { - throw new IllegalStateException("Empty doc for option: " + option.getName() + ", parent options:\n" + throw new IllegalStateException("Empty doc for option: " + option.getName() + ", parent options: " + (parentOptions != null ? Jsoner.serialize(JsonMapper.asJsonObject(parentOptions)) : "<null>")); } }
