Package com.englishtown.vertx

Source Code of com.englishtown.vertx.CouchbasePersistor

/*
* The MIT License (MIT)
* Copyright © 2013 Englishtown <opensource@englishtown.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the “Software”), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package com.englishtown.vertx;

import com.englishtown.vertx.clients.EtCouchbaseClient;
import com.englishtown.vertx.clients.EtCouchbaseClientFactory;
import com.google.common.util.concurrent.FutureCallback;
import net.spy.memcached.PersistTo;
import net.spy.memcached.ReplicateTo;
import org.vertx.java.core.Handler;
import org.vertx.java.core.buffer.Buffer;
import org.vertx.java.core.eventbus.EventBus;
import org.vertx.java.core.eventbus.Message;
import org.vertx.java.core.json.JsonArray;
import org.vertx.java.core.json.JsonObject;
import org.vertx.java.core.logging.Logger;
import org.vertx.java.platform.Verticle;

import javax.inject.Inject;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

/**
*/
public class CouchbasePersistor extends Verticle implements Handler<Message<JsonObject>> {
    private static final String DEFAULT_ADDRESS = "et.mod.couchbase";
    private final EtCouchbaseClientFactory clientFactory;
    private String address;
    private EventBus eb;
    private Logger logger;
    private List<URI> couchHosts;
    private final HashMap<String, EtCouchbaseClient> clients = new HashMap<>();
    private String password;
    private boolean asyncWrites;

    @Inject
    public CouchbasePersistor(EtCouchbaseClientFactory clientFactory) {
        this.clientFactory = clientFactory;
    }

    @Override
    public void start() {
        super.start();
        logger = container.logger();
        eb = vertx.eventBus();
        configure(container.config());

        System.out.println("Address is " + address);
        eb.registerHandler(address, this);
        eb.registerHandler(address + "/saveChunk", new Handler<Message>() {
            @Override
            public void handle(Message message) {
                doSaveChunk(message);
            }
        });
    }

    public void configure(JsonObject config) {
        address = config.getString("address", DEFAULT_ADDRESS);
        address = (address.equals("") ? DEFAULT_ADDRESS : address);

        asyncWrites = config.getBoolean("async_writes", false);
        password = config.getString("password", "");

        try {
            couchHosts = getHostsFromConfig(config);
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }

    private List<URI> getHostsFromConfig(JsonObject config) throws URISyntaxException {
        List<URI> hosts = new ArrayList<>();

        JsonArray hostsAsArray = config.getArray("hosts", new JsonArray().addString("localhost"));
        String[] hostsAsString = Arrays.copyOf(hostsAsArray.toArray(), hostsAsArray.toArray().length, String[].class);
        for (String hostname : hostsAsString) {
            hosts.add(new URI("http://" + hostname + ":8091/pools"));
        }

        return hosts;
    }

    @Override
    public void handle(Message<JsonObject> message) {
        String action = getMandatoryString("action", message);
        switch (action) {
            case "saveDocument":
                doSaveDocument(message);
                break;
            case "getDocument":
                doGetDocument(message);
                break;
            case "getChunk":
                doReadChunk(message);
                break;
            default:
                sendError(message, "Unknown action specified");
        }
    }

    private void doReadChunk(final Message<JsonObject> message) {
        try {
            EtCouchbaseClient client = clientFactory.getClient(couchHosts, getMandatoryString("bucket", message), password);
            String fileId = getMandatoryString("files_id", message);
            Number n = getMandatoryNumber("n", message);
            String key = fileId + "!" + n;

            client.asyncGet(key, new FutureCallback<Object>() {
                @Override
                public void onSuccess(Object o) {
                    message.reply((byte[]) o);
                }

                @Override
                public void onFailure(Throwable throwable) {
                    message.reply(throwable);
                }
            });
        } catch (Exception e) {
            message.reply(e);
        }
    }

    private void doSaveChunk(Message<Buffer> message) {
        JsonObject jsonObject;
        byte[] data;

        // Parse the byte[] message body
        try {
            Buffer body = message.body();

            // First four bytes indicate the json string length
            int len = body.getInt(0);

            // Decode json
            int from = 4;
            byte[] jsonBytes = body.getBytes(from, from + len);
            jsonObject = new JsonObject(decode(jsonBytes));

            // Remaining bytes are the chunk to be written
            from += len;
            data = body.getBytes(from, body.length());
        } catch (RuntimeException e) {
            sendError(message, "Error while extracting message", e);
            return;
        }

        try {
            EtCouchbaseClient client = clientFactory.getClient(couchHosts, jsonObject.getString("bucket"), password);
            String key = jsonObject.getString("files_id") + "!" + jsonObject.getNumber("n");

            if (asyncWrites) {
                client.set(key, data, PersistTo.ZERO, ReplicateTo.ZERO);
            } else {
                client.set(key, data).get();
            }
            sendOK(message);
        } catch (Exception e) {
            sendError(message, "Error while writing to database", e);
        }
    }

    private void doGetDocument(final Message<JsonObject> message) {
        try {
            EtCouchbaseClient client = clientFactory.getClient(couchHosts, getMandatoryString("bucket", message), password);
            String key = getMandatoryString("key", message);
            client.asyncGet(key, new FutureCallback<String>() {
                @Override
                public void onSuccess(String s) {
                    sendOK(message, (s == null ? new JsonObject() : new JsonObject(s)));
                }

                @Override
                public void onFailure(Throwable throwable) {
                    sendError(message, "Failed to retrieve record", throwable);
                }
            });
        } catch (Exception e) {
            sendError(message, e.getMessage());
        }
    }

    private void doSaveDocument(Message<JsonObject> message) {
        try {
            EtCouchbaseClient client = clientFactory.getClient(couchHosts, getMandatoryString("bucket", message), password);
            String id = getMandatoryString("id", message);
            String document = getMandatoryObject("document", message).toString();

            if (asyncWrites) {
                client.set(id, document, PersistTo.ZERO, ReplicateTo.ZERO);
            } else {
                client.set(id, document).get();
            }

            sendOK(message);
        } catch (Exception e) {
            sendError(message, e.getMessage());
        }
    }

    public <T> void sendError(Message<T> message, String error) {
        sendError(message, error, null);
    }

    public <T> void sendError(Message<T> message, String error, Throwable e) {
        logger.error(error, e);
        JsonObject result = new JsonObject().putString("status", "error").putString("message", error);
        message.reply(result);
    }

    public <T> void sendOK(Message<T> message) {
        sendOK(message, new JsonObject());
    }

    public <T> void sendOK(Message<T> message, JsonObject response) {
        response.putString("status", "ok");
        message.reply(response);
    }

    private String decode(byte[] bytes) {
        try {
            return new String(bytes, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            // Should never happen
            throw new RuntimeException(e);
        }
    }

    private String getMandatoryString(String fieldName, Message<JsonObject> message) {
        String fieldValue = message.body().getString(fieldName);
        if (fieldValue == null) {
            sendError(message, "Could not find mandatory fieldname " + fieldName);
        }

        return fieldValue;
    }

    private Number getMandatoryNumber(String fieldName, Message<JsonObject> message) {
        Number fieldValue = message.body().getNumber(fieldName);
        if (fieldValue == null) {
            sendError(message, "Could not find mandatory fieldname " + fieldName);
        }

        return fieldValue;
    }

    private JsonObject getMandatoryObject(String fieldName, Message<JsonObject> message) {
        JsonObject fieldValue = message.body().getObject(fieldName);
        if (fieldValue == null) {
            sendError(message, "Could not find mandatory fieldname " + fieldName);
        }

        return fieldValue;
    }

    public String getAddress() {
        return address;
    }

    public List<URI> getCouchHosts() {
        return couchHosts;
    }

    public String getPassword() {
        return password;
    }

    public boolean isAsyncWrites() {
        return asyncWrites;
    }
}
TOP

Related Classes of com.englishtown.vertx.CouchbasePersistor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.