com.jivesoftware.os.upena.amza.transport.http.replication.endpoints.UpenaAmzaReplicationRestEndpoints.java Source code

Java tutorial

Introduction

Here is the source code for com.jivesoftware.os.upena.amza.transport.http.replication.endpoints.UpenaAmzaReplicationRestEndpoints.java

Source

/*
 * Copyright 2013 Jive Software, Inc
 *
 * 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 com.jivesoftware.os.upena.amza.transport.http.replication.endpoints;

import com.jivesoftware.os.mlogger.core.MetricLogger;
import com.jivesoftware.os.mlogger.core.MetricLoggerFactory;
import com.jivesoftware.os.routing.bird.shared.ResponseHelper;
import com.jivesoftware.os.upena.amza.shared.UpenaAmzaInstance;
import com.jivesoftware.os.upena.amza.shared.UpenaRingHost;
import com.jivesoftware.os.upena.amza.shared.RowIndexKey;
import com.jivesoftware.os.upena.amza.shared.RowIndexValue;
import com.jivesoftware.os.upena.amza.shared.RowScan;
import com.jivesoftware.os.upena.amza.shared.RowScanable;
import com.jivesoftware.os.upena.amza.shared.TableName;
import com.jivesoftware.os.upena.amza.storage.RowMarshaller;
import com.jivesoftware.os.upena.amza.storage.binary.BinaryRowMarshaller;
import com.jivesoftware.os.upena.amza.transport.http.replication.RowUpdates;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Singleton;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import org.apache.commons.lang.mutable.MutableLong;

@Singleton
@Path("/amza")
public class UpenaAmzaReplicationRestEndpoints {

    private static final MetricLogger LOG = MetricLoggerFactory.getLogger();
    private final UpenaAmzaInstance amzaInstance;

    public UpenaAmzaReplicationRestEndpoints(@Context UpenaAmzaInstance amzaInstance) {
        this.amzaInstance = amzaInstance;
    }

    @POST
    @Consumes("application/json")
    @Path("/ring/add")
    public Response addHost(final UpenaRingHost ringHost) {
        try {
            LOG.info("Attempting to add RingHost: " + ringHost);
            amzaInstance.addRingHost("master", ringHost);
            return ResponseHelper.INSTANCE.jsonResponse(Boolean.TRUE);
        } catch (Exception x) {
            LOG.warn("Failed to add RingHost: " + ringHost, x);
            return ResponseHelper.INSTANCE.errorResponse("Failed to add RingHost: " + ringHost, x);
        }
    }

    @POST
    @Consumes("application/json")
    @Path("/ring/remove")
    public Response removeHost(final UpenaRingHost ringHost) {
        try {
            LOG.info("Attempting to remove RingHost: " + ringHost);
            amzaInstance.removeRingHost("master", ringHost);
            return ResponseHelper.INSTANCE.jsonResponse(Boolean.TRUE);
        } catch (Exception x) {
            LOG.warn("Failed to add RingHost: " + ringHost, x);
            return ResponseHelper.INSTANCE.errorResponse("Failed to remove RingHost: " + ringHost, x);
        }
    }

    @POST
    @Consumes("application/json")
    @Path("/ring")
    public Response getRing() {
        try {
            LOG.info("Attempting to get amza ring.");
            List<UpenaRingHost> ring = amzaInstance.getRing("master");
            return ResponseHelper.INSTANCE.jsonResponse(ring);
        } catch (Exception x) {
            LOG.warn("Failed to get amza ring.", x);
            return ResponseHelper.INSTANCE.errorResponse("Failed to get amza ring.", x);
        }
    }

    @POST
    @Consumes("application/json")
    @Path("/tables")
    public Response getTables() {
        try {
            LOG.info("Attempting to get table names.");
            List<TableName> tableNames = amzaInstance.getTableNames();
            return ResponseHelper.INSTANCE.jsonResponse(tableNames);
        } catch (Exception x) {
            LOG.warn("Failed to get table names.", x);
            return ResponseHelper.INSTANCE.errorResponse("Failed to get table names.", x);
        }
    }

    @POST
    @Consumes("application/json")
    @Path("/changes/add")
    public Response changeset(final RowUpdates changeSet) {
        try {
            amzaInstance.updates(changeSet.getTableName(), changeSetToScanable(changeSet));
            return ResponseHelper.INSTANCE.jsonResponse(Boolean.TRUE);
        } catch (Exception x) {
            LOG.warn("Failed to apply changeset: " + changeSet, x);
            return ResponseHelper.INSTANCE.errorResponse("Failed to changeset " + changeSet, x);
        }
    }

    private RowScanable changeSetToScanable(final RowUpdates changeSet) throws Exception {

        final BinaryRowMarshaller rowMarshaller = new BinaryRowMarshaller();
        return new RowScanable() {
            @Override
            public <E extends Exception> void rowScan(RowScan<E> rowScan) throws Exception {
                for (byte[] row : changeSet.getChanges()) {
                    RowMarshaller.WALRow walr = rowMarshaller.fromRow(row);
                    if (!rowScan.row(walr.getTransactionId(), walr.getKey(), walr.getValue())) {
                        return;
                    }
                }
            }

            @Override
            public <E extends Exception> void rangeScan(RowIndexKey from, RowIndexKey to, RowScan<E> rowScan)
                    throws Exception {
                for (byte[] row : changeSet.getChanges()) {
                    RowMarshaller.WALRow walr = rowMarshaller.fromRow(row);
                    if (!rowScan.row(walr.getTransactionId(), walr.getKey(), walr.getValue())) {
                        return;
                    }
                }
            }

        };
    }

    @POST
    @Consumes("application/json")
    @Path("/changes/take")
    public Response take(final RowUpdates rowUpdates) {
        try {

            final BinaryRowMarshaller rowMarshaller = new BinaryRowMarshaller();
            final List<byte[]> rows = new ArrayList<>();
            final MutableLong highestTransactionId = new MutableLong();
            amzaInstance.takeRowUpdates(rowUpdates.getTableName(), rowUpdates.getHighestTransactionId(),
                    new RowScan() {
                        @Override
                        public boolean row(long orderId, RowIndexKey key, RowIndexValue value) throws Exception {
                            rows.add(rowMarshaller.toRow(orderId, key, value));
                            if (orderId > highestTransactionId.longValue()) {
                                highestTransactionId.setValue(orderId);
                            }
                            return true;
                        }
                    });

            return ResponseHelper.INSTANCE.jsonResponse(
                    new RowUpdates(highestTransactionId.longValue(), rowUpdates.getTableName(), rows));
        } catch (Exception x) {
            LOG.warn("Failed to apply changeset: " + rowUpdates, x);
            return ResponseHelper.INSTANCE.errorResponse("Failed to changeset " + rowUpdates, x);
        }
    }
}