All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cz.o2.proxima.server.TransformationObserver Maven / Gradle / Ivy

/**
 * Copyright 2017-2020 O2 Czech Republic, a.s.
 *
 * 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 cz.o2.proxima.server;

import static cz.o2.proxima.server.IngestServer.ingestRequest;

import cz.o2.proxima.direct.commitlog.LogObserver;
import cz.o2.proxima.direct.core.DirectDataOperator;
import cz.o2.proxima.repository.RepositoryFactory;
import cz.o2.proxima.server.metrics.Metrics;
import cz.o2.proxima.storage.StorageFilter;
import cz.o2.proxima.storage.StreamElement;
import cz.o2.proxima.transform.ElementWiseTransformation;
import java.util.concurrent.atomic.AtomicInteger;
import lombok.extern.slf4j.Slf4j;

/** Observer of source data performing transformation to another entity/attribute. */
@Slf4j
public class TransformationObserver implements LogObserver {

  private final RepositoryFactory repoFactory;
  private final ElementWiseTransformation transformation;
  private final StorageFilter filter;
  private final String name;

  private transient DirectDataOperator direct;

  TransformationObserver(
      DirectDataOperator direct,
      String name,
      ElementWiseTransformation transformation,
      StorageFilter filter) {

    this.repoFactory = direct.getRepository().asFactory();
    this.name = name;
    this.transformation = transformation;
    this.filter = filter;
  }

  @Override
  public boolean onError(Throwable error) {
    Utils.die(String.format("Failed to transform using %s. Bailing out.", transformation));
    return false;
  }

  @Override
  public boolean onNext(StreamElement ingest, OnNextContext context) {
    Metrics.reportConsumerWatermark(name, context.getWatermark(), ingest.getStamp());
    if (!filter.apply(ingest)) {
      log.debug("Transformation {}: skipping transformation of {} by filter", name, ingest);
      context.confirm();
    } else {
      doTransform(context, ingest);
    }
    return true;
  }

  @Override
  public void onIdle(OnIdleContext context) {
    Metrics.reportConsumerWatermark(name, context.getWatermark(), -1);
  }

  private void doTransform(OffsetCommitter committer, StreamElement ingest) {

    AtomicInteger toConfirm = new AtomicInteger(0);
    try {
      ElementWiseTransformation.Collector collector =
          elem -> {
            try {
              log.debug("Transformation {}: writing transformed element {}", name, elem);
              ingestRequest(
                  direct(),
                  elem,
                  elem.getUuid(),
                  rpc -> {
                    if (rpc.getStatus() == 200) {
                      if (toConfirm.decrementAndGet() == 0) {
                        committer.confirm();
                      }
                    } else {
                      toConfirm.set(-1);
                      committer.fail(
                          new RuntimeException(
                              String.format(
                                  "Received invalid status %d:%s",
                                  rpc.getStatus(), rpc.getStatusMessage())));
                    }
                  });
            } catch (Exception ex) {
              toConfirm.set(-1);
              committer.fail(ex);
            }
          };

      if (toConfirm.addAndGet(transformation.apply(ingest, collector)) == 0) {
        committer.confirm();
      }
    } catch (Exception ex) {
      toConfirm.set(-1);
      committer.fail(ex);
    }
  }

  private DirectDataOperator direct() {
    if (direct == null) {
      direct = repoFactory.apply().getOrCreateOperator(DirectDataOperator.class);
    }
    return direct;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy