Android Open Source - android-api Catch Notes Xml Parser






From Project

Back to project page android-api.

License

The source code is released under:

Apache License

If you think the Android project android-api listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

//
//  Copyright 2011 Catch.com, Inc.
//  //ww  w  .ja va  2 s .co m
//  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 com.catchnotes.api;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.TimeZone;

import org.apache.http.HttpResponse;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import android.os.Build;
import android.text.format.Time;
import android.util.Log;
import android.util.TimeFormatException;

public class CatchNotesXmlParser {
  public static final long ERROR_RESPONSE_NULL = -1;
  public static final long ERROR_PARAMETERS_NULL = -2;

  private static final String XML_TAG_NOTES = "notes";
  private static final String XML_TAG_NOTE = "note";
  private static final String XML_TAG_CREATED = "created_at";
  private static final String XML_TAG_MODIFIED = "modified_at";
  private static final String XML_TAG_REMINDER = "reminder_at";
    private static final String XML_TAG_SERVER_MODIFIED = "server_modified_at";
  private static final String XML_TAG_ID = "id";
  private static final String XML_TAG_SOURCE = "source";
  private static final String XML_TAG_SOURCE_URL = "source_url";
  private static final String XML_TAG_TEXT = "text";
  private static final String XML_TAG_SUMMARY = "summary";
  private static final String XML_TAG_USER = "user";
  private static final String XML_TAG_USER_NAME = "user_name";
    private static final String XML_TAG_COMMENTS = "comments";
    private static final String XML_TAG_COMMENT = "comment";
  private static final String XML_TAG_MODE = "mode";
  private static final String XML_TAG_BROWSER_URL = "browser_url";
  private static final String XML_TAG_TAGS = "tags";
  private static final String XML_TAG_TAG = "tag";
  private static final String XML_TAG_MEDIA_LIST = "media_list";
  private static final String XML_TAG_MEDIA = "media";
  private static final String XML_TAG_CONTENT_TYPE = "type";
  private static final String XML_TAG_SRC = "src";
  private static final String XML_TAG_SIZE = "size";
  private static final String XML_TAG_FILENAME = "filename";
  private static final String XML_TAG_VOICE_HINT = "voicenote_hint";
  private static final String XML_TAG_LOCATION = "location";
  private static final String XML_TAG_LATITUDE = "latitude";
  private static final String XML_TAG_LONGITUDE = "longitude";
  private static final String XML_TAG_ALTITUDE = "altitude";
  private static final String XML_TAG_SPEED = "speed";
  private static final String XML_TAG_BEARING = "bearing";
  private static final String XML_TAG_ACCURACY_POSITION = "accuracy_position";
  private static final String XML_TAG_ACCURACY_ALTITUDE = "accuracy_altitude";

  // Enable this for extra API call tracing output in the logcat.
  private static final boolean PARSE_TRACING_OUTPUT_ENABLED = false;
  private static final String LOGCAT_NAME = "CatchParser";
    public static final String CATCH_NAMESPACE_PREFIX = "catch";

    private Time timestamper;
  private SimpleDateFormat rfc3339;

  public CatchNotesXmlParser() {    
    try {
      if (Integer.parseInt(Build.VERSION.SDK) >= Build.VERSION_CODES.ECLAIR_0_1) {
        // We can use Time & TimeFormatException on Android 2.0.1
        // (API level 6) or greater. It crashes the VM otherwise.
        timestamper = new Time();
      }
    } catch (Exception e) { }
  }

