/* * Copyright (c) 2013-2017 Cinchapi 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.cinchapi.concourse.server.plugin; import io.atomix.catalyst.buffer.Buffer; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; import javax.annotation.concurrent.Immutable; import com.cinchapi.concourse.annotate.PackagePrivate; import com.cinchapi.concourse.thrift.AccessToken; import com.cinchapi.concourse.thrift.ComplexTObject; import com.cinchapi.concourse.thrift.TransactionToken; import com.google.common.collect.Lists; import com.google.common.collect.Maps; /** * A message that is sent from one process to another via a * {@link InterProcessCommunication} segment with a request to invoke a remote * method. * * @author Jeff Nelson */ @Immutable @PackagePrivate final class RemoteMethodRequest extends RemoteMessage { /** * The non-thrift arguments to pass to the method. */ public List<ComplexTObject> args; /** * The credentials for the session that is making the request. */ public AccessToken creds; /** * The session's current environment. */ public String environment; /** * The name of the method to invoke. */ public String method; /** * The session's current transaction token. */ public TransactionToken transaction; /** * Construct a new instance. * * @param method * @param creds * @param transaction * @param environment * @param args */ public RemoteMethodRequest(String method, AccessToken creds, TransactionToken transaction, String environment, ComplexTObject... args) { this(method, creds, transaction, environment, Arrays.asList(args)); } /** * Construct a new instance. * * @param method * @param creds * @param transaction * @param environment * @param args */ public RemoteMethodRequest(String method, AccessToken creds, TransactionToken transaction, String environment, List<ComplexTObject> args) { this.method = method; this.creds = creds; this.transaction = transaction; this.environment = environment; this.args = args; } /** * DO NOT CALL. Only here for deserialization. */ RemoteMethodRequest() {/* no-op */} @Override public void deserialize(Buffer buffer) { this.method = buffer.readUTF8(); byte[] creds0 = new byte[buffer.readInt()]; buffer.read(creds0); this.creds = new AccessToken(ByteBuffer.wrap(creds0)); boolean transaction0 = buffer.readByte() == 1 ? true : false; this.transaction = null; if(transaction0) { long timestamp = buffer.readLong(); this.transaction = new TransactionToken(creds, timestamp); } this.environment = buffer.readUTF8(); this.args = Lists.newArrayList(); while (buffer.hasRemaining()) { int length = buffer.readInt(); byte[] arg = new byte[length]; buffer.read(arg); args.add(ComplexTObject.fromByteBuffer(ByteBuffer.wrap(arg))); } } @Override public boolean equals(Object obj) { if(obj instanceof RemoteMethodRequest) { return Objects.equals(args, ((RemoteMethodRequest) obj).args) && Objects.equals(creds, ((RemoteMethodRequest) obj).creds) && Objects.equals(environment, ((RemoteMethodRequest) obj).environment) && Objects.equals(method, ((RemoteMethodRequest) obj).method) && Objects.equals(transaction, ((RemoteMethodRequest) obj).transaction); } else { return false; } } @Override public int hashCode() { return Objects.hash(args, creds, environment, method, transaction); } @Override public String toString() { Map<String, Object> data = Maps.newHashMap(); data.put("method", method); data.put("args", args); data.put("creds", creds); data.put("transaction", transaction); data.put("environment", environment); return data.toString(); } @Override public Type type() { return Type.REQUEST; } @Override protected void serialize(Buffer buffer) { buffer.writeUTF8(method); byte[] creds = this.creds.getData(); buffer.writeInt(creds.length); buffer.write(creds); buffer.writeBoolean(transaction != null); if(transaction != null) { buffer.writeLong(transaction.getTimestamp()); // NOTE: Will need the AccessToken to re-create the // TransactionToken, but there is no need to re-write it since it // was previously written } buffer.writeUTF8(environment); args.forEach((arg) -> { ByteBuffer bytes = arg.toByteBuffer(); buffer.writeInt(bytes.remaining()); buffer.write(bytes.array()); }); } }