org.marietjedroid.connect.MarietjeClient.java Source code

Java tutorial

Introduction

Here is the source code for org.marietjedroid.connect.MarietjeClient.java

Source

/**
 * @licence GNU General Public licence http://www.gnu.org/copyleft/gpl.html
 * @Copyright (C) 2012 Thom Wiggers
 * 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
 * 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 org.marietjedroid.connect;

import java.io.FileInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;
import java.util.concurrent.Semaphore;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class MarietjeClient extends Observable implements Observer {

    private static final String DEFAULT_REQUESTER = "marietje";
    /**
     * Locks until we have recieved tracks
     */
    private final Semaphore tracksRetrieved = new Semaphore(0);
    /**
     * Locks until we have retrieved a now playing track
     */
    private final Semaphore playingRetrieved = new Semaphore(0);
    /**
     * Blocks until we have retrieved requests
     */
    private final Semaphore requestsRetrieved = new Semaphore(0);

    /**
     * Blocks until we get answer from a login attempt
     */
    private final Semaphore loginAttempt = new Semaphore(0);

    private final Semaphore queryResults = new Semaphore(0);

    private MarietjeClientChannel channel = null;

    private String accessKey = "";

    Integer queryToken = 0;

    private boolean followingPlaying = false;

    private boolean followingQueue = false;

    /**
     * Creates a new instance of a connection, immediately starts polling
     * Marietje
     * 
     * @param host
     * @param port
     * @param path
     * @throws MarietjeException
     */
    public MarietjeClient(String host, int port, String path) throws MarietjeException {
        this.channel = new MarietjeClientChannel(this, host, port, path);
    }

    /**
     * 
     * @return
     */
    Semaphore getTracksRetrievedSemaphore() {
        return tracksRetrieved;
    }

    /**
     * @return the playingRetrieved
     */
    Semaphore getPlayingRetrievedSemaphore() {
        return playingRetrieved;
    }

    Semaphore getRequestsRetrievedSemaphore() {
        return requestsRetrieved;
    }

    Semaphore getLoginAttemptSemaphore() {
        return loginAttempt;
    }

    /**
     * Gets the queue Blocks until we have it
     * 
     * @return
     * @throws MarietjeException
     */
    public MarietjeTrack[] getQueue() throws MarietjeException {
        if (channel.getException() != null)
            throw channel.getException();

        ArrayList<MarietjeRequest> queue = new ArrayList<MarietjeRequest>();

        try {
            if (!this.followingQueue || this.channel.getRequests() == null) {
                this.followQueue();
                this.requestsRetrieved.acquire();

            }

            JSONArray requests = this.channel.getRequests();

            for (int i = 0; requests.optJSONObject(i) != null; i++) {
                JSONObject req = requests.getJSONObject(i);
                JSONObject media = req.getJSONObject("media");
                String requester = req.optString("byKey", DEFAULT_REQUESTER);
                queue.add(new MarietjeRequest(requester, req.getInt("key"), media));
            }

        } catch (JSONException e) {
            throw new MarietjeException("JSON Error");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return queue.toArray(new MarietjeTrack[0]);
    }

    /**
     * Start following queue updates
     * 
     * @throws MarietjeException
     */
    public void followQueue() throws MarietjeException {
        if (channel.getException() != null)
            throw channel.getException();

        try {
            this.channel.sendMessage("{'type':'follow','which':['requests']}");
            this.followingQueue = true;
        } catch (JSONException e) {
            throw new MarietjeException("JSON Error");
        }
    }

    /**
     * Stop following queue updates
     * 
     * @throws MarietjeException
     */
    public void unfollowQueue() throws MarietjeException {
        if (channel.getException() != null)
            throw channel.getException();

        this.followingQueue = false;
        try {
            this.channel.sendMessage(new JSONObject("{'type':'unfollow','which':['requests']}"));
        } catch (JSONException e) {
            throw new MarietjeException("JSON error");
        }
    }

    /**
     * locks when waiting for a track
     * 
     * @return the now playing track
     * @throws MarietjeException
     */
    public MarietjePlaying getPlaying() throws MarietjeException {
        if (channel.getException() != null)
            throw channel.getException();

        MarietjePlaying nowPlaying = null;
        try {
            if (!followingPlaying || this.channel.getNowPlaying() == null) {
                this.followPlaying();
                this.playingRetrieved.acquire();
            }
            JSONObject np = this.channel.getNowPlaying();
            JSONObject media = np.getJSONObject("media");
            double servertime = np.getDouble("serverTime");
            double endtime = np.getDouble("endTime");
            String byKey = np.getString("byKey");
            nowPlaying = new MarietjePlaying(byKey, servertime, endtime, media);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (JSONException e) {
            throw new MarietjeException("JSON error");
        }

        return nowPlaying;
    }

    /**
     * Start following np updates
     * 
     * @throws MarietjeException
     */
    public void followPlaying() throws MarietjeException {
        if (channel.getException() != null)
            throw channel.getException();

        try {
            this.channel.sendMessage("{'type':'follow','which':['playing']}");
            this.followingPlaying = true;
        } catch (JSONException e) {
            throw new MarietjeException("JSON error");
        }

    }

    /**
     * Stop following the now playing updates
     * 
     * @throws MarietjeException
     */
    public void unfollowNowPlaying() throws MarietjeException {
        if (channel.getException() != null)
            throw channel.getException();
        try {
            this.channel.sendMessage("{'type':'unfollow','which':'['playing']}");
            this.followingPlaying = false;
        } catch (JSONException e) {
            throw new MarietjeException("JSON error");
        }
    }

    /**
     * Logs in, or throws an exception.
     * 
     * @param username
     * @param password
     * @throws MarietjeException
     */
    public void login(String username, String password) throws MarietjeException {

        if (channel.getException() != null)
            throw channel.getException();

        if (this.isLoggedIn())
            return;

        try {
            this.channel.sendPriorityMessage("{'type':'request_login_token'}");
            this.loginAttempt.acquire();
        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        String token = this.channel.getLoginToken();

        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new MarietjeException("Problem with MD5 Message digest");
        }
        String md5pass = new String(org.apache.commons.codec.binary.Hex.encodeHex(md5.digest(password.getBytes())));
        String hash = new String(
                org.apache.commons.codec.binary.Hex.encodeHex(md5.digest((md5pass + token).getBytes())));

        try {
            this.channel.sendPriorityMessage(
                    "{'type':'login', 'username':'" + username + "'," + "'hash':'" + hash + "'}");
        } catch (JSONException e) {
            throw new MarietjeException("Problem with the JSON feed");
        }
        try {
            this.loginAttempt.acquire();
            if (this.channel.getLoginError() != null) {
                throw this.channel.getLoginError();
            }
            this.accessKey = this.channel.getAccessKey();

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    /**
     * Requests a track
     * 
     * @param trackid
     * @throws MarietjeException
     */
    public void requestTrack(String trackid) throws MarietjeException {
        if (channel.getException() != null)
            throw channel.getException();

        if (this.accessKey.equals(""))
            throw new MarietjeException("You must log in");
        try {
            this.channel.sendPriorityMessage("{'type':'request','mediaKey':'" + trackid + "'}");
            this.requestsRetrieved.acquire();
            if (this.channel.getRequestError() != null) {
                throw new MarietjeException(this.channel.getRequestError());
            }
        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * Upload a track
     * 
     * 
     * locks
     * 
     * TODO
     * 
     * @param artist
     * @param title
     * @param f
     * @throws MarietjeException
     */
    public void uploadTrack(String artist, String title, FileInputStream f) throws MarietjeException {
        if (channel.getException() != null)
            throw channel.getException();

    }

    /**
     * Zoeken
     * 
     * @param query
     * @return
     * @throws MarietjeException
     */
    public MarietjeTrack[] search(String query) throws MarietjeException {
        return this.search(query, 0, 10);
    }

    /**
     * Zoeken
     * 
     * @param query
     * @param skip
     * @param count
     * @return the list of tracks found, or null.
     * @throws MarietjeException
     */
    public MarietjeTrack[] search(String query, int skip, int count) throws MarietjeException {
        if (channel.getException() != null)
            throw channel.getException();
        synchronized (queryToken) {
            this.queryToken++;
        }

        try {
            this.channel.sendPriorityMessage("{'type':'query_media', 'token':" + queryToken + ",'skip':" + skip
                    + ",'count':" + count + ",'query':'" + query + "'}");
            this.queryResults.acquire();
            return this.channel.getQueryResults();
        } catch (JSONException e) {
            throw new MarietjeException("Problem with the JSON feed");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @return
     */
    Semaphore getQueryResultsRetrievedSemaphore() {
        return this.queryResults;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
     */
    public void update(Observable o, Object arg) {
        this.setChanged();
        this.notifyObservers(arg);

    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.Observable#addObserver(java.util.Observer)
     */
    public void addObserver(Observer o) {
        super.addObserver(o);
    }

    /**
     * @return is logged in?
     */
    public boolean isLoggedIn() {
        return !accessKey.equals("");
    }

}