blob: bef8e4e4a3ebed3bab01a83c0039a835a623ea49 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2008, 2021 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.rj.server;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.statet.rj.data.RJIO;
import org.eclipse.statet.rj.data.RObject;
import org.eclipse.statet.rj.data.RObjectFactory;
import org.eclipse.statet.rj.data.impl.DefaultRObjectFactory;
/**
* Command item for main loop data exchange/evaluation
*/
public final class DataCmdItem extends MainCmdItem {
public static final class Operation {
public static final byte NONE= 0;
public static final byte EXPR= 1;
public static final byte POINTER= 2;
public static final byte FCALL= 3;
public static final byte RDATA= 4;
public final byte op;
public final String name;
public final byte source;
public final byte target;
public final boolean returnData;
private final boolean reqSourceExpr;
private final boolean reqRData;
private final boolean reqTargetExpr;
private Operation(final int op, final String name,
final byte source, final byte target, final boolean returnData) {
this.op= (byte)op;
this.name= name;
this.source= source;
this.target= target;
this.returnData= returnData;
this.reqSourceExpr= (source == EXPR || source == POINTER || source == FCALL);
this.reqRData= (source == FCALL || source == RDATA);
this.reqTargetExpr= (target == EXPR || target == POINTER);
}
@Override
public String toString() {
return this.name;
}
}
public static final byte EVAL_EXPR_VOID_OP= 0x01;
public static final Operation EVAL_EXPR_VOID= new Operation(EVAL_EXPR_VOID_OP, "EVAL_EXPR_VOID", //$NON-NLS-1$
Operation.EXPR, Operation.NONE, false );
public static final byte EVAL_FCALL_VOID_OP= 0x02;
public static final Operation EVAL_FCALL_VOID= new Operation(EVAL_FCALL_VOID_OP, "EVAL_FCALL_VOID", //$NON-NLS-1$
Operation.FCALL, Operation.NONE, false );
public static final byte EVAL_EXPR_DATA_OP= 0x03;
public static final Operation EVAL_EXPR_DATA= new Operation(EVAL_EXPR_DATA_OP, "EVAL_EXPR_DATA", //$NON-NLS-1$
Operation.EXPR, Operation.NONE, true );
public static final byte EVAL_FCALL_DATA_OP= 0x04;
public static final Operation EVAL_FCALL_DATA= new Operation(EVAL_FCALL_DATA_OP, "EVAL_FCALL_DATA", //$NON-NLS-1$
Operation.FCALL, Operation.NONE, true );
public static final byte RESOLVE_DATA_OP= 0x05;
public static final Operation RESOLVE_DATA= new Operation(RESOLVE_DATA_OP, "RESOLVE_DATA", // EVAL_REF_DATA //$NON-NLS-1$
Operation.POINTER, Operation.NONE, true );
public static final byte ASSIGN_DATA_OP= 0x06;
public static final Operation ASSIGN_DATA= new Operation(ASSIGN_DATA_OP, "ASSIGN_DATA", //$NON-NLS-1$
Operation.RDATA, Operation.EXPR, false );
public static final byte ASSIGN_FCALL_OP= 0x07;
public static final Operation ASSIGN_FCALL= new Operation(ASSIGN_FCALL_OP, "ASSIGN_FCALL", //$NON-NLS-1$
Operation.FCALL, Operation.EXPR, false );
public static final byte FIND_DATA_OP= 0x08;
public static final Operation FIND_DATA= new Operation(FIND_DATA_OP, "FIND_DATA", //$NON-NLS-1$
Operation.EXPR, Operation.NONE, true );
public static final byte EVAL_NAMESPACE_DATA_OP= 0x09;
public static final Operation EVAL_NAMESPACE_DATA= new Operation(EVAL_NAMESPACE_DATA_OP, "EVAL_NAMESPACE_DATA", //$NON-NLS-1$
Operation.EXPR, Operation.NONE, true );
public static final byte EVAL_NAMESPACE_EXPORTS_DATA_OP= 0x0A;
public static final Operation EVAL_NAMESPACE_EXPORTS_DATA= new Operation(EVAL_NAMESPACE_EXPORTS_DATA_OP, "EVAL_NAMESPACE_EXPORTS_DATA", //$NON-NLS-1$
Operation.EXPR, Operation.NONE, true );
private static final Operation[] OPERATIONS= new Operation[11];
private static final void addOp(final Operation operation) {
if (OPERATIONS[operation.op] != null) {
throw new IllegalArgumentException();
}
OPERATIONS[operation.op]= operation;
}
private static final Operation getOperation(final byte op) {
if (op <= 0 || op >= OPERATIONS.length) {
throw new UnsupportedOperationException("data op: " + op); //$NON-NLS-1$
}
return OPERATIONS[op];
}
static {
addOp(EVAL_EXPR_VOID);
addOp(EVAL_FCALL_VOID);
addOp(EVAL_EXPR_DATA);
addOp(EVAL_FCALL_DATA);
addOp(RESOLVE_DATA);
addOp(ASSIGN_DATA);
addOp(ASSIGN_FCALL);
addOp(FIND_DATA);
addOp(EVAL_NAMESPACE_DATA);
addOp(EVAL_NAMESPACE_EXPORTS_DATA);
}
private static final int OV_WITHDATA= 0x02000000;
private static final int OV_WITHRHO= 0x04000000;
private static final int OV_WITHSTATUS= 0x08000000;
public static final String DEFAULT_FACTORY_ID= "default"; //$NON-NLS-1$
static RObjectFactory gDefaultFactory;
static final Map<String, RObjectFactory> gFactories= new ConcurrentHashMap<>();
private static final RObjectFactory getFactory(final String id) {
final RObjectFactory factory= gFactories.get(id);
if (factory != null) {
return factory;
}
return gDefaultFactory;
}
static {
RjsComConfig.setDefaultRObjectFactory(DefaultRObjectFactory.INSTANCE);
}
private static int checkCustomOptions(final int options) {
if ((options & (RObjectFactory.F_WITH_DBG | RObjectFactory.F_ONLY_STRUCT)) == (RObjectFactory.F_WITH_DBG | RObjectFactory.F_ONLY_STRUCT)) {
throw new IllegalArgumentException("options: RObjectFactory.F_LOAD_DBG & RObjectFactory.F_ONLY_STRUCT");
}
return (options & OM_CUSTOM);
}
private final Operation operation;
private byte depth;
private String sourceExpr;
private String targetExpr;
private RObject rdata;
private RObject rho;
private String factoryId;
private RjsStatus status;
/**
* Constructor for operations with returned data
*/
public DataCmdItem(final Operation op, final int options, final byte depth,
final String sourceExpr, final RObject data, final String targetExpr,
final RObject rho,
final String factoryId) {
assert (op.reqSourceExpr == (sourceExpr != null));
assert (op.reqRData == (data != null));
assert (op.reqTargetExpr == (targetExpr != null));
assert (factoryId == null || gFactories.containsKey(factoryId));
this.operation= op;
this.sourceExpr= sourceExpr;
this.targetExpr= targetExpr;
this.options= (OV_WAITFORCLIENT | checkCustomOptions(options));
if (data != null) {
this.rdata= data;
this.options |= OV_WITHDATA;
}
if (rho != null) {
this.rho= rho;
this.options |= OV_WITHRHO;
}
this.depth= depth;
this.factoryId= (factoryId != null) ? factoryId : DEFAULT_FACTORY_ID;
}
/**
* Constructor for operations without returned data:
*/
public DataCmdItem(final Operation op, final int options,
final String sourceExpr, final RObject data, final String targetExpr,
final RObject rho) {
assert (op.reqSourceExpr == (sourceExpr != null));
assert (op.reqRData == (data != null));
assert (op.reqTargetExpr == (targetExpr != null));
this.operation= op;
this.sourceExpr= sourceExpr;
this.targetExpr= targetExpr;
this.options= (OV_WAITFORCLIENT | checkCustomOptions(options));
if (data != null) {
this.rdata= data;
this.options |= OV_WITHDATA;
}
if (rho != null) {
this.rho= rho;
this.options |= OV_WITHRHO;
}
this.factoryId= "";
}
/**
* Constructor for deserialization
*/
public DataCmdItem(final RJIO in) throws IOException {
this.requestId= in.readInt();
this.operation= getOperation(in.readByte());
this.options= in.readInt();
if ((this.options & OV_WITHSTATUS) != 0) {
this.status= new RjsStatus(in);
return;
}
this.depth= in.readByte();
this.factoryId= in.readString();
if ((this.options & OV_ANSWER) == 0) { // request
if (this.operation.reqSourceExpr) {
this.sourceExpr= in.readString();
}
if (this.operation.reqRData) {
in.flags= 0;
this.rdata= gDefaultFactory.readObject(in);
}
if (this.operation.reqTargetExpr) {
this.targetExpr= in.readString();
}
if ((this.options & OV_WITHRHO) != 0) {
in.flags= 0;
this.rho= gDefaultFactory.readObject(in);
}
}
else { // answer
if ((this.options & OV_WITHDATA) != 0) {
in.flags= (this.options & 0xff);
this.rdata= getFactory(this.factoryId).readObject(in);
}
if ((this.options & OV_WITHRHO) != 0) {
in.flags= RObjectFactory.F_ONLY_STRUCT;
this.rho= getFactory(this.factoryId).readObject(in);
}
}
}
@Override
public void writeExternal(final RJIO out) throws IOException {
out.writeInt(this.requestId);
out.writeByte(this.operation.op);
out.writeInt(this.options);
if ((this.options & OV_WITHSTATUS) != 0) {
this.status.writeExternal(out);
return;
}
out.writeByte(this.depth);
out.writeString(this.factoryId);
if ((this.options & OV_ANSWER) == 0) { // request
if (this.operation.reqSourceExpr) {
out.writeString(this.sourceExpr);
}
if (this.operation.reqRData) {
out.flags= 0;
gDefaultFactory.writeObject(this.rdata, out);
}
if (this.operation.reqTargetExpr) {
out.writeString(this.targetExpr);
}
if ((this.options & OV_WITHRHO) != 0) {
out.flags= 0;
gDefaultFactory.writeObject(this.rho, out);
}
}
else { // anwser
if ((this.options & OV_WITHDATA) != 0) {
out.flags= (this.options & 0xff);
gDefaultFactory.writeObject(this.rdata, out);
}
if ((this.options & OV_WITHRHO) != 0) {
out.flags= RObjectFactory.F_ONLY_STRUCT;
gDefaultFactory.writeObject(this.rho, out);
}
}
}
@Override
public byte getCmdType() {
return T_DATA_ITEM;
}
@Override
public void setAnswer(final RjsStatus status) {
assert (status != null);
if (status == RjsStatus.OK_STATUS) {
this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
this.status= null;
this.sourceExpr= null;
this.rdata= null;
this.targetExpr= null;
this.rho= null;
}
else {
this.options= ((this.options & OM_CLEARFORANSWER) | (OV_ANSWER | OV_WITHSTATUS));
this.status= status;
this.sourceExpr= null;
this.rdata= null;
this.targetExpr= null;
this.rho= null;
}
}
public void setAnswer(final RObject rdata, final RObject rho) {
this.options= ((this.options & OM_CLEARFORANSWER) | OV_ANSWER);
if (rdata != null) {
this.options |= OV_WITHDATA;
}
if (rho != null) {
this.options |= OV_WITHRHO;
}
this.status= null;
this.sourceExpr= null;
this.rdata= rdata;
this.targetExpr= null;
this.rho= rho;
}
@Override
public byte getOp() {
return this.operation.op;
}
public Operation getOperation() {
return this.operation;
}
@Override
public boolean isOK() {
return (this.status == null || this.status.getSeverity() == RjsStatus.OK);
}
@Override
public RjsStatus getStatus() {
return this.status;
}
@Override
public String getDataText() {
return this.sourceExpr;
}
public RObject getData() {
return this.rdata;
}
public String getTargetExpr() {
return this.targetExpr;
}
public RObject getRho() {
return this.rho;
}
public byte getDepth() {
return this.depth;
}
@Override
public boolean testEquals(final MainCmdItem other) {
if (other instanceof DataCmdItem) {
final DataCmdItem otherItem= (DataCmdItem) other;
if (getOp() != otherItem.getOp()) {
return false;
}
if (this.options != otherItem.options) {
return false;
}
if (!((this.sourceExpr != null) ?
this.sourceExpr.equals(otherItem.sourceExpr) :
null == otherItem.sourceExpr )) {
return false;
}
if (!((this.rdata != null) ?
this.rdata.equals(otherItem.rdata) :
null == otherItem.rdata )) {
return false;
}
if (!((this.targetExpr != null) ?
this.targetExpr.equals(otherItem.targetExpr) :
null == otherItem.targetExpr )) {
return false;
}
if (!((this.rho != null) ?
this.rho.equals(otherItem.rho) :
null == otherItem.rho )) {
return false;
}
return true;
}
return false;
}
@Override
public String toString() {
final StringBuffer sb= new StringBuffer(100);
sb.append("DataCmdItem ");
sb.append(this.operation.name);
sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
if (this.sourceExpr != null) {
sb.append("\n<SOURCE-EXPR>\n");
sb.append(this.sourceExpr);
sb.append("\n</SOURCE-EXPR>");
}
else {
sb.append("\n<SOURCE-EXPR/>");
}
if ((this.options & OV_WITHDATA) != 0) {
sb.append("\n<DATA>\n");
sb.append(this.rdata);
sb.append("\n</DATA>");
}
else {
sb.append("\n<DATA/>");
}
if (this.targetExpr != null) {
sb.append("\n<TARGET-EXPR>\n");
sb.append(this.targetExpr);
sb.append("\n</TARGET-EXPR>");
}
else {
sb.append("\n<TARGET-EXPR/>");
}
if ((this.options & OV_WITHRHO) != 0) {
sb.append("\n<RHO>\n");
sb.append(this.rho);
sb.append("\n</RHO>");
}
if ((this.options & OV_WITHSTATUS) != 0) {
sb.append("\n<STATUS>\n");
sb.append(this.status);
sb.append("\n</STATUS>");
}
return sb.toString();
}
}