  public void parseSyncV2XML(HttpResponse response, List<CatchNoteRef> noteRefs)
    throws XmlPullParserException, IOException, IllegalArgumentException {
    if (response == null || noteRefs == null) {
      throw new IllegalArgumentException();
    }

    XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
    XmlPullParser parser = factory.newPullParser();
    parser.setInput(response.getEntity().getContent(), null);

    int eventType = parser.getEventType();

    String startTag;
    String endTag;
    String nextText = "";

    while (eventType != XmlPullParser.END_DOCUMENT) {
      if (eventType == XmlPullParser.START_DOCUMENT) {
        parse_trace("Beginning XML pullparse.");
      } else if (eventType == XmlPullParser.START_TAG) {
        startTag = parser.getName();

        if (XML_TAG_NOTES.equals(startTag)) {
          parse_trace("Parsing noteRefs.");
        } else if (XML_TAG_NOTE.equals(startTag)) {
          parse_trace("Parsing a note.");
          CatchNoteRef noteRef = new CatchNoteRef();

          while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG) {
              startTag = parser.getName();
              
              // one-liners:
              if (XML_TAG_ID.equals(startTag)) {
                nextText = parser.nextText();
                noteRef.nodeId = nextText;
                parse_trace("Note ID is " + noteRef.nodeId);
              } else if (XML_TAG_SERVER_MODIFIED.equals(startTag)) {
                nextText = parser.nextText();
                noteRef.serverModified = nextText;
                parse_trace("Server modification time is " + noteRef.serverModified);
              }
            } else if (eventType == XmlPullParser.END_TAG) {
              endTag = parser.getName();
              
              if (XML_TAG_NOTE.equals(endTag)) {
                parse_trace("Parsing noteRef complete.");
                break;
              }
            }

            eventType = parser.next();
          }
          
          noteRefs.add(noteRef);
        } else  {
          parse_trace("(parseSyncV2XML) unknown XML tag: <" + startTag + ">");
        }
      } else if (eventType == XmlPullParser.END_TAG) {
        endTag = parser.getName();

        if (XML_TAG_NOTES.equals(endTag)) {
          parse_trace("Parsed " + noteRefs.size() + " noteRefs.");
        }
      }
      
