package org.sana.android.media; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Hashtable; import java.util.List; import java.util.Map; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.sana.android.media.EducationResource.Audience; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import android.text.TextUtils; import android.util.Log; /** * Parses education resources from xml. * * @author Sana Development Team */ public class EducationResourceParser { public static String TAG = EducationResourceParser.class.getSimpleName(); private EducationResourceHandler handler; /** * Creates a new parser for a education resource info xml resource */ private EducationResourceParser(){} /** * Returns a new parser * @return */ public static EducationResourceParser newInstance(){ return new EducationResourceParser(); } /** * Parses an Input source for education resources * * @param source The input source to read from * @throws ParserConfigurationException * @throws SAXException * @throws IOException */ public void parse(InputSource source) throws ParserConfigurationException, SAXException, IOException { Log.d(TAG, "parse()"); SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); XMLReader xr = sp.getXMLReader(); handler = new EducationResourceHandler(); xr.setContentHandler(handler); xr.parse(source); } /** * Returns the list of education resources parsed from a resource * * @param audience The target audience * @return */ public List<EducationResource> infoList(Audience audience){ return new ArrayList<EducationResource>(handler.infoList(audience)); } /** * Returns the list of media resources parsed from a resource * @return */ public List<EducationResource> infoList(List<String> ids, Audience audience){ return new ArrayList<EducationResource>(handler.infoList(ids, audience)); } /** * Finds a media resource by its id from a parsed xml source * * @param id The resource id * @param audience The target audience * @return */ public EducationResource findById(String id, Audience audience){ return handler.findById(id, audience); } /** * Handles SAX parsing events for media resource xml files * * <media id=""> * <title></title> * <author></author> * <text></concept> * <author></question> * <text></text> * <resource></resource> * <mimetype></mimetype> * <audience></audience> * </media> * * The following fields must be non null: title, author, text | resource, * mimetype, audience * * @author Sana Development Team */ private static class EducationResourceHandler extends DefaultHandler{ public static String TAG = EducationResourceHandler.class.getSimpleName(); private boolean inList, inItem, inID, inTitle, inAuthor, inDescription; private boolean inText, inFileName, inUrl, inMime, inHash, inAudience; private EducationResource current; private Map<String, EducationResource> patientResources; private Map<String, EducationResource> workerResources; private Map<String, EducationResource> errResources; private EducationResourceHandler(){} /** * Returns the list of all available education resources * @return */ public List<EducationResource> infoList(Audience audience){ Log.d(TAG, "Getting list for: " + audience.toString() ); ArrayList<EducationResource> list = new ArrayList<EducationResource>(); switch(audience){ case PATIENT: list.addAll(patientResources.values()); break; case WORKER: list.addAll(workerResources.values()); break; case ALL: list.addAll(workerResources.values()); list.addAll(patientResources.values()); list.addAll(errResources.values()); break; default: break; } Collections.sort(list); return list; } /** * Finds zero or more education resources from available resources * filtered by a list of id's * * @param ids The filter list * @param audience The target audience * @return A list of matching education resources */ public List<EducationResource> infoList(List<String> ids, Audience audience) { List<EducationResource> list = new ArrayList<EducationResource>(); for(String id: ids){ switch(audience){ case PATIENT: if (patientResources.containsKey(id)){ list.add(patientResources.get(id)); } break; case WORKER: if (workerResources.containsKey(id)){ list.add(workerResources.get(id)); } break; case ALL: if (workerResources.containsKey(id)){ list.add(workerResources.get(id)); } if (patientResources.containsKey(id)){ list.add(patientResources.get(id)); } break; } } return list; } /** * Finds a education resource by its id from available resources. * * @param id The id to look up * @return A matching education resource or null */ public EducationResource findById(String id, Audience audience){ switch(audience){ case PATIENT: return patientResources.get(id); case WORKER: return workerResources.get(id); default: EducationResource info = patientResources.get(id); if (info == null) return workerResources.get(id); else return info; } } /** {@inheritDoc} */ @Override public void characters(char ch[], int start, int length) { String chars = new String(ch, start, length); chars = chars.trim(); Log.d(TAG, "Read characters: " + chars ); if(inID){ String scheme = chars.split(":")[0]; current.id = chars.split(":")[1]; try{ current.audience = EducationResource.Audience.valueOf( String.valueOf(scheme).toUpperCase()); } catch(Exception e) { Log.e(TAG, "Error parsing: "+current +", audience: "+chars); current.audience = Audience.ERROR; } } else if (inTitle){ current.name = chars; } else if (inAuthor){ current.author = chars; } else if (inDescription){ current.description = chars; } else if (inText){ current.text = chars; } else if (inFileName){ current.filename = chars; } else if (inUrl){ current.downloadUrl = chars; } else if (inMime){ current.mimeType = chars; } else if (inHash){ current.hash = chars; } else if (inAudience){ try{ current.audience = EducationResource.Audience.valueOf( String.valueOf(chars).toUpperCase()); } catch(Exception e) { Log.e(TAG, "Error parsing: "+current +", audience: "+chars); current.audience = Audience.ERROR; } } } /** {@inheritDoc} */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { Log.d(TAG, "startElement(): " + localName ); if(localName.equals(EducationResource.LIST)) { workerResources = new Hashtable<String,EducationResource>(); patientResources = new Hashtable<String,EducationResource>(); errResources = new Hashtable<String,EducationResource>(); inList = true; }else if (localName.equals(EducationResource.ITEM)){ current = new EducationResource(); inItem = true; } else if (localName.equals(EducationResource.ID)){ inID = true; } else if (localName.equals(EducationResource.TITLE)){ inTitle = true; } else if (localName.equals(EducationResource.AUTHOR)){ inAuthor = true; } else if (localName.equals(EducationResource.DESCRIPTION)){ inDescription = true; } else if (localName.equals(EducationResource.TEXT)){ inText = true; } else if (localName.equals(EducationResource.FILENAME)){ inFileName = true; } else if (localName.equals(EducationResource.DOWNLOAD_URL)){ inUrl = true; } else if (localName.equals(EducationResource.MIMETYPE)){ inMime = true; } else if (localName.equals(EducationResource.HASH)){ inHash = true; } else if (localName.equals(EducationResource.AUDIENCE)){ inAudience = true; } } /** {@inheritDoc} */ @Override public void endElement(String uri, String localName, String qName) throws SAXException { Log.d(TAG, "endElement(): " + localName ); if(localName.equals(EducationResource.LIST)) { inList = false; }else if (localName.equals(EducationResource.ITEM)){ if(!TextUtils.isEmpty(current.filename)){ File f = new File(EducationResource.DEFAULT_MEDIA_ROOT + EducationResource.DEFAULT_MEDIA_PATH + current.filename); if(!f.exists()) current.audience = Audience.ERROR; } switch(current.audience){ case PATIENT: patientResources.put(current.id, current); break; case WORKER: workerResources.put(current.id, current); break; default: errResources.put(current.id, current); break; } current = null; inItem = false; } else if (localName.equals(EducationResource.ID)){ inID = false; } else if (localName.equals(EducationResource.TITLE)){ inTitle = false; } else if (localName.equals(EducationResource.AUTHOR)){ inAuthor = false; } else if (localName.equals(EducationResource.DESCRIPTION)){ inDescription = false; } else if (localName.equals(EducationResource.TEXT)){ inText = false; } else if (localName.equals(EducationResource.FILENAME)){ inFileName = false; } else if (localName.equals(EducationResource.DOWNLOAD_URL)){ inUrl = false; } else if (localName.equals(EducationResource.MIMETYPE)){ inMime = false; } else if (localName.equals(EducationResource.HASH)){ inHash = true; } else if (localName.equals(EducationResource.AUDIENCE)){ inAudience = false; } } } }