001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.component.stream;
018    
019    import java.io.BufferedWriter;
020    import java.io.File;
021    import java.io.FileOutputStream;
022    import java.io.IOException;
023    import java.io.OutputStream;
024    import java.io.OutputStreamWriter;
025    import java.io.Writer;
026    import java.net.URL;
027    import java.net.URLConnection;
028    import java.nio.charset.Charset;
029    import java.util.Arrays;
030    import java.util.List;
031    
032    import org.apache.camel.CamelExchangeException;
033    import org.apache.camel.Exchange;
034    import org.apache.camel.impl.DefaultProducer;
035    import org.apache.camel.util.ObjectHelper;
036    import org.apache.commons.logging.Log;
037    import org.apache.commons.logging.LogFactory;
038    
039    /**
040     * Producer that can write to streams
041     */
042    public class StreamProducer extends DefaultProducer {
043    
044        private static final transient Log LOG = LogFactory.getLog(StreamProducer.class);
045        private static final String TYPES = "out,err,file,header,url";
046        private static final String INVALID_URI = "Invalid uri, valid form: 'stream:{" + TYPES + "}'";
047        private static final List<String> TYPES_LIST = Arrays.asList(TYPES.split(","));
048        private OutputStream outputStream = System.out;
049        private StreamEndpoint endpoint;
050        private String uri;
051    
052        public StreamProducer(StreamEndpoint endpoint, String uri) throws Exception {
053            super(endpoint);
054            this.endpoint = endpoint;
055            validateUri(uri);
056        }
057    
058        @Override
059        public void doStop() throws Exception {
060            // important: do not close the stream as it will close the standard system.out etc.
061            super.doStop();
062        }
063    
064        public void process(Exchange exchange) throws Exception {
065            delay(endpoint.getDelay());
066    
067            if ("out".equals(uri)) {
068                outputStream = System.out;
069            } else if ("err".equals(uri)) {
070                outputStream = System.err;
071            } else if ("file".equals(uri)) {
072                outputStream = resolveStreamFromFile();
073            } else if ("header".equals(uri)) {
074                outputStream = resolveStreamFromHeader(exchange.getIn().getHeader("stream"), exchange);
075            } else if ("url".equals(uri)) {
076                outputStream = resolveStreamFromUrl();
077            }
078    
079            writeToStream(exchange);
080        }
081    
082        private OutputStream resolveStreamFromUrl() throws IOException {
083            String u = endpoint.getUrl();
084            ObjectHelper.notEmpty(u, "url");
085            if (LOG.isDebugEnabled()) {
086                LOG.debug("About to write to url: " + u);
087            }
088    
089            URL url = new URL(u);
090            URLConnection c = url.openConnection();
091            return c.getOutputStream();
092        }
093    
094        private OutputStream resolveStreamFromFile() throws IOException {
095            String fileName = endpoint.getFileName();
096            ObjectHelper.notEmpty(fileName, "fileName");
097            if (LOG.isDebugEnabled()) {
098                LOG.debug("About to write to file: " + fileName);
099            }
100            File f = new File(fileName);
101            // will create a new file if missing or append to existing
102            f.createNewFile();
103            return new FileOutputStream(f);
104        }
105    
106        private OutputStream resolveStreamFromHeader(Object o, Exchange exchange) throws CamelExchangeException {
107            return exchange.getContext().getTypeConverter().convertTo(OutputStream.class, o);
108        }
109    
110        private void delay(long ms) throws InterruptedException {
111            if (ms == 0) {
112                return;
113            }
114            if (LOG.isTraceEnabled()) {
115                LOG.trace("Delaying " + ms + " millis");
116            }
117            Thread.sleep(ms);
118        }
119    
120        private void writeToStream(Exchange exchange) throws IOException, CamelExchangeException {
121            Object body = exchange.getIn().getBody();
122    
123            // if not a string then try as byte array first
124            if (!(body instanceof String)) {
125                byte[] bytes = exchange.getIn().getBody(byte[].class);
126                if (bytes != null) {
127                    if (LOG.isDebugEnabled()) {
128                        LOG.debug("Writing as byte[]: " + bytes + " to " + outputStream);
129                    }
130                    outputStream.write(bytes);
131                    return;
132                }
133            }
134    
135            // okay now fallback to mandatory converterable to string
136            String s = exchange.getIn().getMandatoryBody(String.class);
137            Charset charset = endpoint.getCharset();
138            Writer writer = new OutputStreamWriter(outputStream, charset);
139            BufferedWriter bw = new BufferedWriter(writer);
140            if (LOG.isDebugEnabled()) {
141                LOG.debug("Writing as text: " + body + " to " + outputStream + " using encoding:" + charset);
142            }
143            bw.write(s);
144            bw.write("\n");
145            bw.flush();
146            // important: do not close the writer as it will close the standard system.out etc.
147        }
148    
149        private void validateUri(String uri) throws Exception {
150            String[] s = uri.split(":");
151            if (s.length < 2) {
152                throw new IllegalArgumentException(INVALID_URI);
153            }
154            String[] t = s[1].split("\\?");
155    
156            if (t.length < 1) {
157                throw new IllegalArgumentException(INVALID_URI);
158            }
159            this.uri = t[0].trim();
160            if (this.uri.startsWith("//")) {
161                this.uri = this.uri.substring(2);
162            }
163    
164            if (!TYPES_LIST.contains(this.uri)) {
165                throw new IllegalArgumentException(INVALID_URI);
166            }
167        }
168    
169    }
170