# HG changeset patch # User Vladimir Vukicevic # Date 1199246758 28800 # Node ID c8dd955ea9a478a682366a556fa31898eba288ca # Parent 18b8db707b89a08778ea3f8afe040e9da268ccb2 Add better error handling support Rework things so that API and HTTP errors are reported to the user in a visible fashion. diff -r 18b8db707b89a08778ea3f8afe040e9da268ccb2 -r c8dd955ea9a478a682366a556fa31898eba288ca build.xml --- a/build.xml Sat Dec 29 23:56:18 2007 -0800 +++ b/build.xml Tue Jan 01 20:05:58 2008 -0800 @@ -4,8 +4,8 @@ - - + + diff -r 18b8db707b89a08778ea3f8afe040e9da268ccb2 -r c8dd955ea9a478a682366a556fa31898eba288ca src/org/mrrupert/eveberry/DocHandler.java --- a/src/org/mrrupert/eveberry/DocHandler.java Sat Dec 29 23:56:18 2007 -0800 +++ b/src/org/mrrupert/eveberry/DocHandler.java Tue Jan 01 20:05:58 2008 -0800 @@ -3,23 +3,23 @@ import java.util.*; public interface DocHandler { - public void startElement(String tag,Hashtable h) throws Exception; - public void endElement(String tag) throws Exception; - public void startDocument() throws Exception; - public void endDocument() throws Exception; - public void text(String str) throws Exception; + public void startElement(String tag,Hashtable h) throws ParseException; + public void endElement(String tag) throws ParseException; + public void startDocument() throws ParseException; + public void endDocument() throws ParseException; + public void text(String str) throws ParseException; } class DefaultDocHandler implements DocHandler { - public void startElement(String tag,Hashtable h) throws Exception + public void startElement(String tag,Hashtable h) throws ParseException { } - public void endElement(String tag) throws Exception + public void endElement(String tag) throws ParseException { } - public void startDocument() throws Exception + public void startDocument() throws ParseException { } - public void endDocument() throws Exception + public void endDocument() throws ParseException { } - public void text(String str) throws Exception + public void text(String str) throws ParseException { } } diff -r 18b8db707b89a08778ea3f8afe040e9da268ccb2 -r c8dd955ea9a478a682366a556fa31898eba288ca src/org/mrrupert/eveberry/EveAPI.java --- a/src/org/mrrupert/eveberry/EveAPI.java Sat Dec 29 23:56:18 2007 -0800 +++ b/src/org/mrrupert/eveberry/EveAPI.java Tue Jan 01 20:05:58 2008 -0800 @@ -34,7 +34,18 @@ //import java.text.*; +class EveAPIError extends Exception { + public String ErrorString; + public int ErrorCode; + + public EveAPIError(String str, int code) { + ErrorString = str; + ErrorCode = code; + } +} + public class EveAPI { + //static String kAPIPrefix = "http://api.eve-online.com"; static String sAPIPrefix = "http://vlad.off.net/eve/eproxy.php"; static String sURLSuffix = ";deviceside=true"; @@ -49,13 +60,13 @@ static String kDataServiceURL = "http://vlad.off.net/eve/eveDataService.php"; static void DoAPICall(String api, byte[] postBytes, DocHandler handler) - throws IOException, Exception + throws IOException, EveAPIError { DoXMLPOSTCall(sAPIPrefix + api, postBytes, handler); } static void DoXMLPOSTCall(String url, byte[] postBytes, DocHandler handler) - throws IOException, Exception + throws IOException, EveAPIError { HttpConnection http = null; OutputStream os = null; @@ -74,7 +85,7 @@ int rc = http.getResponseCode(); if (rc != HttpConnection.HTTP_OK) { - throw new Exception("HTTP failure"); + throw new EveAPIError("HTTP failure: " + rc + " -- " + http.getResponseMessage(), -2); } InputStream is; @@ -85,85 +96,113 @@ is = http.openInputStream(); } - QDParser sax = new QDParser(); - sax.parse(handler, new InputStreamReader(is)); + try { + QDParser sax = new QDParser(); + sax.parse(handler, new InputStreamReader(is)); + } catch (ParseException pex) { + throw new EveAPIError("Parse exception: " + pex, -3); + } http.close(); } - public static EveCharacterList GetCharacters(String userid, String key) { + public static EveCharacterList GetCharacters(String userid, String key) + throws EveAPIError + { EveCharacterList retval = null; try { retval = new EveCharacterList(); - DocHandler handler = new CharactersXMLHandler(retval); + GenericEveAPIHandler handler = new CharactersXMLHandler(retval); DoAPICall(kCharactersXMLURL, ("userID=" + userid + "&apiKey=" + key).getBytes(), handler); - } catch (Exception ex) { - EveBerry.debug("Exception caught! " + ex); - retval = null; + + if (handler.mErrorCode != 0) { + EveBerry.debug("handler in error, throwing EveAPIError"); + throw new EveAPIError(handler.mErrorString, handler.mErrorCode); + } + } catch (IOException ex) { + EveBerry.debug("IO Exception caught! " + ex); + throw new EveAPIError("IO Exception: " + ex, -1); } return retval; } - public static EveCharacterSheet GetCharacterSheet(String userid, String key, long charid) { + public static EveCharacterSheet GetCharacterSheet(String userid, String key, long charid) + throws EveAPIError + { EveCharacterSheet retval = null; try { retval = new EveCharacterSheet(); - DocHandler handler = new CharacterSheetXMLHandler(retval); + GenericEveAPIHandler handler = new CharacterSheetXMLHandler(retval); DoAPICall(kCharacterSheetXMLURL, ("userID=" + userid + "&apiKey=" + key + "&characterID=" + charid).getBytes(), handler); - } catch (Exception ex) { + + if (handler.mErrorCode != 0) + throw new EveAPIError(handler.mErrorString, handler.mErrorCode); + } catch (IOException ex) { EveBerry.debug("Exception caught! " + ex); - retval = null; + throw new EveAPIError("IO Exception: " + ex, -1); } return retval; } - public static EveSkillInTraining GetSkillInTraining(String userid, String key, long charid) { + public static EveSkillInTraining GetSkillInTraining(String userid, String key, long charid) + throws EveAPIError + { EveSkillInTraining retval = null; try { retval = new EveSkillInTraining(); - DocHandler handler = new SkillInTrainingXMLHandler(retval); + GenericEveAPIHandler handler = new SkillInTrainingXMLHandler(retval); DoAPICall(kSkillInTrainingXMLURL, ("userID=" + userid + "&apiKey=" + key + "&characterID=" + charid).getBytes(), handler); - } catch (Exception ex) { + + if (handler.mErrorCode != 0) + throw new EveAPIError(handler.mErrorString, handler.mErrorCode); + } catch (IOException ex) { EveBerry.debug("Exception caught! " + ex); - retval = null; + throw new EveAPIError("IO Exception: " + ex, -1); } return retval; } - public static Vector GetCharacterMarketOrders(String userid, String key, long charid) { + public static Vector GetCharacterMarketOrders(String userid, String key, long charid) + throws EveAPIError + { Vector retval = null; try { retval = new Vector(); - DocHandler handler = new MarketOrdersXMLHandler(retval); + GenericEveAPIHandler handler = new MarketOrdersXMLHandler(retval); DoAPICall(kMarketOrdersXMLURL, ("userID=" + userid + "&apiKey=" + key + "&characterID=" + charid).getBytes(), handler); - } catch (Exception ex) { + + if (handler.mErrorCode != 0) + throw new EveAPIError(handler.mErrorString, handler.mErrorCode); + } catch (IOException ex) { EveBerry.debug("Exception caught! " + ex); - retval = null; + throw new EveAPIError("IO Exception: " + ex, -1); } return retval; } - public static Vector DataServiceIdLookup(String op, Vector ids) { + public static Vector DataServiceIdLookup(String op, Vector ids) + throws EveAPIError + { Vector retval = null; try { @@ -184,7 +223,7 @@ DoXMLPOSTCall(kDataServiceURL, sb.toString().getBytes(), handler); } catch (Exception ex) { EveBerry.debug("Exception caught! " + ex); - retval = null; + throw new EveAPIError("IO Exception: " + ex, -1); } return retval; @@ -215,12 +254,12 @@ static class GenericEveAPIHandler extends DefaultDocHandler { boolean mInCachedUntil; - String mCachedUntilText; - long mCachedUntil; + public String mCachedUntilText; + public long mCachedUntil; boolean mInError; - int mErrorCode; - String mErrorString; + public int mErrorCode; + public String mErrorString; GenericEveAPIHandler() { mInCachedUntil = false; @@ -268,7 +307,7 @@ } boolean GenericStartElement(String tag, Hashtable attributes) - throws Exception + throws ParseException { if (tag.equalsIgnoreCase("cachedUntil")) { mInCachedUntil = true; @@ -279,6 +318,8 @@ if (tag.equalsIgnoreCase("error")) { mInError = true; mErrorCode = Integer.parseInt((String) attributes.get("code")); + + EveBerry.debug("API call in error: " + mErrorCode); return true; } @@ -315,14 +356,12 @@ } public void GenericEndDocument() - throws Exception + throws ParseException { - if (mErrorCode != 0) - throw new Exception(mErrorString); } public void GenericEndDocument(EveCacheableItem eci) - throws Exception + throws ParseException { GenericEndDocument(); @@ -330,25 +369,25 @@ } public void startElement(String tag, Hashtable attributes) - throws Exception + throws ParseException { GenericStartElement(tag, attributes); } public void endElement(String tag) - throws Exception + throws ParseException { GenericEndElement(tag); } public void text(String str) - throws Exception + throws ParseException { GenericText(str); } public void endDocument() - throws Exception + throws ParseException { GenericEndDocument(); } @@ -377,7 +416,7 @@ } public void startElement(String tag, Hashtable attributes) - throws Exception + throws ParseException { if (GenericStartElement(tag, attributes)) return; @@ -392,7 +431,7 @@ } public void endDocument() - throws Exception + throws ParseException { GenericEndDocument(mList); @@ -433,7 +472,7 @@ } public void startElement(String tag, Hashtable attributes) - throws Exception + throws ParseException { if (GenericStartElement(tag, attributes)) return; @@ -470,7 +509,7 @@ } public void text(String str) - throws Exception + throws ParseException { if (GenericText(str)) return; @@ -480,7 +519,7 @@ } public void endElement(String tag) - throws Exception + throws ParseException { if (GenericEndElement(tag)) return; @@ -553,7 +592,7 @@ } public void startElement(String tag, Hashtable attributes) - throws Exception + throws ParseException { if (GenericStartElement(tag, attributes)) return; @@ -593,7 +632,7 @@ } public void endElement(String tag) - throws Exception + throws ParseException { if (GenericEndElement(tag)) return; @@ -629,7 +668,7 @@ } public void startElement(String tag, Hashtable attributes) - throws Exception + throws ParseException { if (GenericStartElement(tag, attributes)) return; @@ -644,7 +683,7 @@ } public void text(String str) - throws Exception + throws ParseException { if (GenericText(str)) return; @@ -654,7 +693,7 @@ } public void endElement(String tag) - throws Exception + throws ParseException { if (GenericEndElement(tag)) return; @@ -701,7 +740,7 @@ } public void startElement(String tag, Hashtable attributes) - throws Exception + throws ParseException { if (tag.equalsIgnoreCase("typenames") || tag.equalsIgnoreCase("itemnames")) { mInNameList = true; @@ -715,7 +754,7 @@ } public void endElement(String tag) - throws Exception + throws ParseException { if (tag.equalsIgnoreCase("typenames") || tag.equalsIgnoreCase("itemnames")) mInNameList = false; diff -r 18b8db707b89a08778ea3f8afe040e9da268ccb2 -r c8dd955ea9a478a682366a556fa31898eba288ca src/org/mrrupert/eveberry/EveBerryBackground.java --- a/src/org/mrrupert/eveberry/EveBerryBackground.java Sat Dec 29 23:56:18 2007 -0800 +++ b/src/org/mrrupert/eveberry/EveBerryBackground.java Tue Jan 01 20:05:58 2008 -0800 @@ -44,6 +44,7 @@ interface EveBerryBackgroundActionListener { public void onActionComplete(Object result, Object token); + public void onError(EveAPIError error, Object token); } class EveBerryBackground implements Runnable { @@ -233,6 +234,7 @@ do { WorkItem item = null; + Object actionResult = null; synchronized(this) { if (mWorkQueue.size() > 0) { @@ -244,60 +246,66 @@ if (item != null) { EveBerry.debug("Processing work item of type " + item.WorkType); - final WorkItem wi = item; - if (wi.WorkType == ITEM_CHARACTER_UPDATE) { - final EveCharacterInfo eci = (EveCharacterInfo) wi.Item; + final WorkItem wi = item; - eci.UpdateInProgress = true; - UpdateCharacterInfo(eci); - mgr.getBitmapPortraitForCharacter(eci.ID); - eci.UpdateInProgress = false; + // wrap with try/catch to get API Errors + try { + if (wi.WorkType == ITEM_CHARACTER_UPDATE) { + final EveCharacterInfo eci = (EveCharacterInfo) wi.Item; - EveBerry.sApp.invokeLater(new Runnable() { - public void run() { - EveCharacterManager.Manager().characterUpdated(eci); + eci.UpdateInProgress = true; + UpdateCharacterInfo(eci); + mgr.getBitmapPortraitForCharacter(eci.ID); + eci.UpdateInProgress = false; - // this is kind of stupid, since we force a characterUpdated bit above, but meh. - if (wi.Listener != null) - wi.Listener.onActionComplete(eci, wi.Closure); - }}); - } else if (wi.WorkType == ITEM_CHARACTER_LIST_REQUEST) { - String [] auth = (String []) wi.Item; + actionResult = eci; - final EveCharacterList ecl = EveAPI.GetCharacters(auth[0], auth[1]); + EveBerry.sApp.invokeLater(new Runnable() { + public void run() { + EveCharacterManager.Manager().characterUpdated(eci); + }}); + } else if (wi.WorkType == ITEM_CHARACTER_LIST_REQUEST) { + String [] auth = (String []) wi.Item; - if (wi.Listener != null) { - EveBerry.sApp.invokeLater(new Runnable() { - public void run() { - wi.Listener.onActionComplete(ecl, wi.Closure); - }}); - } - } else if (wi.WorkType == ITEM_CHARACTER_MARKET_ORDERS_REQUEST) { - EveCharacterInfo eci = (EveCharacterInfo) wi.Item; + actionResult = EveAPI.GetCharacters(auth[0], auth[1]); + } else if (wi.WorkType == ITEM_CHARACTER_MARKET_ORDERS_REQUEST) { + EveCharacterInfo eci = (EveCharacterInfo) wi.Item; - final Vector orders = EveAPI.GetCharacterMarketOrders(eci.UserID, eci.UserKey, eci.ID); + actionResult = EveAPI.GetCharacterMarketOrders(eci.UserID, eci.UserKey, eci.ID); + } else if (wi.WorkType == ITEM_DATA_SERVICE_ID_NAME_LOOKUP) { + Vector args = (Vector) wi.Item; + + String op = (String) args.elementAt(0); + Vector ids = (Vector) args.elementAt(1); + + actionResult = EveAPI.DataServiceIdLookup(op, ids); + } if (wi.Listener != null) { + final Object res = actionResult; EveBerry.sApp.invokeLater(new Runnable() { - public void run() { - wi.Listener.onActionComplete(orders, wi.Closure); - }}); + public void run() { + wi.Listener.onActionComplete(res, wi.Closure); + }}); } - } else if (wi.WorkType == ITEM_DATA_SERVICE_ID_NAME_LOOKUP) { - Vector args = (Vector) wi.Item; + } catch (EveAPIError err) { + final EveAPIError ferr = err; - String op = (String) args.elementAt(0); - Vector ids = (Vector) args.elementAt(1); - - final Vector result = EveAPI.DataServiceIdLookup(op, ids); - + // report the error to the listener if (wi.Listener != null) { EveBerry.sApp.invokeLater(new Runnable() { + public void run() { + wi.Listener.onError(ferr, wi.Closure); + }}); + } + + // and also display notification to the user + EveBerry.sApp.invokeLater(new Runnable() { public void run() { - wi.Listener.onActionComplete(result, wi.Closure); + Dialog.alert("Eve API failure (" + ferr.ErrorCode + "): " + ferr.ErrorString); }}); - } } + } synchronized(this) { diff -r 18b8db707b89a08778ea3f8afe040e9da268ccb2 -r c8dd955ea9a478a682366a556fa31898eba288ca src/org/mrrupert/eveberry/EveBerryMarketOrdersScreen.java --- a/src/org/mrrupert/eveberry/EveBerryMarketOrdersScreen.java Sat Dec 29 23:56:18 2007 -0800 +++ b/src/org/mrrupert/eveberry/EveBerryMarketOrdersScreen.java Tue Jan 01 20:05:58 2008 -0800 @@ -91,6 +91,13 @@ screen.setOrders(orders); } + + public void onError(EveAPIError error, Object token) { + EveBerryMarketOrdersScreen screen = (EveBerryMarketOrdersScreen) token; + screen.deleteAll(); + screen.add(new LabelField("Error while retrieving orders:", LabelField.USE_ALL_WIDTH)); + screen.add(new LabelField(error.ErrorString, LabelField.USE_ALL_WIDTH)); + } }; EveBerryBackground.GetBackgroundRunnable().requestCharacterMarketOrders(mChar, listener, this); diff -r 18b8db707b89a08778ea3f8afe040e9da268ccb2 -r c8dd955ea9a478a682366a556fa31898eba288ca src/org/mrrupert/eveberry/EveDatabase.java --- a/src/org/mrrupert/eveberry/EveDatabase.java Sat Dec 29 23:56:18 2007 -0800 +++ b/src/org/mrrupert/eveberry/EveDatabase.java Tue Jan 01 20:05:58 2008 -0800 @@ -194,4 +194,8 @@ } } } + + public void onError(EveAPIError err, Object token) { + // nothing we can do + } } diff -r 18b8db707b89a08778ea3f8afe040e9da268ccb2 -r c8dd955ea9a478a682366a556fa31898eba288ca src/org/mrrupert/eveberry/EveEditCharacterScreen.java --- a/src/org/mrrupert/eveberry/EveEditCharacterScreen.java Sat Dec 29 23:56:18 2007 -0800 +++ b/src/org/mrrupert/eveberry/EveEditCharacterScreen.java Tue Jan 01 20:05:58 2008 -0800 @@ -39,12 +39,12 @@ BasicEditField mUserIDField; BasicEditField mUserKeyField; - ObjectChoiceField mChoiceField; - EveCharacterList mCharList; LabelField mLoginStatusField; + CheckboxField mCharsFields[]; + public EveEditCharacterScreen() { super(DEFAULT_MENU | DEFAULT_CLOSE); @@ -67,108 +67,89 @@ final EveEditCharacterScreen self = this; - LabelField fetchCharacters = new RunnableLabelField("Fetch Characters...", Field.FOCUSABLE) { - public void run() { + ButtonField fetchButton = new ButtonField("Fetch Characters..."); + fetchButton.setChangeListener(new FieldChangeListener() { + public void fieldChanged(Field field, int context) { EveBerryBackgroundActionListener bal = new EveBerryBackgroundActionListener() { public void onActionComplete(Object result, Object token) { EveCharacterList ecl = (EveCharacterList) result; - EveEditCharacterScreen ecs = (EveEditCharacterScreen) token; + self.onCharactersAvailable(ecl); + } - synchronized (Application.getEventLock()) { - if (ecl == null) { - ecs.mLoginStatusField.setText("Error logging in! (Check uid/key!)"); - mChoiceField.setChoices(null); - } else { - ecs.mLoginStatusField.setText("Login success!"); - mChoiceField.setChoices(ecl.CharacterNames); - mChoiceField.setDirty(true); + public void onError(EveAPIError err, Object token) { + self.mLoginStatusField.setText("Error: " + err.ErrorString); + } + }; - mCharList = ecl; - } - } - } - }; mLoginStatusField.setText("Retrieving characters..."); EveBerryBackground.GetBackgroundRunnable().requestCharacterList(mUserIDField.getText(), mUserKeyField.getText(), bal, - self); - } - }; + null); + }}); - add(fetchCharacters); + add(fetchButton); - mLoginStatusField = new LabelField("", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH | LabelField.NON_FOCUSABLE); + mLoginStatusField = new LabelField("Enter your User ID and API Key, then press Fetch Characters.", + LabelField.USE_ALL_WIDTH | LabelField.NON_FOCUSABLE); add(mLoginStatusField); - - add(new SeparatorField()); - - mChoiceField = new ObjectChoiceField("Choose Character", null); - - add(mChoiceField); } - public void save() throws IOException { - // ok, we're being asked to save + void onCharactersAvailable(EveCharacterList ecl) { + mCharList = ecl; - EveBerry.debug("We're in save()"); + if (mCharsFields != null) { + for (int i = 0; i < mCharsFields.length; i++) { + delete(mCharsFields[i]); + } - // ignore, XXX do something - if (mCharList == null) - return; + mCharsFields = null; + } - int idx = mChoiceField.getSelectedIndex(); - if (idx == -1) - return; + if (ecl == null) { + mLoginStatusField.setText("Error logging in! (Check uid/key!)"); + return; + } - EveBerry.debug("Calling addCharacter: " + mUserIDField.getText() + " " + mUserKeyField.getText() + " " + mCharList.CharacterNames[idx] + " " + mCharList.CharacterIDs[idx]); + mLoginStatusField.setText("Select characters to monitor:"); - EveCharacterManager.Manager().addCharacter(mUserIDField.getText(), - mUserKeyField.getText(), - mCharList.CharacterNames[idx], - mCharList.CharacterIDs[idx]); + mCharsFields = new CheckboxField[ecl.CharacterNames.length]; + for (int i = 0; i < mCharsFields.length; i++) { + boolean exists = EveCharacterManager.Manager().getCharacter(ecl.CharacterIDs[i]) != null; + mCharsFields[i] = new CheckboxField(ecl.CharacterNames[i], exists); + add(mCharsFields[i]); + } } - static class RunnableLabelField extends LabelField implements Runnable { - RunnableLabelField() { - super(); - } + public boolean onClose() { + EveBerry.debug("In Screen.onClose!"); - RunnableLabelField(Object s) { - super(s); - } + // did we even load anything? + if (mCharList == null || mCharsFields == null) { + close(); + return true; + } - RunnableLabelField(Object s, int offset, int len, long style) { - super(s, offset, len, style); - } + // make any changes necessary + for (int i = 0; i < mCharsFields.length; i++) { + long id = mCharList.CharacterIDs[i]; + boolean add = mCharsFields[i].getChecked(); + boolean exists = EveCharacterManager.Manager().getCharacter(id) != null; - RunnableLabelField(Object s, long style) { - super(s, style); - } + if (add && !exists) { + EveCharacterManager.Manager().addCharacter(mUserIDField.getText(), + mUserKeyField.getText(), + mCharList.CharacterNames[i], + id); + } else if (!add && exists) { + EveCharacterManager.Manager().deleteCharacter(id); + } + } - protected boolean navigationClick(int status, int time) { - run(); - return true; - } - - public boolean keyChar(char key, int status, int time) { - boolean retval = false; - - switch (key) { - case Characters.ENTER: - run(); - retval = true; - break; - } - - return retval; - } - - public void run () { - // nothing by default - } + close(); + return true; } } diff -r 18b8db707b89a08778ea3f8afe040e9da268ccb2 -r c8dd955ea9a478a682366a556fa31898eba288ca src/org/mrrupert/eveberry/QDParser.java --- a/src/org/mrrupert/eveberry/QDParser.java Sat Dec 29 23:56:18 2007 -0800 +++ b/src/org/mrrupert/eveberry/QDParser.java Tue Jan 01 20:05:58 2008 -0800 @@ -10,6 +10,12 @@ // Based on java tip at http://www.javaworld.com/javatips/jw-javatip128_p.html // because RIM's SAX parser seems ludicrously slow +class ParseException extends Exception { + public ParseException(String s) { + super(s); + } +} + public class QDParser { private static int popMode(Stack st) { if(!st.empty()) @@ -34,7 +40,7 @@ DOCTYPE = 14, PRE = 15, CDATA = 16; - public static void parse(DocHandler doc,Reader r) throws Exception { + public static void parse(DocHandler doc,Reader r) throws IOException, ParseException { Stack st = new Stack(); int depth = 0; int mode = PRE; @@ -314,8 +320,8 @@ exc("missing end tag",line,col); } private static void exc(String s,int line,int col) - throws Exception + throws ParseException { - throw new Exception(s+" near line "+line+", column "+col); + throw new ParseException(s+" near line "+line+", column "+col); } }