class StatefulSetOperationsImpl
    extends RollableScalableResourceOperation<StatefulSet, StatefulSetList, RollableScalableResource<StatefulSet>>
    implements TimeoutImageEditReplacePatchable<StatefulSet> {
  public StatefulSetOperationsImpl(Client client) {
    this(new PodOperationContext(), HasMetadataOperationsImpl.defaultContext(client));
  }

  public StatefulSetOperationsImpl(PodOperationContext context, OperationContext superContext) {
    super(context, superContext.withApiGroupName("apps")
        .withApiGroupVersion("v1")
        .withPlural("statefulsets"), StatefulSet.class, StatefulSetList.class);
  }

  @Override
  public StatefulSetOperationsImpl newInstance(OperationContext context) {
    return new StatefulSetOperationsImpl(rollingOperationContext, context);
  }

  @Override
  public StatefulSetOperationsImpl newInstance(PodOperationContext context,
      OperationContext superContext) {
    return new StatefulSetOperationsImpl(context, superContext);
  }

  @Override
  public RollingUpdater<StatefulSet, StatefulSetList> getRollingUpdater(long rollingTimeout, TimeUnit rollingTimeUnit) {
    return null;
  }

  @Override
  public Status rollback(DeploymentRollback deploymentRollback) {
    throw new KubernetesClientException("rollback not supported in case of StatefulSets");
  }

  @Override
  public String getLog(boolean isPretty) {
    return PodOperationUtil.getLog(
        new StatefulSetOperationsImpl(rollingOperationContext.withPrettyOutput(isPretty), context).doGetLog(), isPretty);
  }

  private List<PodResource> doGetLog() {
    StatefulSet statefulSet = requireFromServer();

    return PodOperationUtil.getPodOperationsForController(context,
        rollingOperationContext, statefulSet.getMetadata().getUid(),
        getStatefulSetSelectorLabels(statefulSet));
  }

  /**
   * Returns an unclosed Reader. It's the caller responsibility to close it.
   *
   * @return Reader
   */
  @Override
  public Reader getLogReader() {
    return PodOperationUtil.getLogReader(doGetLog());
  }

  /**
   * Returns an unclosed InputStream. It's the caller responsibility to close it.
   *
   * @return InputStream
   */
  @Override
  public InputStream getLogInputStream() {
    return PodOperationUtil.getLogInputStream(doGetLog());
  }

  @Override
  public LogWatch watchLog(OutputStream out) {
    return PodOperationUtil.watchLog(doGetLog(), out);
  }

  @Override
  public StatefulSet restart() {
    return RollingUpdater.restart(this);
  }

  @Override
  public StatefulSet undo() {<FILL_FUNCTION_BODY>}

  private ControllerRevisionList getControllerRevisionListForStatefulSet(StatefulSet statefulSet) {
    return this.context.getClient().resources(ControllerRevision.class, ControllerRevisionList.class).inNamespace(namespace)
        .withLabels(statefulSet.getSpec().getSelector().getMatchLabels()).list();
  }

  static Map<String, String> getStatefulSetSelectorLabels(StatefulSet statefulSet) {
    Map<String, String> labels = new HashMap<>();
    if (statefulSet != null && statefulSet.getSpec() != null
        && statefulSet.getSpec().getTemplate() != null
        && statefulSet.getSpec().getTemplate().getMetadata() != null) {
      labels.putAll(statefulSet.getSpec().getTemplate().getMetadata().getLabels());
    }
    return labels;
  }

  @Override
  protected List<Container> getContainers(StatefulSet value) {
    return value.getSpec().getTemplate().getSpec().getContainers();
  }

  @Override
  public TimeTailPrettyLoggable limitBytes(int limitBytes) {
    return new StatefulSetOperationsImpl(rollingOperationContext.withLimitBytes(limitBytes), context);
  }

  @Override
  public TimeTailPrettyLoggable terminated() {
    return new StatefulSetOperationsImpl(rollingOperationContext.withTerminatedStatus(true), context);
  }

  @Override
  public Loggable withPrettyOutput() {
    return new StatefulSetOperationsImpl(rollingOperationContext.withPrettyOutput(true), context);
  }

  @Override
  public PrettyLoggable tailingLines(int lines) {
    return new StatefulSetOperationsImpl(rollingOperationContext.withTailingLines(lines), context);
  }

  @Override
  public TailPrettyLoggable sinceTime(String timestamp) {
    return new StatefulSetOperationsImpl(rollingOperationContext.withSinceTimestamp(timestamp), context);
  }

  @Override
  public TailPrettyLoggable sinceSeconds(int seconds) {
    return new StatefulSetOperationsImpl(rollingOperationContext.withSinceSeconds(seconds), context);
  }

  @Override
  public BytesLimitTerminateTimeTailPrettyLoggable usingTimestamps() {
    return new StatefulSetOperationsImpl(rollingOperationContext.withTimestamps(true), context);
  }
}

    List<ControllerRevision> controllerRevisions = getControllerRevisionListForStatefulSet(get()).getItems();
    if (controllerRevisions.size() < 2) {
      throw new IllegalStateException("No revision to rollback to!");
    }

    // Sort list of replicaSets based on revision annotation
    controllerRevisions.sort((o1, o2) -> {
      Long revision2 = o2.getRevision();
      Long revision1 = o1.getRevision();
      if (revision1 != null && revision2 != null) {
        return revision2.intValue() - revision1.intValue();
      } else if (revision1 != null) {
        return revision1.intValue();
      } else if (revision2 != null) {
        return revision2.intValue();
      } else {
        return 0;
      }
    });
    ControllerRevision previousControllerRevision = controllerRevisions.get(1);

    return patch(PatchContext.of(PatchType.STRATEGIC_MERGE),
        getKubernetesSerialization().asJson(previousControllerRevision.getData()));
  
<methods>public StatefulSet edit(UnaryOperator<StatefulSet>) ,public java.lang.String getLog() ,public io.fabric8.kubernetes.client.dsl.Loggable inContainer(java.lang.String) ,public abstract RollableScalableResourceOperation<StatefulSet,StatefulSetList,RollableScalableResource<StatefulSet>> newInstance(io.fabric8.kubernetes.client.dsl.internal.PodOperationContext, io.fabric8.kubernetes.client.dsl.internal.OperationContext) ,public StatefulSet pause() ,public StatefulSet restart() ,public StatefulSet resume() ,public TimeoutImageEditReplacePatchable<StatefulSet> rolling() ,public StatefulSet undo() ,public StatefulSet updateImage(java.lang.String) ,public StatefulSet updateImage(Map<java.lang.String,java.lang.String>) ,public io.fabric8.kubernetes.client.dsl.LogWatch watchLog() ,public io.fabric8.kubernetes.client.dsl.Loggable withLogWaitTimeout(java.lang.Integer) ,public io.fabric8.kubernetes.client.dsl.Loggable withReadyWaitTimeout(java.lang.Integer) ,public RollableScalableResourceOperation<StatefulSet,StatefulSetList,RollableScalableResource<StatefulSet>> withTimeout(long, java.util.concurrent.TimeUnit) ,public RollableScalableResourceOperation<StatefulSet,StatefulSetList,RollableScalableResource<StatefulSet>> withTimeoutInMillis(long) <variables>protected final non-sealed io.fabric8.kubernetes.client.dsl.internal.PodOperationContext rollingOperationContext