Java tutorial
package jp.gr.java_conf.petit_lycee.subsonico; import android.util.Base64; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.utils.URLEncodedUtils; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Stack; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import jp.gr.java_conf.petit_lycee.utils.StringUtil; class MethodConstants { public static final String PING = "ping"; public static final String GET_LICENSE = "getLicense"; public static final String GET_INDEXES = "getIndexes"; public static final String GET_MUSIC_DIRECTORY = "getMusicDirectory"; public static final String GET_ALBUM = "getAlbum"; public static final String GET_SONG = "getSong"; public static final String STREAM = "stream"; } /*** * Subsonic??? */ class SubsonicXMLHandler extends DefaultHandler { private Stack<ArrayList<Entry>> stack; private SubsonicException subsEx = null; private SubsonicResponse response; public boolean isError() { return subsEx != null; } public SubsonicException getException() { return subsEx; } public SubsonicResponse getResponse() { return response; } public void startDocument() { subsEx = null; response = new SubsonicResponse(); response.setEntryList(new ArrayList<Entry>()); stack = new Stack<ArrayList<Entry>>(); stack.push(response.getEntryList()); } private Field getField(@SuppressWarnings("rawtypes") Class cls, String fieldName) throws NoSuchFieldException { try { return cls.getDeclaredField(fieldName); } catch (NoSuchFieldException e) { @SuppressWarnings("rawtypes") Class super_cls = cls.getSuperclass(); //???? //?? if (super_cls != null && super_cls.getPackage().equals(cls.getPackage())) { return getField(super_cls, fieldName); } throw e; } } /*** * ??????? * int,boolean,String,Date?? * @param obj * @param attrs attributes */ private void setValues(Object obj, org.xml.sax.Attributes attrs) { for (int i = 0; i < attrs.getLength(); i++) { try { Field field = getField(obj.getClass(), attrs.getLocalName(i)); field.setAccessible(true); String attr_value = attrs.getValue(i); if (field.getType() == boolean.class) { field.setBoolean(obj, Boolean.valueOf(attr_value)); } else if (field.getType() == int.class) { field.setInt(obj, Integer.parseInt(attr_value)); } else if (field.getType() == String.class) { field.set(obj, attr_value); } else if (field.getType() == Date.class) { String format = "yyyy-MM-dd'T'HH:mm:ss"; field.set(obj, StringUtil.toDate(attr_value, format)); } } catch (Exception ignored) { } } } public void startElement(String namespaceURI, String localName, String qName, org.xml.sax.Attributes attributes) { ResponseElement elem = null; //element???? //(error????) if (qName.equals("subsonic-response")) { //set response data response.setStatus(attributes.getValue("status")); response.setVersion(attributes.getValue("version")); if (!"ok".equals(response.getStatus())) { subsEx = new SubsonicException(); } } else if (qName.equals("error")) { if (subsEx != null) setValues(subsEx, attributes); } else if (qName.equals("directory")) { Directory p = new Directory(); p.setDir(true); elem = p; } else if (qName.equals("index")) { elem = new Index(); } else if (qName.equals("child")) { int spam = attributes.getIndex("isDir"); if (spam >= 0 && attributes.getValue(spam).equals("true")) { elem = new Directory(); } else { elem = new Media(); } } else if (qName.equals("artist")) { elem = new Directory(); } else if (qName.equals("song")) { elem = new Media(); } else if (qName.equals("license")) { elem = new License(); } if (elem != null) { setValues(elem, attributes); if (elem instanceof Entry) { Entry etr = (Entry) elem; ArrayList<Entry> list = stack.peek(); list.add(etr); stack.push(etr.children); } } } public void endElement(String namespaceURI, String localName, String qName) { if (qName.equals("directory") || qName.equals("index") || qName.equals("child") || qName.equals("artist") || qName.equals("song")) { stack.pop(); } } } public class SubsonicAccessor { private String top_url;// = "http://ore-no-server/rest/ping.view?v=1.1.0&c=myapp"; private String user_id; private String passwd; private String api_version = "1.8.0"; private String app_name = "subsonico"; private int max_bit_rate = 320; public void setTop_url(String top_url) { if (!top_url.endsWith("/")) { top_url += "/"; } this.top_url = top_url; } public void setPasswd(String passwd) { this.passwd = passwd; } public void setUser_id(String user_id) { this.user_id = user_id; } SubsonicResponse parseResponseXML(InputStream is) throws SubsonicException, IOException, SAXException, ParserConfigurationException { SubsonicXMLHandler handler = new SubsonicXMLHandler(); SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); parser.parse(is, handler); if (handler.isError()) { throw handler.getException(); } return handler.getResponse(); } /*** * ????? * todo:stream??? */ SubsonicResponse getSubsonicResponse(String req, ArrayList<BasicNameValuePair> params) throws SubsonicException { HttpResponse res; final String error_code = "XX"; try { res = getServerResponse(req, params); } catch (IOException e) { throw new SubsonicException(error_code, e.getMessage()); } try { HttpEntity entity = res.getEntity(); return parseResponseXML(entity.getContent()); } catch (SubsonicException e) { throw e; } catch (Exception e) { throw new SubsonicException(error_code, e.getMessage()); } } private String getRequestUrl(String reqMethod, List<BasicNameValuePair> param) { StringBuilder sb = new StringBuilder(); sb.append(top_url); sb.append("rest/"); sb.append(reqMethod); sb.append(".view?"); sb.append("v="); sb.append(api_version); sb.append("&c="); sb.append(app_name); if (param != null) { sb.append("&"); sb.append(URLEncodedUtils.format(param, "UTF-8")); } return sb.toString(); } private HttpResponse getServerResponse(String reqMethod, List<BasicNameValuePair> params) throws IOException { String url = getRequestUrl(reqMethod, params); HttpGet method = new HttpGet(url); DefaultHttpClient client = new DefaultHttpClient(); // ? String tmp = Base64.encodeToString((user_id + ":" + passwd).getBytes(), Base64.NO_WRAP); method.setHeader("Authorization", "Basic " + tmp); HttpResponse response = client.execute(method); int status = response.getStatusLine().getStatusCode(); if (status == HttpStatus.SC_OK) { return response; } else { //TODO:? return null; } } /*** * Used to test connectivity with the server. Takes no extra parameters. * @return SubsonicResponse * @throws SubsonicException */ public SubsonicResponse ping() throws SubsonicException { return getSubsonicResponse(MethodConstants.PING, null); } /*** * Get details about the software license. * @return SubsonicResponse * @throws SubsonicException */ public SubsonicResponse getLicense() throws SubsonicException { return getSubsonicResponse(MethodConstants.GET_LICENSE, null); } /*** * Returns an indexed structure of all artists. * @return SubsonicResponse * @throws SubsonicException */ public SubsonicResponse getIndexes() throws SubsonicException { return getSubsonicResponse(MethodConstants.GET_INDEXES, null); } /*** * Returns a listing of all files in a music directory. Typically used to get list of albums for an artist, or list of songs for an album. * @param id identifies the music folder * @return SubsonicResponse * @throws SubsonicException */ public SubsonicResponse getMusicDirectory(String id) throws SubsonicException { ArrayList<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>(); params.add(new BasicNameValuePair("id", id)); return getSubsonicResponse(MethodConstants.GET_MUSIC_DIRECTORY, params); } /*** * Returns details for an album, including a list of songs. This method organizes music according to ID3 tags. * @param id album'ID * @return SubsonicResponse * @throws SubsonicException */ public SubsonicResponse getAlbum(String id) throws SubsonicException { ArrayList<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>(); params.add(new BasicNameValuePair("id", id)); return getSubsonicResponse(MethodConstants.GET_ALBUM, params); } /*** * Returns details for a song. * @param id the song ID * @return SubsonicResponse * @throws SubsonicException */ public SubsonicResponse getSong(String id) throws SubsonicException { ArrayList<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>(); params.add(new BasicNameValuePair("id", id)); return getSubsonicResponse(MethodConstants.GET_SONG, params); } /*** * Streams a given media file. * @param id id the file to stream. * @return a response from Server * @throws SubsonicException */ public SubsonicResponse stream(String id) throws SubsonicException { ArrayList<BasicNameValuePair> params = new ArrayList(); params.add(new BasicNameValuePair("id", id)); return getSubsonicResponse(MethodConstants.STREAM, params); } }