/* Copyright (c) 2007 Roland Sch�r
*
* Licensed 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 ch.rolandschaer.ascrblr.scrobbler;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import org.xml.sax.SAXException;
import ch.rolandschaer.ascrblr.HttpRequest;
import ch.rolandschaer.ascrblr.Service;
import ch.rolandschaer.ascrblr.Session;
import ch.rolandschaer.ascrblr.HttpRequest.Factory;
import ch.rolandschaer.ascrblr.HttpRequest.RequestType;
import ch.rolandschaer.ascrblr.data.Feed;
import ch.rolandschaer.ascrblr.scrobbler.impl.AudioscrobblerImpl;
import ch.rolandschaer.ascrblr.util.NotSupportedOperationException;
import ch.rolandschaer.ascrblr.util.ServiceException;
/**
* TODO: Implement radio MP3 stream.
*/
public class AudioscrobblerService extends Service {
/** Default protocol implementation */
private String protocolVersion = "1.2";
/** Default client id. For possible values please visit */
private String clientId = "tst";
/** Default client version. */
private String clientVersion = "1.0";
/** Protocol implementation */
private static AudioscrobblerImpl protocolImpl;
/**
* Session token which encapsulates the session identifier returned
* by the service after the handshake.
*/
private Session session = null;
/**
* Initialize <code>AudioscrobblerService</code> with default
* client id and client version number values. In this case the
* client id 'tst', client version '1.0' and protocol 1.2 is used.
*/
public AudioscrobblerService() {
protocolImpl = Factory.create(protocolVersion);
}
/**
* Initialize <code>AudioscrobblerService</code> with specific protocol
* version.
*
* @param protocolVersion Protocol version (1.1 or 1.2)
*/
public AudioscrobblerService(String protocolVersion) {
this.protocolVersion = protocolVersion;
protocolImpl = Factory.create(protocolVersion);
}
/**
* Initialize <code>AudioscrobblerService</code> with specific
* client id and client version.
* @param clientId
* Client identifier given from last.fm. For development and
* testing purpose the identifier 'tst' is used.
* Possible values are:
* <li>Applescriptable MacOS X Application (iTunes) = osx
* <li>Winamp2 = wa2 <li>Winamp3 = wa3
* <li>XMMS = xms <li>XMMS2 = xm2
* <li>Windows Media Player = wmp
* <li>SliMP3 = slm
* <li>MusicMatch Jukebox = mmj
* <li>FooBar = foo
* <li>QCD = qcd
* <li>AmigaAMP = ami
* <li>BMPx = mpx
* <li>Audacious = aud
* <li>Herrie = her
*
* @param clientVersion
* Version number of client beeing used. If client id 'tst' is used,
* use version '1.0'.
*/
public AudioscrobblerService(String clientId, String clientVersion) {
this.clientId = clientId;
this.clientVersion = clientVersion;
protocolImpl = Factory.create(protocolVersion);
}
/**
* Sets the service credentials used for authentication.
* By calling this method a request of type HANDSHAKE is
* done to obtain a valid session.
*
* @param username
* Audioscrobbler user name
* @param password
* Audioscrobbler password
* @throws IOException
* @throws ServiceException
*/
public void setCredentials(String username, String password) throws IOException, ServiceException {
protocolImpl.setCredentials(username, password);
if(session == null) {
handshake();
}
}
/**
* Propagates handshake to the protocol implementation.
*
* @throws IOException
* @throws ServiceException
*/
private void handshake() throws IOException, ServiceException {
String url = protocolImpl.handshake(clientId, clientVersion);
doRequest(RequestType.HANDSHAKE, url);
}
/**
* Submit data of the recently played tracks to the service.
*
* @param submission
* <code>Submission</code> object containing the audio meta
* data
* @throws IOException
* @throws ServiceException
*/
public void submit(TrackInfo trackInfo) throws IOException, ServiceException {
if (session == null) {
handshake();
}
String url = protocolImpl.submit(trackInfo);
doRequest(RequestType.SUBMISSION, url);
}
/**
* Notifies the service of the track currently played.
*
* @param notification
* <code></code> object containing the audio meta data
* @throws IOException
* @throws ServiceException
*/
public void notifyNew(TrackInfo trackInfo) throws IOException, ServiceException {
if(protocolImpl.getVersion().equals("1.1")){
throw new NotSupportedOperationException("The protocol version 1.1 does not support notification");
}
if(session == null) {
handshake();
}
String url = protocolImpl.notifyNew(trackInfo);
doRequest(RequestType.NOTIFY, url);
}
/**
* Gets a feed from the Audioscrobbler Data API.
*
* @param feedClass
* Feed class
* @return Parsed feed
* @throws IOException
* @throws ServiceException
*/
public Feed getFeed(Feed feed) throws IOException, ServiceException {
InputStream resultStream = null;
try {
HttpRequest request = requestFactory.getRequest(RequestType.QUERY, new URL(feed.getUrl()));
if(connectTimeout>0) {
request.setConnectTimeout(connectTimeout);
}
if(readTimeout>0) {
request.setReadTimeout(readTimeout);
}
// Execute the request
request.execute();
resultStream = request.getResponseStream();
feed.parse(resultStream);
return feed;
} catch(SAXException e) {
throw new ServiceException(e);
} finally {
if (resultStream != null) {
resultStream.close();
}
}
}
/*
* (non-Javadoc)
* @see ch.rolandschaer.ascrblr.Service#handleResponse(java.io.InputStream)
*/
protected void handleResponse(InputStream responseStream) throws IOException, ServiceException {
protocolImpl.handleResponse(responseStream);
if(session == null) {
session = protocolImpl.getSession();
}
}
/*
* (non-Javadoc)
* @see ch.rolandschaer.ascrblr.Service#getVersion()
*/
public String getVersion() {
return protocolImpl.getVersion();
}
/**
* Returns client version used for requests.
*
* @return Client version
*/
public String getClientVersion() {
return clientVersion;
}
/**
* Returns client identifier used for requests.
*
* @return Client identifier
*/
public String getClientId() {
return clientId;
}
/**
* Loads a class via reflection.
*
* @param className
* Class to load
* @return
*/
private static Object loadImpl(String className) {
Object impl = null;
try {
impl = Class.forName(className).newInstance();
} catch (ClassNotFoundException e) {
logger.severe(e.getMessage());
} catch (InstantiationException e) {
logger.severe(e.getMessage());
} catch (IllegalAccessException e) {
logger.severe(e.getMessage());
}
return impl;
}
private static class Factory {
/**
* Creates an AudioscrobblerService instance.
*
* @param protocolVersion
* Protocol version 1.1 or 1.2
* @return
*/
public static AudioscrobblerImpl create(String protocolVersion) {
Object o;
if (protocolVersion.equals("1.2")) {
o = AudioscrobblerService.loadImpl("ch.rolandschaer.ascrblr.scrobbler.impl.Audioscrobbler12Impl");
} else {
o = AudioscrobblerService.loadImpl("ch.rolandschaer.ascrblr.scrobbler.impl.Audioscrobbler11Impl");
}
return (AudioscrobblerImpl)o;
}
}
}