/** * 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.camel.component.stream; import java.nio.charset.Charset; import org.apache.camel.Component; import org.apache.camel.Consumer; import org.apache.camel.Exchange; import org.apache.camel.Processor; import org.apache.camel.Producer; import org.apache.camel.impl.DefaultEndpoint; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.spi.UriParam; import org.apache.camel.spi.UriPath; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The stream: component provides access to the system-in, system-out and system-err streams as well as allowing streaming of file and URL. */ @UriEndpoint(firstVersion = "1.3.0", scheme = "stream", title = "Stream", syntax = "stream:kind", consumerClass = StreamConsumer.class, label = "file,system") public class StreamEndpoint extends DefaultEndpoint { private static final Logger LOG = LoggerFactory.getLogger(StreamEndpoint.class); private transient Charset charset; @UriPath(enums = "in,out,err,header,file,url") @Metadata(required = "true") private String kind; @UriParam private String url; @UriParam private String fileName; @UriParam(label = "consumer") private boolean scanStream; @UriParam(label = "consumer") private boolean retry; @UriParam(label = "producer") private boolean closeOnDone; @UriParam(label = "consumer") private long scanStreamDelay; @UriParam(label = "producer") private long delay; @UriParam private String encoding; @UriParam(label = "consumer") private String promptMessage; @UriParam(label = "consumer") private long promptDelay; @UriParam(label = "consumer", defaultValue = "2000") private long initialPromptDelay = 2000; @UriParam(label = "consumer") private int groupLines; @UriParam(label = "producer") private int autoCloseCount; @UriParam(label = "consumer") private GroupStrategy groupStrategy = new DefaultGroupStrategy(); public StreamEndpoint(String endpointUri, Component component) throws Exception { super(endpointUri, component); } @Deprecated public StreamEndpoint(String endpointUri) { super(endpointUri); } public Consumer createConsumer(Processor processor) throws Exception { StreamConsumer answer = new StreamConsumer(this, processor, getEndpointUri()); configureConsumer(answer); return answer; } public Producer createProducer() throws Exception { return new StreamProducer(this, getEndpointUri()); } public boolean isSingleton() { return true; } protected Exchange createExchange(Object body, long index, boolean last) { Exchange exchange = createExchange(); exchange.getIn().setBody(body); exchange.getIn().setHeader(StreamConstants.STREAM_INDEX, index); exchange.getIn().setHeader(StreamConstants.STREAM_COMPLETE, last); return exchange; } // Properties //------------------------------------------------------------------------- public String getKind() { return kind; } /** * Kind of stream to use such as System.in or System.out. */ public void setKind(String kind) { this.kind = kind; } public String getFileName() { return fileName; } /** * When using the stream:file URI format, this option specifies the filename to stream to/from. */ public void setFileName(String fileName) { this.fileName = fileName; } public String getUrl() { return url; } /** * When using the stream:url URI format, this option specifies the URL to stream to/from. * The input/output stream will be opened using the JDK URLConnection facility. */ public void setUrl(String url) { this.url = url; } public long getDelay() { return delay; } /** * Initial delay in milliseconds before producing the stream. */ public void setDelay(long delay) { this.delay = delay; } public String getEncoding() { return encoding; } /** * You can configure the encoding (is a charset name) to use text-based streams (for example, message body is a String object). * If not provided, Camel uses the JVM default Charset. */ public void setEncoding(String encoding) { this.encoding = encoding; } public String getPromptMessage() { return promptMessage; } /** * Message prompt to use when reading from stream:in; for example, you could set this to Enter a command: */ public void setPromptMessage(String promptMessage) { this.promptMessage = promptMessage; } public long getPromptDelay() { return promptDelay; } /** * Optional delay in milliseconds before showing the message prompt. */ public void setPromptDelay(long promptDelay) { this.promptDelay = promptDelay; } public long getInitialPromptDelay() { return initialPromptDelay; } /** * Initial delay in milliseconds before showing the message prompt. This delay occurs only once. * Can be used during system startup to avoid message prompts being written while other logging is done to the system out. */ public void setInitialPromptDelay(long initialPromptDelay) { this.initialPromptDelay = initialPromptDelay; } public boolean isScanStream() { return scanStream; } /** * To be used for continuously reading a stream such as the unix tail command. */ public void setScanStream(boolean scanStream) { this.scanStream = scanStream; } public GroupStrategy getGroupStrategy() { return groupStrategy; } /** * Allows to use a custom GroupStrategy to control how to group lines. */ public void setGroupStrategy(GroupStrategy strategy) { this.groupStrategy = strategy; } public boolean isRetry() { return retry; } /** * Will retry opening the file if it's overwritten, somewhat like tail --retry */ public void setRetry(boolean retry) { this.retry = retry; } public boolean isCloseOnDone() { return closeOnDone; } /** * This option is used in combination with Splitter and streaming to the same file. * The idea is to keep the stream open and only close when the Splitter is done, to improve performance. * Mind this requires that you only stream to the same file, and not 2 or more files. */ public void setCloseOnDone(boolean closeOnDone) { this.closeOnDone = closeOnDone; } public long getScanStreamDelay() { return scanStreamDelay; } /** * Delay in milliseconds between read attempts when using scanStream. */ public void setScanStreamDelay(long scanStreamDelay) { this.scanStreamDelay = scanStreamDelay; } public int getGroupLines() { return groupLines; } /** * To group X number of lines in the consumer. * For example to group 10 lines and therefore only spit out an Exchange with 10 lines, instead of 1 Exchange per line. */ public void setGroupLines(int groupLines) { this.groupLines = groupLines; } public int getAutoCloseCount() { return autoCloseCount; } /** * Number of messages to process before closing stream on Producer side. * Never close stream by default (only when Producer is stopped). If more messages are sent, the stream is reopened for another autoCloseCount batch. */ public void setAutoCloseCount(int autoCloseCount) { this.autoCloseCount = autoCloseCount; } public Charset getCharset() { return charset; } // Implementations //------------------------------------------------------------------------- protected void doStart() throws Exception { charset = loadCharset(); } Charset loadCharset() { if (encoding == null) { encoding = Charset.defaultCharset().name(); LOG.debug("No encoding parameter using default charset: {}", encoding); } if (!Charset.isSupported(encoding)) { throw new IllegalArgumentException("The encoding: " + encoding + " is not supported"); } return Charset.forName(encoding); } }