class RollableScalableResourceOperation<T extends HasMetadata, L extends KubernetesResourceList<T>, R extends Resource<T>>
    extends HasMetadataOperation<T, L, R> implements RollableScalableResource<T>, TimeoutImageEditReplacePatchable<T> {

  protected final PodOperationContext rollingOperationContext;

  protected RollableScalableResourceOperation(PodOperationContext context, OperationContext superContext, Class<T> type,
      Class<L> listType) {
    super(superContext, type, listType);
    this.rollingOperationContext = context;
  }

  protected abstract RollingUpdater<T, L> getRollingUpdater(long rollingTimeout, TimeUnit rollingTimeUnit);

  @Override
  public T edit(UnaryOperator<T> function) {
    RollingUpdater<T, L> rollingUpdater = getRollingUpdater(context.getTimeout(), context.getTimeoutUnit());
    if (!rollingOperationContext.isRolling() || rollingUpdater == null) {
      return super.edit(function);
    }
    T oldObj = getItemOrRequireFromServer();
    T newObj = function.apply(getKubernetesSerialization().clone(oldObj));
    return rollingUpdater.rollUpdate(oldObj, newObj);
  }

  public abstract RollableScalableResourceOperation<T, L, R> newInstance(PodOperationContext context,
      OperationContext superContext);

  @Override
  public Loggable withLogWaitTimeout(Integer logWaitTimeout) {
    return withReadyWaitTimeout(logWaitTimeout);
  }

  @Override
  public Loggable withReadyWaitTimeout(Integer timeout) {
    return newInstance(rollingOperationContext.withReadyWaitTimeout(timeout), context);
  }

  @Override
  public Loggable inContainer(String id) {
    return newInstance(rollingOperationContext.withContainerId(id), context);
  }

  @Override
  public TimeoutImageEditReplacePatchable<T> rolling() {
    return newInstance(rollingOperationContext.toBuilder().rolling(true).build(), context);
  }

  @Override
  public String getLog() {
    return getLog(rollingOperationContext.isPrettyOutput());
  }

  @Override
  public LogWatch watchLog() {
    return watchLog(null);
  }

  @Override
  public T updateImage(String image) {
    T value = get();

    if (value == null) {
      throw new KubernetesClientException("Resource doesn't exist");
    }

    List<Container> containers = getContainers(value);

    if (containers.size() > 1) {
      throw new KubernetesClientException("Image update is not supported for multicontainer pods");
    }
    if (containers.isEmpty()) {
      throw new KubernetesClientException("Pod has no containers!");
    }

    Container container = containers.iterator().next();
    return updateImage(Collections.singletonMap(container.getName(), image));
  }

  protected abstract List<Container> getContainers(T value);

  @Override
  public T updateImage(Map<String, String> containerToImageMap) {
    T value = get();
    if (value == null) {
      throw new KubernetesClientException("Resource doesn't exist");
    }

    T base = getKubernetesSerialization().clone(value);

    List<Container> containers = getContainers(value);

    if (containers.isEmpty()) {
      throw new KubernetesClientException("Pod has no containers!");
    }

    for (Container container : containers) {
      if (containerToImageMap.containsKey(container.getName())) {
        container.setImage(containerToImageMap.get(container.getName()));
      }
    }

    return sendPatchedObject(base, value);
  }

  protected T sendPatchedObject(T oldObject, T updatedObject) {
    return this.patch(null, oldObject, updatedObject);
  }

  @Override
  public RollableScalableResourceOperation<T, L, R> withTimeout(long timeout, TimeUnit unit) {
    return newInstance(rollingOperationContext, context.withTimeout(timeout, unit));
  }

  @Override
  public RollableScalableResourceOperation<T, L, R> withTimeoutInMillis(long timeoutInMillis) {
    return withTimeout(timeoutInMillis, TimeUnit.MILLISECONDS);
  }

  @Override
  public T pause() {
    throw new KubernetesClientException(context.getPlural() + " pausing is not supported");
  }

  @Override
  public T resume() {
    throw new KubernetesClientException(context.getPlural() + " resuming is not supported");
  }

  @Override
  public T restart() {
    throw new KubernetesClientException(context.getPlural() + " restarting is not supported");
  }

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

}

    throw new KubernetesClientException(context.getPlural() + " undo is not supported");
  
<methods>public void <init>(io.fabric8.kubernetes.client.dsl.internal.OperationContext, Class<T>, Class<L>) ,public T accept(Consumer<T>) ,public T edit(UnaryOperator<T>) ,public transient T edit(Visitor[]) ,public T editStatus(UnaryOperator<T>) ,public HasMetadataOperation<T,L,R> newInstance(io.fabric8.kubernetes.client.dsl.internal.OperationContext) ,public T patch() ,public T patch(io.fabric8.kubernetes.client.dsl.base.PatchContext) ,public T patch(io.fabric8.kubernetes.client.dsl.base.PatchContext, T) ,public T patch(io.fabric8.kubernetes.client.dsl.base.PatchContext, java.lang.String) ,public T patchStatus() ,public T patchStatus(T) ,public T replace() ,public T replaceStatus() ,public T scale(int) ,public T scale(int, boolean) ,public Scale scale(Scale) ,public T update() ,public T updateStatus() <variables>public static final long DEFAULT_GRACE_PERIOD_IN_SECONDS,public static final io.fabric8.kubernetes.api.model.DeletionPropagation DEFAULT_PROPAGATION_POLICY,private static final Logger LOGGER,private static final java.lang.String PATCH_OPERATION,private static final java.lang.String REPLACE_OPERATION,private static final java.lang.String UPDATE_OPERATION