      eventType = parser.next();
    }
  }

    public void parseNotesXml(HttpResponse response,
      ArrayList<CatchNote> notes, long parentId)
  throws XmlPullParserException, IOException, IllegalArgumentException {    
    if (response == null || notes == null) {
      throw new IllegalArgumentException();
    }
    
    XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
    factory.setNamespaceAware(true);
    XmlPullParser parser = factory.newPullParser();
    parser.setInput(response.getEntity().getContent(), null);

    int eventType = parser.getEventType();

    while (eventType != XmlPullParser.END_DOCUMENT) {
      if (eventType == XmlPullParser.START_DOCUMENT) {
        parse_trace("Beginning XML pullparse.");
      } else if (eventType == XmlPullParser.START_TAG) {
        String startTag = parser.getName();

        if (XML_TAG_NOTES.equals(startTag)) {
          parse_trace("Parsing notes.");
        } else if (XML_TAG_NOTE.equals(startTag)) {
          parse_trace("Parsing a note.");
          parseNote(parser, notes, parentId);
        } else {
          parse_trace("(parseNotesXml) unknown XML tag: <" + startTag + ">");
        }
      } else if (eventType == XmlPullParser.END_TAG) {
        String endTag = parser.getName();

        if (XML_TAG_NOTES.equals(endTag)) {
          parse_trace("Parsed " + notes.size() + " notes.");
        }
      }

      eventType = parser.next();
    }
  }
  
  private void parseNote(XmlPullParser parser,
      ArrayList<CatchNote> returnVal, long parentId)
  throws XmlPullParserException, IOException {
    // Create a blank note object
    CatchNote note = new CatchNote();
    returnVal.add(note);
    note.parentId = parentId;
    int eventType = parser.next();

    while (eventType != XmlPullParser.END_DOCUMENT) {
      if (eventType == XmlPullParser.START_TAG) {
        String startTag = parser.getName();
        String nextText = "";

                if (parser.getNamespace().equals(XmlPullParser.NO_NAMESPACE)) { // default properties
                    // one-liners:
                    if (XML_TAG_ID.equals(startTag)) {
                        nextText = parser.nextText();
                        note.id = nextText;
                        parse_trace("Note ID is " + note.id);
                    } else if (XML_TAG_SOURCE.equals(startTag)) {
                        nextText = parser.nextText();
                        note.source = nextText;
                        parse_trace("Note source is " + note.source);
                    } else if (XML_TAG_SOURCE_URL.equals(startTag)) {
                        nextText = parser.nextText();
                        note.sourceUrl = nextText;
                        parse_trace("Note source URL is " + note.sourceUrl);
                    } else if (XML_TAG_CREATED.equals(startTag)) {
                        nextText = parser.nextText();
                        note.creationTime = parse3339(nextText);
                        parse_trace("Creation time is " + nextText + " (" +
                                note.creationTime + ')');
                    } else if (XML_TAG_MODIFIED.equals(startTag)) {
                        nextText = parser.nextText();
                        note.modificationTime = parse3339(nextText);
                        parse_trace("Modification time is " + nextText +
                                " (" + note.modificationTime + ')');
                    } else if (XML_TAG_REMINDER.equals(startTag)) {
                        nextText = parser.nextText();
                        note.reminderTime = parse3339(nextText);
                        parse_trace("Reminder time is " + nextText + " (" +
                                note.reminderTime + ')');
                    } else if (XML_TAG_SERVER_MODIFIED.equals(startTag)) {
                        nextText = parser.nextText();
                        note.serverModifiedAt= parse3339(nextText);
                        parse_trace("ServerModifiedAt time is " + nextText + " (" +
                                note.serverModifiedAt + ')');
                    } else if (XML_TAG_TEXT.equals(startTag)) {
                        nextText = parser.nextText();
                        note.text = nextText;
                        parse_trace("Note text is \"" + note.text + '"');
                    } else if (XML_TAG_SUMMARY.equals(startTag)) {
                        nextText = parser.nextText();
                        note.summary = nextText;
                        parse_trace("Note summary is \"" + note.summary + '"');
                    } else if (XML_TAG_COMMENTS.equals(startTag)) {
                        note.children = 0;

                        while (eventType != XmlPullParser.END_DOCUMENT) {
                            if (eventType == XmlPullParser.START_TAG) {
                                startTag = parser.getName();

                                if (XML_TAG_COMMENT.equals(startTag)) {
                                    note.children++;
                                    parse_trace("found comment");
                                }
                            } else if (eventType == XmlPullParser.END_TAG) {
                                String endTag = parser.getName();

                                if (XML_TAG_COMMENTS.equals(endTag)) {
                                    parse_trace("Parsing comments complete.");
                                    break;
                                }
                            }

                            eventType = parser.next();
                        }

                        parse_trace("Comment count is " + note.children);
                    }  else if (XML_TAG_MODE.equals(startTag)) {
                        nextText = parser.nextText();
                        note.mode = nextText;
                        parse_trace("Mode is " + note.mode);
                    } else if (XML_TAG_BROWSER_URL.equals(startTag)) {
                        nextText = parser.nextText();
                        note.browserUrl = nextText;
                        parse_trace("Browser URL is " + note.browserUrl);
                    }
                    // new blocks:
                    else if (XML_TAG_USER.equals(startTag)) {
                        parse_trace("Parsing note owner data.");
                        parseNoteOwner(parser, note);
                    } else if (XML_TAG_TAGS.equals(startTag)) {
                        parse_trace("Parsing note tags.");
                        parseTags(parser, note);
                    } else if (XML_TAG_LOCATION.equals(startTag)) {
                        parse_trace("Parsing geotag.");
                        parseLocation(parser, note);
                    } else if (XML_TAG_MEDIA_LIST.equals(startTag)) {
                        parse_trace("Parsing media list.");
                        parseMediaList(parser, note);
                    } else {
                        parse_trace("(parseNote) unknown XML tag: <" + startTag + ">");
                    }
                } else if (parser.getPrefix().equals(CATCH_NAMESPACE_PREFIX)) { // XXXaes. use full path once we fix server side uris
                    parse_trace("Parsing annotation.");
                    if (note.annotations == null) {
                        note.annotations = new HashMap<String, String>();
                    }
                    note.annotations.put(startTag, parser.nextText());
                }
      } else if (eventType == XmlPullParser.END_TAG) {
        String endTag = parser.getName();

        if (XML_TAG_NOTE.equals(endTag)) {
          parse_trace("Parsing note complete.");
          break;
        }
      }

      eventType = parser.next();
    }
  }

  private void parseTags(XmlPullParser parser, CatchNote note)
  throws XmlPullParserException, IOException {
    ArrayList<CharSequence> tags = new ArrayList<CharSequence>();
    int eventType = parser.next();

    while (eventType != XmlPullParser.END_DOCUMENT) {
      if (eventType == XmlPullParser.START_TAG) {
        String startTag = parser.getName();

        if (XML_TAG_TAG.equals(startTag)) {
          String tag = parser.nextText();
          tags.add(tag);
          parse_trace("Added tag \"" + tag + '"');
        } else {
          parse_trace("(parseTags) unknown XML tag: <" + startTag + ">");
        }
      } else if (eventType == XmlPullParser.END_TAG) {
        String endTag = parser.getName();

        if (XML_TAG_TAGS.equals(endTag)) {
          note.tags = tags;
          parse_trace("Note had " + note.tags.size()
              + " tag(s).");
          break;
        }
      }

      eventType = parser.next();
    }
  }

  private void parseMediaList(XmlPullParser parser, CatchNote note)
  throws XmlPullParserException, IOException {
    int eventType = parser.next();

    while (eventType != XmlPullParser.END_DOCUMENT) {
      if (eventType == XmlPullParser.START_TAG) {
        String startTag = parser.getName();

        if (XML_TAG_MEDIA.equals(startTag)) {
          parse_trace("Parsing a media item.");
          parseMedia(parser, note);
        } else {
          parse_trace("(parseMediaList) unknown XML tag: <" + startTag + ">");
        }
      } else if (eventType == XmlPullParser.END_TAG) {
        String endTag = parser.getName();

        if (XML_TAG_MEDIA_LIST.equals(endTag)) {
          parse_trace("Parsing media list complete.");
          break;
        }
      }

      eventType = parser.next();
    }
  }

  private void parseMedia(XmlPullParser parser, CatchNote note)
  throws XmlPullParserException, IOException {
    CatchMedia media = new CatchMedia();
    media.note_id = note.id;
    int eventType = parser.next();

    while (eventType != XmlPullParser.END_DOCUMENT) {
      if (eventType == XmlPullParser.START_TAG) {
        String startTag = parser.getName();
        String nextText = "";

        if (XML_TAG_SRC.equals(startTag)) {
          nextText = parser.nextText();
          media.src = nextText;
          parse_trace("Source = " + media.src);
        } else if (XML_TAG_ID.equals(startTag)) {
          nextText = parser.nextText();
          media.id = nextText;
          parse_trace("API ID = " + media.id);
        } else if (XML_TAG_CREATED.equals(startTag)) {
          nextText = parser.nextText();
          media.created_at = parse3339(nextText);
          parse_trace("Creation time = " + nextText + " (" + media.created_at + ')');
        } else if (XML_TAG_CONTENT_TYPE.equals(startTag)) {
          nextText = parser.nextText();
          media.content_type = nextText;
          parse_trace("Type = " + media.content_type);
        } else if (XML_TAG_SIZE.equals(startTag)) {
          try {
            nextText = parser.nextText();
            long size = Long.parseLong(nextText);
            media.size = size;
          } catch (NumberFormatException nfe) {
            Log.e(LOGCAT_NAME, "unable to parse value for media size: \"" + nextText + '"');
            media.size = 0;
          }
          
          parse_trace("Size = " + media.size);
        } else if (XML_TAG_VOICE_HINT.equals(startTag)) {
          nextText = parser.nextText();
          media.voice_hint = Boolean.parseBoolean(nextText);
          parse_trace("voice hint = " + media.voice_hint);
        } else if (XML_TAG_FILENAME.equals(startTag)) {
          nextText = parser.nextText();
          media.filename = nextText;
          parse_trace("Filename = " + media.filename);
        } else {
          parse_trace("(parseMedia) unknown XML tag: <" + startTag + ">");
        }
      } else if (eventType == XmlPullParser.END_TAG) {
        String endTag = parser.getName();

        if (XML_TAG_MEDIA.equals(endTag)) {
          if (note.mediaList == null) {
            note.mediaList = new ArrayList<CatchMedia>();
          }

          note.mediaList.add(media);
          parse_trace("Parsing media item complete.");
          break;
        }
      }

      eventType = parser.next();
    }
  }

  private void parseNoteOwner(XmlPullParser parser, CatchNote note)
  throws XmlPullParserException, IOException {
    int eventType = parser.next();

    while (eventType != XmlPullParser.END_DOCUMENT) {
      if (eventType == XmlPullParser.START_TAG) {
        String startTag = parser.getName();
        String nextText = "";

        if (XML_TAG_ID.equals(startTag)) {
          try {
            nextText = parser.nextText();
            long ownerId = Long.parseLong(nextText);
            note.ownerId = ownerId;
          } catch (NumberFormatException nfe) {
            Log.e(LOGCAT_NAME, "unable to parse value for note owner ID: \"" + nextText + '"');
            note.ownerId = 0;
          }

          parse_trace("Owner ID = " + note.ownerId);
        } else if (XML_TAG_USER_NAME.equals(startTag)) {
          String owner = parser.nextText();
          note.owner = owner;
          parse_trace("Owner name = " + note.owner);
        } else {
          parse_trace("(parseNoteOwner) unknown XML tag: <" + startTag + ">");
        }
      } else if (eventType == XmlPullParser.END_TAG) {
        String endTag = parser.getName();

        if (XML_TAG_USER.equals(endTag)) {
          parse_trace("Parsing owner data complete.");
          break;
        }
      }

      eventType = parser.next();
    }
  }

  private void parseLocation(XmlPullParser parser, CatchNote note)
  throws XmlPullParserException, IOException {
    int eventType = parser.next();

    while (eventType != XmlPullParser.END_DOCUMENT) {
      if (eventType == XmlPullParser.START_TAG) {
        String startTag = parser.getName();
        String nextText = "";

        if (XML_TAG_LATITUDE.equals(startTag)) {
          try {
            nextText = parser.nextText();
            double latitude = Double.parseDouble(nextText);
            note.latitude = latitude;
          } catch (NumberFormatException nfe) {
            Log.e(LOGCAT_NAME, "unable to parse value for latitude: \"" + nextText + '"');
            note.latitude = 0.0;
          }
          
          parse_trace("Latitude = " + note.latitude);
        } else if (XML_TAG_LONGITUDE.equals(startTag)) {
          try {
            nextText = parser.nextText();
            double longitude = Double.parseDouble(nextText);
            note.longitude = longitude;
          } catch (NumberFormatException nfe) {
            Log.e(LOGCAT_NAME, "unable to parse value for longitude: \"" + nextText + '"');
            note.longitude = 0.0;
          }
          
          parse_trace("Longitude = " + note.longitude);
        } else if (XML_TAG_ALTITUDE.equals(startTag)) {
          try {
            nextText = parser.nextText();
            double altitude = Double.parseDouble(nextText);
            note.altitude = altitude;
          } catch (NumberFormatException nfe) {
            Log.e(LOGCAT_NAME, "unable to parse value for altitude: \"" + nextText + '"');
            note.altitude = 0.0;
          }

          parse_trace("Altitude = " + note.altitude);
        } else if (XML_TAG_SPEED.equals(startTag)) {
          try {
            nextText = parser.nextText();
            double speed = Double.parseDouble(nextText);
            note.speed = speed;
          } catch (NumberFormatException nfe) {
            Log.e(LOGCAT_NAME, "unable to parse value for speed: \"" + nextText + '"');
            note.speed = 0.0;
          }
          
          parse_trace("Speed = " + note.speed);
        } else if (XML_TAG_BEARING.equals(startTag)) {
          try {
            nextText = parser.nextText();
            double bearing = Double.parseDouble(nextText);
            note.bearing = bearing;
          } catch (NumberFormatException nfe) {
            Log.e(LOGCAT_NAME, "unable to parse value for bearing: \"" + nextText + '"');
            note.bearing = 0.0;
          }
  
          parse_trace("Bearing = " + note.bearing);
        } else if (XML_TAG_ACCURACY_POSITION.equals(startTag)) {
          try {
            nextText = parser.nextText();
            double accuracyPosition = Double.parseDouble(nextText);
            note.accuracyPosition = accuracyPosition;
          } catch (NumberFormatException nfe) {
            Log.e(LOGCAT_NAME, "unable to parse value for accuracyPosition: \"" + nextText + '"');
            note.accuracyPosition = 0.0;
          }
          
          parse_trace("Positional accuracy = "
              + note.accuracyPosition);
        } else if (XML_TAG_ACCURACY_ALTITUDE.equals(startTag)) {
          try {
            nextText = parser.nextText();
            double accuracyAltitude = Double.parseDouble(nextText);
            note.accuracyAltitude = accuracyAltitude;
          } catch (NumberFormatException nfe) {
            Log.e(LOGCAT_NAME, "unable to parse value for accuracyAltitude: \"" + nextText + '"');
            note.accuracyAltitude = 0.0;
          }
          
          parse_trace("Altitude accuracy = "
              + note.accuracyAltitude);
        } else {
          parse_trace("(parseLocation) unknown XML tag: <" + startTag + ">");
        }
      } else if (eventType == XmlPullParser.END_TAG) {
        String endTag = parser.getName();

        if (XML_TAG_LOCATION.equals(endTag)) {
          parse_trace("Parsing geotag complete.");
          break;
        }
      }

      eventType = parser.next();
    }
  }
  
  private void parse_trace(String msg) {
    if (PARSE_TRACING_OUTPUT_ENABLED) {
      Log.d(LOGCAT_NAME, msg);
    }
  }
  
  private synchronized long parse3339(String time) {
    if (time == null || time.length() == 0) {
      return 0;
    }
    
    if (timestamper != null) {
      try {
        timestamper.parse3339(time);
      } catch (TimeFormatException e) {
        Log.e(LOGCAT_NAME, "got TimeFormatException parsing timestamp: \"" + time + '"', e);
        return 0;
      }

      return timestamper.normalize(false);
    } else {
      Date timestamp = null;

      if (rfc3339 == null) {
        rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        rfc3339.setTimeZone(TimeZone.getTimeZone("GMT+0"));
        rfc3339.setLenient(true);
      }
      
      try {
        timestamp = rfc3339.parse(time);
      } catch (ParseException e) {
        Log.e(LOGCAT_NAME, "got ParseException parsing timestamp: \"" + time + '"', e);
        return 0;
      }

      return timestamp.getTime();      
    }
  }
}




