gt:   protected void handleError(IOException e) {
context: package org.danbrough.mega;
  
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.io.OutputStream;
  import java.io.Reader;
  import java.math.BigInteger;
  import java.net.HttpURLConnection;
  import java.net.URL;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Locale;
  import java.util.Map;
  import java.util.ResourceBundle;
  import java.util.concurrent.TimeUnit;
  import java.util.zip.GZIPInputStream;
  
  import com.google.gson.JsonArray;
  import com.google.gson.JsonElement;
  import com.google.gson.JsonObject;
  import com.google.gson.annotations.SerializedName;
  
  public class MegaClient {
    private transient static final org.slf4j.Logger log = org.slf4j.LoggerFactory
        .getLogger(MegaClient.class.getSimpleName());
  
    static final String API_URL;
    static final String USER_AGENT;
  
    static {
      ResourceBundle properties = ResourceBundle.getBundle(MegaClient.class
          .getName());
      API_URL = properties.getString("apiPath");
      USER_AGENT = properties.getString("userAgent");
    }
  
    transient MegaCrypto crypto = MegaCrypto.get();
  
    Node currentFolder = null;
  
    @SuppressWarnings("rawtypes")
    transient LinkedList<Command> cmdQueue = new LinkedList<Command>();
  
    byte passwordKey[];
    byte masterKey[];
    BigInteger[] privateKey;
  
    String email;
  
    User me;
  
    // no two interrelated client instances should ever have the same sessionid
    @SerializedName("sid")
    String sessionID;
  
    // request id
    char[] reqid;
  
    transient String appkey = "MegaJavaTest";
  
    transient boolean running = false;
  
    transient ThreadPool threadPool;
  
    // back off time for server client requests in millis
    transient long backoffsc = 100;
  
    transient String scnotifyurl = null;
  
    transient boolean startedSC = false;
  
    // server-client request sequence number
    String scsn;
  
    Node rootNode, incomingNode, rubbishNode, mailNode;
    Map<String, Node> nodes;
    HashMap<String, User> users;
  
    transient HttpURLConnection scConn;
  
    public MegaClient() {
      super();
    }
  
    char[] generateID(int len) {
      char id[] = new char[len];
      for (int i = 0; i < 10; i++) {
        id[i] = (char) ('a' + crypto.randInt(26));
      }
      return id;
    }
  
    public void setSessionID(String sessionID) {
      this.sessionID = sessionID;
    }
  
    public String getSessionID() {
      return sessionID;
    }
  
    public void login(String email, String password, final Callback<Void> callback)
        throws IOException {
      log.info("login() {}", email);
  
      this.email = email.toLowerCase(Locale.getDefault());
  
      enqueueCommand(new CommandLogin(this, password, callback) {
        @Override
        public void processResponse(JsonElement e) throws Exception {
          super.processResponse(e);
          fetchNodes(callback);
        }
      });
    }
  
    public void fetchNodes(final Callback<Void> callback) throws IOException {
      log.info("fetchNodes();");
      enqueueCommand(new CommandFetchNodes(this, callback));
    }
  
    public void enqueueCommand(@SuppressWarnings("rawtypes") Command cmd) {
      synchronized (cmdQueue) {
        cmdQueue.addLast(cmd);
        cmdQueue.notify();
      }
    }
  
    public void enqueueCommands(
        @SuppressWarnings("rawtypes") List<Command> commands) {
      synchronized (cmdQueue) {
        cmdQueue.addAll(commands);
        cmdQueue.notify();
      }
    }
  
    public void setEmail(String email) {
      this.email = email;
    }
  
    public String getEmail() {
      return email;
    }
  
    public synchronized void start() {
      if (running)
        return;
  
      if (threadPool == null)
        throw new RuntimeException("Thread pool not provided");
      running = true;
  
      if (sessionID != null) {
        log.info("logged in as: {} with session: {}", email, sessionID);
      }
  
      // initialize random API request sequence ID
  
      if (reqid == null)
        reqid = generateID(10);
  
      startSC();
  
      threadPool.background(new Runnable() {
  
        @Override
        public void run() {
          try {
            workerLoop();
          } catch (Throwable t) {
            log.error(t.getMessage(), t);
          } finally {
            MegaClient.this.stop();
          }
        }
      });
    }
  
    public synchronized void stop() {
      if (!running)
        return;
      log.info("stop();");
      running = false;
      notifyWorker();
      stopSC();
    }
  
    @SuppressWarnings("unchecked")
    protected void workerLoop() {
  
      log.debug("workerLoop();");
  
      if (scsn != null && sessionID != null) {
        startSC();
      }
  
      synchronized (cmdQueue) {
        while (running) {
          try {
            cmdQueue.wait();
          } catch (InterruptedException e) {
            log.error(e.getMessage(), e);
            return;
          }
          if (!running)
            return;
  
          if (!cmdQueue.isEmpty()) {
            // commands to send
            @SuppressWarnings("rawtypes")
            final LinkedList<Command> commands = (LinkedList<Command>) cmdQueue
                .clone();
            cmdQueue.clear();
  
            if (!running)
              return;
  
            threadPool.background(new Runnable() {
  
              @Override
              public void run() {
                log.error("run();");
                try {
                  processRequest(commands);
                } catch (IOException e) {
                  handleError(e);
                }
              }
            });
          }
        }
      }
    }
  
    public void getAccountDetails(boolean storage, boolean transfer, boolean pro,
        boolean transactions, boolean purchases, final boolean sessions,
        final Callback<AccountDetails> detailsCallback) {
      final AccountDetails details = new AccountDetails();
  
      log.info("getAccountDetails() running: {}", this.running);
      @SuppressWarnings("rawtypes")
      LinkedList<Command> commands = new LinkedList<Command>();
  
      // if (transactions)
      // reqs[r].add(new CommandGetUserTransactions(this, ad));
      // if (purchases)
      // reqs[r].add(new CommandGetUserPurchases(this, ad));
  
      commands.addLast(new CommandGetUserQuota(this, details, storage, transfer,
          pro) {
        @Override
        public void processResponse(JsonElement e) throws Exception {
          super.processResponse(e);
          if (!sessions)
            detailsCallback.onResult(details);
        }
      });
  
      log.warn("transactions,purchases not implemented");
  
      if (sessions) {
        commands.addLast(new Command<AccountDetails>("usl", detailsCallback) {
          @Override
          public void processResponse(JsonElement e) throws Exception {
            details.setSessions(e.getAsJsonArray());
            onResult(details);
          }
        });
      }
  
      enqueueCommands(commands);
  
    }
  
    /**
     * {"a":[{"a":"t","i":"uRHghuyDqJ","t":{"f":[{"h":"9xERwLIa","t":1,"a":
     * "VE8iL_y3eUW1KqOuL6vFfA"
     * ,"k":"XF6DfmTorLE:J6lPWMFvJSw-8IQnGy5vFg","p":"I91ESJKZ"
     * ,"ts":1375206239,"u"
     * :"XF6DfmTorLE"}]},"ou":"XF6DfmTorLE"}],"sn":"QP7kECjmcgE"}
     **/
  
    protected void procsc(JsonObject o) {
      log.trace("procsc() {}", o);
  
      if (o.has("w")) {
        this.scnotifyurl = o.get("w").getAsString();
      }
  
      if (o.has("sn")) {
        setScsn(o.get("sn").getAsString());
      }
  
      if (o.has("a")) {
        log.trace("a: {}", o.get("a"));
        procSC_a(o.get("a").getAsJsonArray());
      }
    }
  
    protected void procSC_a(JsonArray array) {
      for (int i = 0; i < array.size(); i++) {
        JsonObject o = array.get(i).getAsJsonObject();
        String action = o.get("a").getAsString();
        if (action.equals("u")) {
          log.info("node update");
          // sc_updatenode();
        } else if (action.equals("t")) {
          log.info("node addition");
          // sc_newnodes();
          // mergenewshares();
          // applykeys();
  
        } else if (action.equals("d")) {
          log.info("node deletion");
          // sc_deltree();
  
        } else if (action.equals("s")) {
          log.info("share addition/update/revocation");
          // sc_shares();
  
        } else if (action.equals("c")) {
          log.info("contact addition/update");
          // sc_contacts();
  
        } else if (action.equals("k")) {
          log.info("crypto key reques");
          // sc_keys();
  
        } else if (action.equals("fa")) {
  
        } else if (action.equals("")) {
          log.info("file attribute update");
  
        } else {
          log.error("unknown action {}", action);
          continue;
        }
  
      }
    }
  
  