public InstanceState unmarshall(StaxUnmarshallerContext context) throws Exception {
    InstanceState instanceState = new InstanceState();
    int originalDepth = context.getCurrentDepth();
    int targetDepth = originalDepth + 1;

    if (context.isStartOfDocument()) targetDepth += 2;

    while (true) {
      XMLEvent xmlEvent = context.nextEvent();
      if (xmlEvent.isEndDocument()) return instanceState;

      if (xmlEvent.isAttribute() || xmlEvent.isStartElement()) {
        if (context.testExpression("InstanceId", targetDepth)) {
          instanceState.setInstanceId(StringStaxUnmarshaller.getInstance().unmarshall(context));
          continue;
        }
        if (context.testExpression("State", targetDepth)) {
          instanceState.setState(StringStaxUnmarshaller.getInstance().unmarshall(context));
          continue;
        }
        if (context.testExpression("ReasonCode", targetDepth)) {
          instanceState.setReasonCode(StringStaxUnmarshaller.getInstance().unmarshall(context));
          continue;
        }
        if (context.testExpression("Description", targetDepth)) {
          instanceState.setDescription(StringStaxUnmarshaller.getInstance().unmarshall(context));
          continue;
        }
      } else if (xmlEvent.isEndElement()) {
        if (context.getCurrentDepth() < originalDepth) {
          return instanceState;
        }
      }
    }
  }
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    state = (InstanceState) getLastNonConfigurationInstance();

    if (state == null) {
      state = new InstanceState();
      state.handler = new FeedHandler(this);
      Intent i = new Intent(this, FeedService.class);

      i.putExtra(FeedService.EXTRA_URL, getIntent().getStringExtra(FEED_URL));
      i.putExtra(FeedService.EXTRA_MESSENGER, new Messenger(state.handler));

      startService(i);

    } else {
      if (state.handler != null) {
        state.handler.attach(this);
      }

      if (state.feed != null) {
        setFeed(state.feed);
      }
    }
  }
  @VisibleForTesting
  protected void restartZooKeeper(InstanceState currentInstanceState) throws Exception {
    if (currentInstanceState != null) {
      currentInstanceState.updateTimestampMs();
    }
    if (!exhibitor.getControlPanelValues().isSet(ControlPanelTypes.RESTARTS)) {
      exhibitor
          .getLog()
          .add(ActivityLog.Type.INFO, "Restart of ZooKeeper skipped due to control panel setting");
      return;
    }

    exhibitor.getActivityQueue().add(QueueGroups.MAIN, new KillRunningInstance(exhibitor, true));
  }
  @VisibleForTesting
  void doWork() throws Exception {
    InstanceConfig config = exhibitor.getConfigManager().getConfig();
    InstanceState instanceState =
        new InstanceState(
            new ServerList(config.getString(StringConfigs.SERVERS_SPEC)),
            new Checker(exhibitor).calculateState(),
            new RestartSignificantConfig(config));

    exhibitor.getConfigManager().checkRollingConfig(instanceState);

    InstanceState localCurrentInstanceState = currentInstanceState.get();
    if (instanceState.equals(localCurrentInstanceState)) {
      if ((localCurrentInstanceState.getState() == InstanceStateTypes.DOWN)
          || (localCurrentInstanceState.getState() == InstanceStateTypes.NOT_SERVING)) {
        if (!exhibitor.getConfigManager().isRolling()) {
          long elapsedMs = System.currentTimeMillis() - localCurrentInstanceState.getTimestampMs();
          int downInstanceRestartMs = getDownInstanceRestartMs(config);
          if (elapsedMs > downInstanceRestartMs) {
            exhibitor
                .getLog()
                .add(
                    ActivityLog.Type.INFO,
                    "Restarting down/not-serving ZooKeeper after " + elapsedMs + " ms pause");
            restartZooKeeper(localCurrentInstanceState);
          } else {
            exhibitor
                .getLog()
                .add(
                    ActivityLog.Type.INFO,
                    "ZooKeeper down/not-serving waiting "
                        + elapsedMs
                        + " of "
                        + downInstanceRestartMs
                        + " ms before restarting");
          }
        }
      }
    } else {
      boolean serverListChange =
          (localCurrentInstanceState != null)
              && !localCurrentInstanceState.getServerList().equals(instanceState.getServerList());
      boolean configChange =
          (localCurrentInstanceState != null)
              && !localCurrentInstanceState
                  .getCurrentConfig()
                  .equals(instanceState.getCurrentConfig());
      currentInstanceState.set(instanceState);

      exhibitor
          .getLog()
          .add(ActivityLog.Type.INFO, "State: " + instanceState.getState().getDescription());

      if (serverListChange) {
        exhibitor.getLog().add(ActivityLog.Type.INFO, "Server list has changed");
        restartZooKeeper(localCurrentInstanceState);
      } else if (configChange) {
        exhibitor
            .getLog()
            .add(ActivityLog.Type.INFO, "ZooKeeper related configuration has changed");
        restartZooKeeper(localCurrentInstanceState);
      } else {
        switch (instanceState.getState()) {
          case DOWN:
            {
              restartZooKeeper(localCurrentInstanceState);
              break;
            }

          default:
            {
              // nop
              break;
            }
        }
      }
    }
  }
 public InstanceStateTypes getCurrentInstanceState() {
   InstanceState state = currentInstanceState.get();
   return (state != null) ? state.getState() : InstanceStateTypes.LATENT;
 }
  public Instance createInstance(
      GoogleCloud cloud, MachineCreationRequest request, PublicKey sshPublicKey)
      throws OpsException {
    // GoogleComputeClient computeClient = getComputeClient(cloud);

    try {
      Image foundImage = null;

      {
        DiskImageRecipe recipe = null;
        if (request.recipeId != null) {
          recipe = platformLayerClient.getItem(request.recipeId, DiskImageRecipe.class);
        }

        OperatingSystemRecipe operatingSystem = null;
        if (recipe != null) {
          operatingSystem = recipe.getOperatingSystem();
        }

        log.info("Listing images to pick best image");
        Iterable<Image> images = listImages(PROJECTID_GOOGLE);

        // TODO: We need a better solution here!!
        log.warn("Hard coding image names");
        Set<String> imageNames = Sets.newHashSet("ubuntu-12-04-v20120621");
        // Set<String> imageNames = Sets.newHashSet("centos-6-2-v20120621");

        for (Image image : images) {
          if (imageNames.contains(image.getName())) {
            foundImage = image;
            break;
          }
        }

        if (foundImage == null) {
          throw new IllegalArgumentException("Could not find image");
        }
      }

      // GCE requires that the name comply with RFC1035, which I think means a valid DNS
      // For now, just use a UUID, with a pl- prefix so it doesn't start with a number
      // TODO: Fix this!
      String instanceName = "pl-" + UUID.randomUUID().toString();

      Operation createServerOperation;
      {
        Instance create = new Instance();

        create.setName(instanceName);

        create.setZone(buildZoneUrl(projectId, ZONE_US_CENTRAL1_A));

        {
          NetworkInterface networkInterface = new NetworkInterface();
          networkInterface.setNetwork(buildNetworkUrl(projectId, "default"));

          AccessConfig networkAccessConfig = new AccessConfig();
          networkAccessConfig.setType("ONE_TO_ONE_NAT");

          networkInterface.setAccessConfigs(Lists.newArrayList(networkAccessConfig));

          create.setNetworkInterfaces(Lists.newArrayList(networkInterface));
        }

        Metadata metadata = new Metadata();
        metadata.setItems(Lists.<Items>newArrayList());
        create.setMetadata(metadata);

        if (request.tags != null) {
          for (Tag tag : request.tags) {
            Metadata.Items meta = new Metadata.Items();
            meta.setKey(tag.getKey());
            meta.setValue(tag.getValue());
            metadata.getItems().add(meta);
          }
        }

        if (request.sshPublicKey != null) {
          Metadata.Items meta = new Metadata.Items();
          meta.setKey("sshKeys");
          meta.setValue(USER_NAME + ":" + OpenSshUtils.serialize(sshPublicKey));

          metadata.getItems().add(meta);
        }

        create.setImage(foundImage.getSelfLink());

        MachineType flavor = getClosestInstanceType(request);
        if (flavor == null) {
          throw new OpsException("Cannot determine machine type for request");
        }
        create.setMachineType(flavor.getSelfLink());

        if (request.securityGroups != null) {
          // TODO: Reimplement if needed
          throw new UnsupportedOperationException();
        }

        // if (createdSecurityGroup != null) {
        // ServerForCreate.SecurityGroup serverSecurityGroup = new ServerForCreate.SecurityGroup();
        // serverSecurityGroup.setName(createdSecurityGroup.getName());
        // create.getSecurityGroups().add(serverSecurityGroup);
        // }

        // create.setConfigDrive(cloudBehaviours.useConfigDrive());

        log.info("Launching new server: " + instanceName);
        try {
          createServerOperation = compute.instances().insert(projectId, create).execute();
        } catch (IOException e) {
          throw new OpsException("Error launching new instance", e);
        }
      }

      log.info("Waiting for server to be ready");
      createServerOperation = waitComplete(createServerOperation, 10, TimeUnit.MINUTES);

      Instance created;

      InstanceState state = null;
      while (true) {
        created = findInstanceByName(instanceName);

        state = InstanceState.get(created);
        log.info("Instance state: " + state);

        if (state.isRunning()) {
          break;
        }

        Thread.sleep(1000);
      }

      return created;
    } catch (InterruptedException e) {
      ExceptionUtils.handleInterrupted(e);
      throw new OpsException("Error building server", e);
    } catch (TimeoutException e) {
      throw new OpsException("Timeout waiting for server build", e);
    }
  }
  private void setFeed(RSSFeed feed) {
    state.feed = feed;

    setListAdapter(new FeedAdapter(feed));
  }