Java Source Code List

com.android.http.multipart.ByteArrayPartSource.java
com.android.http.multipart.ByteArrayPartSource.java
com.android.http.multipart.FilePartSource.java
com.android.http.multipart.FilePartSource.java
com.android.http.multipart.FilePart.java
com.android.http.multipart.FilePart.java
com.android.http.multipart.MultipartEntity.java
com.android.http.multipart.MultipartEntity.java
com.android.http.multipart.PartBase.java
com.android.http.multipart.PartBase.java
com.android.http.multipart.PartSource.java
com.android.http.multipart.PartSource.java
com.android.http.multipart.Part.java
com.android.http.multipart.Part.java
com.android.http.multipart.StringPart.java
com.android.http.multipart.StringPart.java
com.catchnotes.api.CatchAPI.java
com.catchnotes.api.CatchAPI.java
com.catchnotes.api.CatchAccount.java
com.catchnotes.api.CatchAccount.java
com.catchnotes.api.CatchMedia.java
com.catchnotes.api.CatchMedia.java
com.catchnotes.api.CatchNoteRef.java
com.catchnotes.api.CatchNoteRef.java
com.catchnotes.api.CatchNote.java
com.catchnotes.api.CatchNote.java
com.catchnotes.api.CatchNotesXmlParser.java
com.catchnotes.api.CatchNotesXmlParser.java
com.catchnotes.api.VersionedCatchHttpClient.java
com.catchnotes.api.VersionedCatchHttpClient.java
com.example.CatchApiDemo.Dashboard.java