package io.eguan.vvr.remote; /* * #%L * Project eguan * %% * Copyright (C) 2012 - 2017 Oodrive * %% * 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. * #L% */ import io.eguan.dtx.DtxResourceManagerContext; import io.eguan.dtx.DtxTaskApi; import io.eguan.net.MsgClientStartpoint; import io.eguan.net.MsgServerRemoteStatus; import io.eguan.net.MsgServerTimeoutException; import io.eguan.proto.Common.OpCode; import io.eguan.proto.Common.ProtocolVersion; import io.eguan.proto.Common.Type; import io.eguan.proto.Common.Uuid; import io.eguan.proto.vvr.VvrRemote; import io.eguan.proto.vvr.VvrRemote.RemoteOperation; import io.eguan.utils.UuidT; import java.net.ConnectException; import java.util.ArrayList; import java.util.Collection; import java.util.Objects; import java.util.UUID; import javax.annotation.Nonnull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.protobuf.InvalidProtocolBufferException; /** * Utilities around {@link VvrRemote}. * * @author oodrive * @author llambert * @author jmcaba * */ public final class VvrRemoteUtils { private static final Logger LOGGER = LoggerFactory.getLogger(VvrRemoteUtils.class.getSimpleName()); /** * No instance. */ private VvrRemoteUtils() { throw new AssertionError(); } /** * {@link Uuid} to {@link UUID}. * * @param uuid * @return {@link UUID} corresponding to <code>uuid</code> */ public static final UUID fromUuid(@Nonnull final Uuid uuid) { return new UUID(uuid.getMsb(), uuid.getLsb()); } /** * {@link Uuid} to {@link UuidT}. * * @param uuid * @return {@link UuidT} corresponding to <code>uuid</code> */ public static final <F> UuidT<F> fromUuidT(@Nonnull final Uuid uuid) { return new UuidT<>(uuid.getMsb(), uuid.getLsb()); } /** * {@link UUID} to {@link Uuid}. * * @param uuid * @return {@link Uuid} corresponding to <code>uuid</code> */ public static final Uuid newUuid(@Nonnull final UUID uuid) { return Uuid.newBuilder().setMsb(uuid.getMostSignificantBits()).setLsb(uuid.getLeastSignificantBits()).build(); } /** * {@link UuidT} to {@link Uuid}. * * @param uuid * @return {@link Uuid} corresponding to <code>uuid</code> */ public static final <F> Uuid newTUuid(@Nonnull final UuidT<F> uuid) { return Uuid.newBuilder().setMsb(uuid.getMostSignificantBits()).setLsb(uuid.getLeastSignificantBits()).build(); } /** * Tells if the given {@link Uuid}s are equals. * * @param uuid1 * a valid Uuid or <code>null</code> * @param uuid2 * a valid Uuid or <code>null</code> * @return <code>true</code> if the <code>uuid1</code> and <code>uuid2</code> are equals or both <code>null</code> */ public static final boolean equalsUuid(final Uuid uuid1, final Uuid uuid2) { // true if both are null if (uuid1 == uuid2) { return true; } if (uuid1 == null || uuid2 == null) { return false; } // Nor uuid1 nor uuid2 is null return uuid1.getMsb() == uuid2.getMsb() && uuid1.getLsb() == uuid2.getLsb(); } /** * Sends a {@link VvrRemote} message to the given destinations. The source, type and opCode are filled. Nothing is * sent if <code>startpoint</code> or <code>source</code> is <code>null</code>. * * @param opBuilder * message builder * @param startpoint * message destination * @param source * message source * @param type * type of object * @param opCode * operation on object * @return status of sync request or <code>null</code> for async messages or stand alone mode * @throws InterruptedException * @throws MsgServerTimeoutException * @throws ConnectException * if peer != null */ public static final Collection<MsgServerRemoteStatus> sendMessage(final RemoteOperation.Builder opBuilder, final MsgClientStartpoint startpoint, final Uuid source, final Type type, final OpCode opCode, final boolean async, final UUID peer) throws MsgServerTimeoutException, InterruptedException, ConnectException { // Stand alone? if (startpoint == null) { return null; } // Source is immutable, no need to make a defensive copy opBuilder.setVersion(ProtocolVersion.VERSION_1); opBuilder.setSource(Objects.requireNonNull(source)); opBuilder.setType(type); opBuilder.setOp(opCode); final RemoteOperation operation = opBuilder.build(); if (async) { try { startpoint.sendAsyncMessage(operation); } catch (final Exception e) { LOGGER.warn( "Failed to send message type=" + type + ", uuid=" + (operation == null ? "?" : fromUuid(operation.getUuid()).toString()) + ", op=" + opCode, e); } return null; } else { if (peer == null) { return startpoint.sendSyncMessage(operation); } else { final MsgServerRemoteStatus status = startpoint.sendSyncMessageNewChannel(peer, operation); final Collection<MsgServerRemoteStatus> result = new ArrayList<>(1); result.add(status); return result; } } } /** * Submit a {@link VvrRemote} message to the given destinations as a transaction. The source, type and opCode are * filled. * * @param opBuilder * message builder * @param dtxTaskApi * dtx manager * @param resourceId * id of resource manager * @param source * message source * @param type * type of object * @param opCode * operation on object * @return the task ID or null if on mode stand alone */ public static final UUID submitTransaction(final RemoteOperation.Builder opBuilder, final DtxTaskApi dtxTaskApi, final UUID resourceId, final Uuid source, final Type type, final OpCode opCode) { // Fill builder // source is immutable, no need to make a defensive copy opBuilder.setVersion(ProtocolVersion.VERSION_1); opBuilder.setSource(source); opBuilder.setType(type); opBuilder.setOp(opCode); // Submit transaction in mode distributed RemoteOperation operation = null; try { operation = opBuilder.build(); final byte[] payload = operation.toByteArray(); return dtxTaskApi.submit(resourceId, payload); } catch (final Error | IllegalStateException e) { LOGGER.warn("Failed to submit transaction resourceId=" + resourceId + ", type=" + type + ", uuid=" + (operation == null ? "?" : fromUuid(operation.getUuid()).toString()) + ", op=" + opCode, e); throw e; } catch (final Exception e) { LOGGER.warn("Failed to submit transaction resourceId=" + resourceId + ", type=" + type + ", uuid=" + (operation == null ? "?" : fromUuid(operation.getUuid()).toString()) + ", op=" + opCode, e); throw new IllegalStateException(e); } } /** * Create dtx context containing the deserialized payload. */ public static final DtxResourceManagerContext createDtxContext(final UUID resourceManagerId, final byte[] payload) throws InvalidProtocolBufferException { final RemoteOperation operation = RemoteOperation.parseFrom(payload); return new VvrDtxRmContext(resourceManagerId, operation); } }