All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wso2.extension.siddhi.io.file.FileSink Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2017, WSO2 Inc. (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 org.wso2.extension.siddhi.io.file;

import org.apache.log4j.Logger;
import org.wso2.carbon.messaging.BinaryCarbonMessage;
import org.wso2.carbon.messaging.exceptions.ClientConnectorException;
import org.wso2.extension.siddhi.io.file.util.Constants;
import org.wso2.siddhi.annotation.Example;
import org.wso2.siddhi.annotation.Extension;
import org.wso2.siddhi.annotation.Parameter;
import org.wso2.siddhi.annotation.util.DataType;
import org.wso2.siddhi.core.config.SiddhiAppContext;
import org.wso2.siddhi.core.exception.ConnectionUnavailableException;
import org.wso2.siddhi.core.stream.output.sink.Sink;
import org.wso2.siddhi.core.util.config.ConfigReader;
import org.wso2.siddhi.core.util.transport.DynamicOptions;
import org.wso2.siddhi.core.util.transport.Option;
import org.wso2.siddhi.core.util.transport.OptionHolder;
import org.wso2.siddhi.query.api.definition.StreamDefinition;
import org.wso2.transport.file.connector.sender.VFSClientConnector;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

/**
 * This class contains the implementation of siddhi-io-file sink which provides the functionality of
 * publishing data to files through siddhi.
 */

@Extension(
        name = "file" ,
        namespace = "sink" ,
        description = "" +
                "File Sink can be used to publish (write) event data which is processed within siddhi " +
                "to files. \nSiddhi-io-file sink provides support to write both textual and binary data into files\n",
        parameters = {
                @Parameter(name = "file.uri",
                        description =
                                "Used to specify the file for data to be written. ",
                        type = {DataType.STRING},
                        dynamic = true
                ),

                @Parameter(name = "append",
                        description = "" +
                                "This parameter is used to specify whether the data should be " +
                                "append to the file or not.\n" +
                                "If append = 'true', " +
                                "data will be write at the end of the file without " +
                                "changing the existing content.\n" +
                                "If file does not exist, a new fill will be crated and then data will be written.\n" +
                                "If append append = 'false', \n" +
                                "If given file exists, existing content will be deleted and then data will be " +
                                "written back to the file.\n" +
                                "If given file does not exist, a new file will be created and " +
                                "then data will be written on it.\n",
                        type = {DataType.BOOL},
                        optional = true,
                        defaultValue = "true"
                ),
                @Parameter(
                        name = "add.line.separator",
                        description = "This parameter is used to specify whether events added to the file should " +
                                "be separated by a newline.\n" +
                                "If add.event.separator= 'true'," +
                                "then a newline will be added after data is added to the file.",
                        type = {DataType.BOOL},
                        optional = true,
                        defaultValue = "true. (However, if csv mapper is used, it is false)"
                )
        },
        examples = {
                @Example(
                        syntax = "" +
                                "@sink(type='file', @map(type='json'), " +
                                "append='false', " +
                                "file.uri='/abc/{{symbol}}.txt') " +
                                "define stream BarStream (symbol string, price float, volume long); ",

                        description = "" +
                                "Under above configuration, for each event, " +
                                "a file will be generated if there's no such a file," +
                                "and then data will be written to that file as json messages" +
                                "output will looks like below.\n" +
                                "{\n" +
                                "    \"event\":{\n" +
                                "        \"symbol\":\"WSO2\",\n" +
                                "        \"price\":55.6,\n" +
                                "        \"volume\":100\n" +
                                "    }\n" +
                                "}\n")
        }
)
public class FileSink extends Sink {
    private static final Logger log = Logger.getLogger(FileSink.class);

    private VFSClientConnector vfsClientConnector = null;
    private Map properties = null;
    private Option uriOption;
    private SiddhiAppContext siddhiAppContext;
    private boolean addEventSeparator;


    @Override
    public Class[] getSupportedInputEventClasses() {
        return new Class[]{String.class, byte[].class, Object.class};
    }

    public String[] getSupportedDynamicOptions() {
        return new String[]{Constants.FILE_URI};
    }

    protected void init(StreamDefinition streamDefinition, OptionHolder optionHolder,
                        ConfigReader configReader, SiddhiAppContext siddhiAppContext) {
        this.siddhiAppContext = siddhiAppContext;
        uriOption = optionHolder.validateAndGetOption(Constants.FILE_URI);
        String append = optionHolder.validateAndGetStaticValue(Constants.APPEND, Constants.TRUE);
        properties = new HashMap<>();
        properties.put(Constants.ACTION, Constants.WRITE);
        if (Constants.TRUE.equalsIgnoreCase(append)) {
            properties.put(Constants.APPEND, append);
        }
        String mapType = streamDefinition.getAnnotations().get(0).getAnnotations().get(0).getElements().get(0)
                .getValue();
        addEventSeparator = optionHolder.isOptionExists(Constants.ADD_EVENT_SEPARATOR) ?
                Boolean.parseBoolean(optionHolder.validateAndGetStaticValue(Constants.ADD_EVENT_SEPARATOR)) :
                !mapType.equalsIgnoreCase("csv");
    }

    public void connect() throws ConnectionUnavailableException {
        vfsClientConnector = new VFSClientConnector();
    }

    public void disconnect() {

    }

    public void destroy() {

    }

    public void publish(Object payload, DynamicOptions dynamicOptions) throws ConnectionUnavailableException {
        byte[] byteArray = new byte[0];
        boolean canBeWritten = true;
        if (payload instanceof byte[]) {
            byteArray = (byte[]) payload;
        } else {
            try {
                StringBuilder sb = new StringBuilder();
                sb.append(payload.toString());
                if (this.addEventSeparator) {
                    sb.append("\n");
                }
                byteArray = sb.toString().getBytes(Constants.UTF_8);
            } catch (UnsupportedEncodingException e) {
                canBeWritten = false;
                log.error("Received payload does not support UTF-8 encoding. Hence dropping the event." , e);
            }
        }

        if (canBeWritten) {
            String uri = uriOption.getValue(dynamicOptions);
            BinaryCarbonMessage binaryCarbonMessage = new BinaryCarbonMessage(ByteBuffer.wrap(byteArray), true);
            properties.put(Constants.URI, uri);
            try {
                vfsClientConnector.send(binaryCarbonMessage, null, properties);
            } catch (ClientConnectorException e) {
                throw new ConnectionUnavailableException("Writing data into the file " + uri + " failed during the " +
                        "execution of '" + siddhiAppContext.getName() + "' SiddhiApp, due to " +
                        e.getMessage(), e);
            }
        }
    }

    public Map currentState() {
        return new HashMap<>();
    }

    public void restoreState(Map map) {
        //do nothing
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy