com.idlegandalf.ledd.services.ColorService.java Source code

Java tutorial

Introduction

Here is the source code for com.idlegandalf.ledd.services.ColorService.java

Source

/*
 * LEDD Project
 * Copyright (C) 2015 LEDD Team
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.idlegandalf.ledd.services;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;

import com.idlegandalf.ledd.components.AnswerTask;
import com.idlegandalf.ledd.components.LedDDaemon;
import com.idlegandalf.ledd.components.Sendable;
import com.koushikdutta.async.AsyncServer;
import com.koushikdutta.async.AsyncSocket;
import com.koushikdutta.async.ByteBufferList;
import com.koushikdutta.async.DataEmitter;
import com.koushikdutta.async.Util;
import com.koushikdutta.async.callback.ConnectCallback;
import com.koushikdutta.async.callback.DataCallback;
import com.thetransactioncompany.jsonrpc2.JSONRPC2ParseException;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;

import org.json.JSONException;

import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ColorService extends Service {
    private static ScheduledThreadPoolExecutor poolExecutor = new ScheduledThreadPoolExecutor(5);
    private final IBinder mBinder = new ColorBinder();
    private LinkedBlockingQueue<Sendable> queue;
    private Worker<Sendable> worker;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return -1;
    }

    @Override
    public IBinder onBind(Intent intent) {
        queue = new LinkedBlockingQueue<>();
        worker = new Worker<>(queue);
        new Thread(worker).start();

        return mBinder;
    }

    @Override
    public void onDestroy() {
        worker.stop();
        poolExecutor.shutdownNow();
    }

    private static class Worker<T> implements Runnable {
        private final LinkedBlockingQueue<T> workQueue;
        private HashMap<LedDDaemon, AsyncSocket> socketHashMap;
        private HashMap<String, Sendable> sendableHashMap;
        private HashMap<String, ScheduledFuture> timeoutHashMap;

        DataCallback dataCallback = new DataCallback() {
            @Override
            public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
                JSONRPC2Response reqIn = null;
                String dataStr = new String(bb.getAllByteArray());

                if (!dataStr.isEmpty()) {
                    try {
                        reqIn = JSONRPC2Response.parse(dataStr);
                    } catch (JSONRPC2ParseException e) {
                        e.printStackTrace();
                    }
                }

                if (reqIn != null) {
                    if (sendableHashMap.containsKey(reqIn.getID().toString())) {
                        sendableHashMap.get(reqIn.getID().toString()).onResponse(reqIn);
                        sendableHashMap.remove(reqIn.getID().toString());
                        if (timeoutHashMap.containsKey(reqIn.getID().toString())
                                && timeoutHashMap.get(reqIn.getID().toString()) != null)
                            timeoutHashMap.get(reqIn.getID().toString()).cancel(false);
                        timeoutHashMap.remove(reqIn.getID().toString());
                    }
                }
            }
        };

        public Worker(LinkedBlockingQueue<T> workQueue) {
            this.workQueue = workQueue;
            this.socketHashMap = new HashMap<>();
            this.sendableHashMap = new HashMap<>();
            this.timeoutHashMap = new HashMap<>();
        }

        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    final T item = workQueue.take();

                    if (item instanceof Sendable) {
                        final Sendable sendable = (Sendable) item;
                        if (socketHashMap.containsKey(sendable.getRecipient())) {
                            if (socketHashMap.get(sendable.getRecipient()) == null) {
                                // if server is not running yet, readd item to queue
                                workQueue.add(item);
                                continue;
                            } else if (!socketHashMap.get(sendable.getRecipient()).getServer().isRunning()) {
                                // connection probably closed or was interrupted -> reconnect
                                socketHashMap.remove(sendable.getRecipient());
                                workQueue.add(item);
                                continue;
                            }

                            Util.writeAll(socketHashMap.get(sendable.getRecipient()),
                                    (sendable.getRequest().toString() + "\n").getBytes("UTF-8"), null);
                            sendableHashMap.put((String) sendable.getRequest().getID(), sendable);
                            if (!poolExecutor.isTerminating() && !poolExecutor.isTerminated())
                                timeoutHashMap.put((String) sendable.getRequest().getID(),
                                        poolExecutor.schedule(new Runnable() {
                                            @Override
                                            public void run() {
                                                sendable.onNoResponse();
                                                timeoutHashMap.remove(sendable.getRequest().getID());
                                                sendableHashMap.remove(sendable.getRequest().getID());
                                            }
                                        }, 1000, TimeUnit.MILLISECONDS));
                        } else {
                            socketHashMap.put(sendable.getRecipient(), null);
                            AsyncServer.getDefault()
                                    .connectSocket(new InetSocketAddress(sendable.getRecipient().getAddress(),
                                            sendable.getRecipient().getPort()), new ConnectCallback() {
                                                @Override
                                                public void onConnectCompleted(Exception ex,
                                                        final AsyncSocket socket) {
                                                    if (ex == null) {
                                                        socket.setDataCallback(dataCallback);

                                                        socketHashMap.put(sendable.getRecipient(), socket);

                                                        //if (!workQueue.contains(item)) -> needs equals implementation
                                                        workQueue.add(item);
                                                    } else {
                                                        sendable.onConnectionFailed(ex.getMessage());
                                                    }
                                                }
                                            });
                        }
                    }
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                    break;
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
        }

        public void stop() {
            Thread.currentThread().interrupt();
        }
    }

    public class ColorBinder extends Binder {
        public void queueSend(LedDDaemon rec, JSONRPC2Request request, AnswerTask answerTask) {
            Sendable sendable = null;
            try {
                sendable = new Sendable(request, answerTask, rec);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            if (sendable != null) {
                queue.add(sendable);
            }
        }
    }
}