http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1b0e45a2/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridClientTaskResultBean.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridClientTaskResultBean.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridClientTaskResultBean.java new file mode 100644 index 0000000..dbd18fd --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridClientTaskResultBean.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.rest.client.message; + +import org.apache.ignite.internal.util.portable.*; +import org.apache.ignite.portables.*; +import org.apache.ignite.internal.util.typedef.internal.*; + +import java.io.*; + +/** + * Task result. + */ +public class GridClientTaskResultBean implements Externalizable, PortableMarshalAware { + /** */ + private static final long serialVersionUID = 0L; + + /** Synthetic ID containing task ID and result holding node ID. */ + private String id; + + /** Execution finished flag. */ + private boolean finished; + + /** Result. */ + private Object res; + + /** Error if any occurs while execution. */ + private String error; + + /** + * @return Task ID. + */ + public String getId() { + return id; + } + + /** + * @param id Task ID. + */ + public void setId(String id) { + this.id = id; + } + + /** + * @return {@code true} if execution finished. + */ + public boolean isFinished() { + return finished; + } + + /** + * @param finished {@code true} if execution finished. + */ + public void setFinished(boolean finished) { + this.finished = finished; + } + + /** + * @return Task result. + */ + @SuppressWarnings("unchecked") + public <R> R getResult() { + return (R)res; + } + + /** + * @param res Task result. + */ + public void setResult(Object res) { + this.res = res; + } + + /** + * @return Error. + */ + public String getError() { + return error; + } + + /** + * @param error Error. + */ + public void setError(String error) { + this.error = error; + } + + /** {@inheritDoc} */ + @Override public void writePortable(PortableWriter writer) throws PortableException { + PortableRawWriterEx raw = (PortableRawWriterEx)writer.rawWriter(); + + raw.writeString(id); + raw.writeBoolean(finished); + + raw.writeObject(res); + + raw.writeString(error); + } + + /** {@inheritDoc} */ + @Override public void readPortable(PortableReader reader) throws PortableException { + PortableRawReaderEx raw = (PortableRawReaderEx)reader.rawReader(); + + id = raw.readString(); + finished = raw.readBoolean(); + + res = raw.readObject(); + + error = raw.readString(); + } + + /** {@inheritDoc} */ + @Override public void writeExternal(ObjectOutput out) throws IOException { + U.writeString(out, id); + out.writeBoolean(finished); + out.writeObject(res); + U.writeString(out, error); + } + + /** {@inheritDoc} */ + @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + id = U.readString(in); + finished = in.readBoolean(); + res = in.readObject(); + error = U.readString(in); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return getClass().getSimpleName() + " [res=" + res + ", error=" + error + + ", finished=" + finished + ", id=" + id + "]"; + } +}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1b0e45a2/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridClientTopologyRequest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridClientTopologyRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridClientTopologyRequest.java new file mode 100644 index 0000000..9c87c63 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridClientTopologyRequest.java @@ -0,0 +1,174 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.rest.client.message; + +import org.apache.ignite.portables.*; +import org.apache.ignite.internal.util.typedef.internal.*; + +import java.io.*; +import java.util.*; + +/** + * {@code Topology} command request. + */ +public class GridClientTopologyRequest extends GridClientAbstractMessage { + /** */ + private static final long serialVersionUID = 0L; + + /** Id of requested node. */ + private UUID nodeId; + + /** IP address of requested node. */ + private String nodeIp; + + /** Include metrics flag. */ + private boolean includeMetrics; + + /** Include node attributes flag. */ + private boolean includeAttrs; + + /** + * @return Include metrics flag. + */ + public boolean includeMetrics() { + return includeMetrics; + } + + /** + * @param includeMetrics Include metrics flag. + */ + public void includeMetrics(boolean includeMetrics) { + this.includeMetrics = includeMetrics; + } + + /** + * @return Include node attributes flag. + */ + public boolean includeAttributes() { + return includeAttrs; + } + + /** + * @param includeAttrs Include node attributes flag. + */ + public void includeAttributes(boolean includeAttrs) { + this.includeAttrs = includeAttrs; + } + + /** + * @return Node identifier, if specified, {@code null} otherwise. + */ + public UUID nodeId() { + return nodeId; + } + + /** + * @param nodeId Node identifier to lookup. + */ + public void nodeId(UUID nodeId) { + this.nodeId = nodeId; + } + + /** + * @return Node ip address if specified, {@code null} otherwise. + */ + public String nodeIp() { + return nodeIp; + } + + /** + * @param nodeIp Node ip address to lookup. + */ + public void nodeIp(String nodeIp) { + this.nodeIp = nodeIp; + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object o) { + if (this == o) + return true; + + if (o == null || getClass() != o.getClass()) + return false; + + GridClientTopologyRequest other = (GridClientTopologyRequest)o; + + return includeAttrs == other.includeAttrs && + includeMetrics == other.includeMetrics; + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + return 31 * (includeMetrics ? 1 : 0) + + (includeAttrs ? 1 : 0); + } + + /** {@inheritDoc} */ + @Override public void writePortable(PortableWriter writer) throws PortableException { + super.writePortable(writer); + + PortableRawWriter raw = writer.rawWriter(); + + raw.writeUuid(nodeId); + raw.writeString(nodeIp); + raw.writeBoolean(includeMetrics); + raw.writeBoolean(includeAttrs); + } + + /** {@inheritDoc} */ + @Override public void readPortable(PortableReader reader) throws PortableException { + super.readPortable(reader); + + PortableRawReader raw = reader.rawReader(); + + nodeId = raw.readUuid(); + nodeIp = raw.readString(); + includeMetrics = raw.readBoolean(); + includeAttrs = raw.readBoolean(); + } + + /** {@inheritDoc} */ + @Override public void writeExternal(ObjectOutput out) throws IOException { + super.writeExternal(out); + + U.writeUuid(out, nodeId); + + U.writeString(out, nodeIp); + + out.writeBoolean(includeMetrics); + out.writeBoolean(includeAttrs); + } + + /** {@inheritDoc} */ + @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + super.readExternal(in); + + nodeId = U.readUuid(in); + + nodeIp = U.readString(in); + + includeMetrics = in.readBoolean(); + includeAttrs = in.readBoolean(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return getClass().getSimpleName() + " [includeMetrics=" + includeMetrics + + ", includeAttrs=" + includeAttrs + "]"; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1b0e45a2/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridRouterRequest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridRouterRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridRouterRequest.java new file mode 100644 index 0000000..34efcf6 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridRouterRequest.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.rest.client.message; + +import java.util.*; + +/** + * Container for routed message information. + */ +public class GridRouterRequest extends GridClientAbstractMessage { + /** */ + private static final long serialVersionUID = 0L; + + /** Raw message. */ + private final byte[] body; + + /** + * @param body Message in raw form. + * @param clientId Client id. + * @param reqId Request id. + * @param destId Destination where this message should be delivered. + */ + public GridRouterRequest(byte[] body, Long reqId, UUID clientId, UUID destId) { + this.body = body; + destinationId(destId); + clientId(clientId); + requestId(reqId); + } + + /** + * @return Raw message. + */ + public byte[] body() { + return body; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "GridRouterRequest [clientId=" + clientId() + ", reqId=" + requestId() + ", " + + "destId=" + destinationId() + ", length=" + body.length + "]"; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1b0e45a2/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridRouterResponse.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridRouterResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridRouterResponse.java new file mode 100644 index 0000000..ce5104c --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/GridRouterResponse.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.rest.client.message; + +import java.util.*; + +/** + * + */ +public class GridRouterResponse extends GridClientAbstractMessage { + /** */ + private static final long serialVersionUID = 0L; + + /** Raw message. */ + private final byte[] body; + + /** Error message. */ + private final String errMsg; + + /** Status. */ + private final int status; + + /** + * @param body Message in raw form. + * @param clientId Client id. + * @param reqId Request id. + * @param destId Destination where this message should be delivered. + */ + public GridRouterResponse(byte[] body, Long reqId, UUID clientId, UUID destId) { + this.body = body; + errMsg = null; + status = GridClientResponse.STATUS_SUCCESS; + + destinationId(destId); + clientId(clientId); + requestId(reqId); + } + + /** + * @return Response body. + */ + public byte[] body() { + return body; + } + + /** + * @return Error message. + */ + public String errorMessage() { + return errMsg; + } + + /** + * @return Status. + */ + public int status() { + return status; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "GridRoutedResponse [" + + "clientId=" + clientId() + + ", reqId=" + requestId() + + ", destId=" + destinationId() + + ", status=" + status + + ", errMsg=" + errorMessage() + "]"; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1b0e45a2/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/package.html ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/package.html b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/package.html new file mode 100644 index 0000000..9cf3550 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/client/message/package.html @@ -0,0 +1,23 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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. + --> +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<body> +<!-- Package description. --> + Defines messages that are used in binary TCP communication between GridGain clients and nodes. +</body> +</html> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1b0e45a2/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/GridRestCommandHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/GridRestCommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/GridRestCommandHandler.java new file mode 100644 index 0000000..1f585ce --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/GridRestCommandHandler.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.rest.handlers; + +import org.apache.ignite.lang.*; +import org.apache.ignite.internal.processors.rest.*; +import org.apache.ignite.internal.processors.rest.request.*; + +import java.util.*; + +/** + * Command handler. + */ +public interface GridRestCommandHandler { + /** + * @return Collection of supported commands. + */ + public Collection<GridRestCommand> supportedCommands(); + + /** + * @param req Request. + * @return Future. + */ + public IgniteFuture<GridRestResponse> handleAsync(GridRestRequest req); +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1b0e45a2/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/GridRestCommandHandlerAdapter.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/GridRestCommandHandlerAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/GridRestCommandHandlerAdapter.java new file mode 100644 index 0000000..2fd0f2d --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/GridRestCommandHandlerAdapter.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.rest.handlers; + +import org.apache.ignite.*; +import org.apache.ignite.internal.*; + +/** + * Abstract command handler. + */ +public abstract class GridRestCommandHandlerAdapter implements GridRestCommandHandler { + /** Kernal context. */ + protected final GridKernalContext ctx; + + /** Log. */ + protected final IgniteLogger log; + + /** + * @param ctx Context. + */ + protected GridRestCommandHandlerAdapter(GridKernalContext ctx) { + this.ctx = ctx; + + log = ctx.log(getClass()); + } + + /** + * Return missing parameter error message. + * + * @param param Parameter name. + * @return Missing parameter error message. + */ + protected static String missingParameter(String param) { + return "Failed to find mandatory parameter in request: " + param; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1b0e45a2/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheClientQueryResult.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheClientQueryResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheClientQueryResult.java new file mode 100644 index 0000000..fc845c4 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheClientQueryResult.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.rest.handlers.cache; + +import org.apache.ignite.portables.*; + +import java.io.Serializable; +import java.util.*; + +/** + * Client query result. + */ +public class GridCacheClientQueryResult implements PortableMarshalAware, Serializable { + /** */ + private static final long serialVersionUID = 0L; + + /** Query ID. */ + private long qryId; + + /** Result items. */ + private Collection<?> items; + + /** Last flag. */ + private boolean last; + + /** Node ID. */ + private UUID nodeId; + + /** + * @return Query ID. + */ + public long queryId() { + return qryId; + } + + /** + * @param qryId Query ID. + */ + public void queryId(long qryId) { + this.qryId = qryId; + } + + /** + * @return Items. + */ + public Collection<?> items() { + return items; + } + + /** + * @param items Items. + */ + public void items(Collection<?> items) { + this.items = items; + } + + /** + * @return Last flag. + */ + public boolean last() { + return last; + } + + /** + * @param last Last flag. + */ + public void last(boolean last) { + this.last = last; + } + + /** + * @return Node ID. + */ + public UUID nodeId() { + return nodeId; + } + + /** + * @param nodeId Node ID. + */ + public void nodeId(UUID nodeId) { + this.nodeId = nodeId; + } + + /** {@inheritDoc} */ + @Override public void writePortable(PortableWriter writer) throws PortableException { + PortableRawWriter rawWriter = writer.rawWriter(); + + rawWriter.writeBoolean(last); + rawWriter.writeLong(qryId); + rawWriter.writeUuid(nodeId); + rawWriter.writeCollection(items); + } + + /** {@inheritDoc} */ + @Override public void readPortable(PortableReader reader) throws PortableException { + PortableRawReader rawReader = reader.rawReader(); + + last = rawReader.readBoolean(); + qryId = rawReader.readLong(); + nodeId = rawReader.readUuid(); + items = rawReader.readCollection(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1b0e45a2/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java new file mode 100644 index 0000000..43dff3b --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java @@ -0,0 +1,1149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.rest.handlers.cache; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.apache.ignite.cache.datastructures.*; +import org.apache.ignite.cluster.*; +import org.apache.ignite.internal.*; +import org.apache.ignite.lang.*; +import org.apache.ignite.resources.*; +import org.apache.ignite.transactions.*; +import org.gridgain.grid.kernal.processors.cache.*; +import org.apache.ignite.internal.processors.license.*; +import org.apache.ignite.internal.processors.rest.*; +import org.apache.ignite.internal.processors.rest.handlers.*; +import org.apache.ignite.internal.processors.rest.request.*; +import org.apache.ignite.internal.processors.task.*; +import org.apache.ignite.internal.util.future.*; +import org.apache.ignite.internal.util.lang.*; +import org.apache.ignite.internal.util.typedef.*; +import org.apache.ignite.internal.util.typedef.internal.*; +import org.jetbrains.annotations.*; + +import javax.cache.expiry.*; +import java.io.*; +import java.util.*; +import java.util.concurrent.*; + +import static java.util.concurrent.TimeUnit.*; +import static org.apache.ignite.transactions.IgniteTxConcurrency.*; +import static org.apache.ignite.transactions.IgniteTxIsolation.*; +import static org.apache.ignite.internal.processors.rest.GridRestCommand.*; +import static org.apache.ignite.internal.processors.license.GridLicenseSubsystem.*; + +/** + * Command handler for API requests. + */ +public class GridCacheCommandHandler extends GridRestCommandHandlerAdapter { + /** Supported commands. */ + private static final Collection<GridRestCommand> SUPPORTED_COMMANDS = U.sealList( + CACHE_GET, + CACHE_GET_ALL, + CACHE_PUT, + CACHE_ADD, + CACHE_PUT_ALL, + CACHE_REMOVE, + CACHE_REMOVE_ALL, + CACHE_REPLACE, + CACHE_INCREMENT, + CACHE_DECREMENT, + CACHE_CAS, + CACHE_APPEND, + CACHE_PREPEND, + CACHE_METRICS + ); + + /** Requests with required parameter {@code key}. */ + private static final EnumSet<GridRestCommand> KEY_REQUIRED_REQUESTS = EnumSet.of( + CACHE_GET, + CACHE_PUT, + CACHE_ADD, + CACHE_REMOVE, + CACHE_REPLACE, + CACHE_INCREMENT, + CACHE_DECREMENT, + CACHE_CAS, + CACHE_APPEND, + CACHE_PREPEND + ); + + /** */ + private static final GridCacheFlag[] EMPTY_FLAGS = new GridCacheFlag[0]; + + /** + * @param ctx Context. + */ + public GridCacheCommandHandler(GridKernalContext ctx) { + super(ctx); + } + + /** {@inheritDoc} */ + @Override public Collection<GridRestCommand> supportedCommands() { + return SUPPORTED_COMMANDS; + } + + /** + * Retrieves cache flags from corresponding bits. + * + * @param cacheFlagsBits Integer representation of cache flags bit set. + * @return Array of cache flags. + */ + public static GridCacheFlag[] parseCacheFlags(int cacheFlagsBits) { + if (cacheFlagsBits == 0) + return EMPTY_FLAGS; + + EnumSet<GridCacheFlag> flagSet = EnumSet.noneOf(GridCacheFlag.class); + + if ((cacheFlagsBits & 1) != 0) + flagSet.add(GridCacheFlag.SKIP_STORE); + + if ((cacheFlagsBits & (1 << 1)) != 0) + flagSet.add(GridCacheFlag.SKIP_SWAP); + + if ((cacheFlagsBits & (1 << 2)) != 0) + flagSet.add(GridCacheFlag.SYNC_COMMIT); + + if ((cacheFlagsBits & (1 << 4)) != 0) + flagSet.add(GridCacheFlag.INVALIDATE); + + return flagSet.toArray(new GridCacheFlag[flagSet.size()]); + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<GridRestResponse> handleAsync(final GridRestRequest req) { + assert req instanceof GridRestCacheRequest : "Invalid command for topology handler: " + req; + + assert SUPPORTED_COMMANDS.contains(req.command()); + + GridLicenseUseRegistry.onUsage(DATA_GRID, getClass()); + + if (log.isDebugEnabled()) + log.debug("Handling cache REST request: " + req); + + GridRestCacheRequest req0 = (GridRestCacheRequest)req; + + final String cacheName = req0.cacheName(); + + final Object key = req0.key(); + + final GridCacheFlag[] flags = parseCacheFlags(req0.cacheFlags()); + + try { + GridRestCommand cmd = req0.command(); + + if (key == null && KEY_REQUIRED_REQUESTS.contains(cmd)) + throw new IgniteCheckedException(GridRestCommandHandlerAdapter.missingParameter("key")); + + final Long ttl = req0.ttl(); + + IgniteFuture<GridRestResponse> fut; + + switch (cmd) { + case CACHE_GET: { + fut = executeCommand(req.destinationId(), req.clientId(), cacheName, flags, key, + new GetCommand(key), req.portableMode()); + + break; + } + + case CACHE_GET_ALL: { + Set<Object> keys = req0.values().keySet(); + + if (F.isEmpty(keys)) + throw new IgniteCheckedException(GridRestCommandHandlerAdapter.missingParameter("keys")); + + // HashSet wrapping for correct serialization + keys = new HashSet<>(keys); + + fut = executeCommand(req.destinationId(), req.clientId(), cacheName, flags, key, + new GetAllCommand(keys), req.portableMode()); + + break; + } + + case CACHE_PUT: { + final Object val = req0.value(); + + if (val == null) + throw new IgniteCheckedException(GridRestCommandHandlerAdapter.missingParameter("val")); + + fut = executeCommand(req.destinationId(), req.clientId(), cacheName, flags, key, new + PutCommand(key, ttl, val), req.portableMode()); + + break; + } + + case CACHE_ADD: { + final Object val = req0.value(); + + if (val == null) + throw new IgniteCheckedException(GridRestCommandHandlerAdapter.missingParameter("val")); + + fut = executeCommand(req.destinationId(), req.clientId(), cacheName, flags, key, + new AddCommand(key, ttl, val), req.portableMode()); + + break; + } + + case CACHE_PUT_ALL: { + Map<Object, Object> map = req0.values(); + + if (F.isEmpty(map)) + throw new IgniteCheckedException(GridRestCommandHandlerAdapter.missingParameter("values")); + + for (Map.Entry<Object, Object> e : map.entrySet()) { + if (e.getKey() == null) + throw new IgniteCheckedException("Failing putAll operation (null keys are not allowed)."); + + if (e.getValue() == null) + throw new IgniteCheckedException("Failing putAll operation (null values are not allowed)."); + } + + // HashMap wrapping for correct serialization + map = new HashMap<>(map); + + fut = executeCommand(req.destinationId(), req.clientId(), cacheName, flags, key, + new PutAllCommand(map), req.portableMode()); + + break; + } + + case CACHE_REMOVE: { + fut = executeCommand(req.destinationId(), req.clientId(), cacheName, flags, key, + new RemoveCommand(key), req.portableMode()); + + break; + } + + case CACHE_REMOVE_ALL: { + Map<Object, Object> map = req0.values(); + + // HashSet wrapping for correct serialization + Set<Object> keys = map == null ? null : new HashSet<>(map.keySet()); + + fut = executeCommand(req.destinationId(), req.clientId(), cacheName, flags, key, + new RemoveAllCommand(keys), req.portableMode()); + + break; + } + + case CACHE_REPLACE: { + final Object val = req0.value(); + + if (val == null) + throw new IgniteCheckedException(GridRestCommandHandlerAdapter.missingParameter("val")); + + fut = executeCommand(req.destinationId(), req.clientId(), cacheName, flags, key, + new ReplaceCommand(key, ttl, val), req.portableMode()); + + break; + } + + case CACHE_INCREMENT: { + fut = executeCommand(req.destinationId(), req.clientId(), cacheName, key, + new IncrementCommand(key, req0)); + + break; + } + + case CACHE_DECREMENT: { + fut = executeCommand(req.destinationId(), req.clientId(), cacheName, key, + new DecrementCommand(key, req0)); + + break; + } + + case CACHE_CAS: { + final Object val1 = req0.value(); + final Object val2 = req0.value2(); + + fut = executeCommand(req.destinationId(), req.clientId(), cacheName, flags, key, + new CasCommand(val2, val1, key), req.portableMode()); + + break; + } + + case CACHE_APPEND: { + fut = executeCommand(req.destinationId(), req.clientId(), cacheName, flags, key, + new AppendCommand(key, req0), req.portableMode()); + + break; + } + + case CACHE_PREPEND: { + fut = executeCommand(req.destinationId(), req.clientId(), cacheName, flags, key, + new PrependCommand(key, req0), req.portableMode()); + + break; + } + + case CACHE_METRICS: { + fut = executeCommand(req.destinationId(), req.clientId(), cacheName, key, new MetricsCommand()); + + break; + } + + default: + throw new IllegalArgumentException("Invalid command for cache handler: " + req); + } + + return fut; + } + catch (IgniteException e) { + U.error(log, "Failed to execute cache command: " + req, e); + + return new GridFinishedFuture<>(ctx, e); + } + catch (IgniteCheckedException e) { + U.error(log, "Failed to execute cache command: " + req, e); + + return new GridFinishedFuture<>(ctx, e); + } + finally { + if (log.isDebugEnabled()) + log.debug("Handled cache REST request: " + req); + } + } + + /** + * Executes command on flagged cache projection. Checks {@code destId} to find + * if command could be performed locally or routed to a remote node. + * + * @param destId Target node Id for the operation. + * If {@code null} - operation could be executed anywhere. + * @param clientId Client ID. + * @param cacheName Cache name. + * @param flags Cache flags. + * @param key Key to set affinity mapping in the response. + * @param op Operation to perform. + * @param keepPortable Keep portable flag. + * @return Operation result in future. + * @throws IgniteCheckedException If failed + */ + private IgniteFuture<GridRestResponse> executeCommand( + @Nullable UUID destId, + UUID clientId, + final String cacheName, + final GridCacheFlag[] flags, + final Object key, + final CacheProjectionCommand op, + final boolean keepPortable) throws IgniteCheckedException { + + final boolean locExec = + destId == null || destId.equals(ctx.localNodeId()) || replicatedCacheAvailable(cacheName); + + if (locExec) { + GridCacheProjection<?,?> prj = localCache(cacheName).forSubjectId(clientId).flagsOn(flags); + + if (keepPortable) + prj = prj.keepPortable(); + + return op.apply((GridCacheProjection<Object, Object>)prj, ctx). + chain(resultWrapper((GridCacheProjection<Object, Object>)prj, key)); + } + else { + ClusterGroup prj = ctx.grid().forPredicate(F.nodeForNodeId(destId)); + + IgniteCompute comp = ctx.grid().compute(prj).withNoFailover().enableAsync(); + + comp.call(new FlaggedCacheOperationCallable(clientId, cacheName, flags, op, key, keepPortable)); + + return comp.future(); + } + } + + /** + * Executes command on cache. Checks {@code destId} to find + * if command could be performed locally or routed to a remote node. + * + * @param destId Target node Id for the operation. + * If {@code null} - operation could be executed anywhere. + * @param clientId Client ID. + * @param cacheName Cache name. + * @param key Key to set affinity mapping in the response. + * @param op Operation to perform. + * @return Operation result in future. + * @throws IgniteCheckedException If failed + */ + private IgniteFuture<GridRestResponse> executeCommand( + @Nullable UUID destId, + UUID clientId, + final String cacheName, + final Object key, + final CacheCommand op) throws IgniteCheckedException { + final boolean locExec = destId == null || destId.equals(ctx.localNodeId()) || + ctx.cache().cache(cacheName) != null; + + if (locExec) { + final GridCacheProjection<Object, Object> cache = localCache(cacheName).forSubjectId(clientId); + + return op.apply(cache, ctx).chain(resultWrapper(cache, key)); + } + else { + ClusterGroup prj = ctx.grid().forPredicate(F.nodeForNodeId(destId)); + + IgniteCompute comp = ctx.grid().compute(prj).withNoFailover().enableAsync(); + + comp.call(new CacheOperationCallable(clientId, cacheName, op, key)); + + return comp.future(); + } + } + + /** + * Handles increment and decrement commands. + * + * @param cache Cache. + * @param key Key. + * @param req Request. + * @param decr Whether to decrement (increment otherwise). + * @return Future of operation result. + * @throws IgniteCheckedException In case of error. + */ + private static IgniteFuture<?> incrementOrDecrement(GridCacheProjection<Object, Object> cache, String key, + GridRestCacheRequest req, final boolean decr) throws IgniteCheckedException { + assert cache != null; + assert key != null; + assert req != null; + + Long init = req.initial(); + Long delta = req.delta(); + + if (delta == null) + throw new IgniteCheckedException(GridRestCommandHandlerAdapter.missingParameter("delta")); + + final GridCacheAtomicLong l = cache.cache().dataStructures().atomicLong(key, init != null ? init : 0, true); + + final Long d = delta; + + return ((GridKernal)cache.gridProjection().ignite()).context().closure().callLocalSafe(new Callable<Object>() { + @Override public Object call() throws Exception { + return l.addAndGet(decr ? -d : d); + } + }, false); + } + + /** + * Handles append and prepend commands. + * + * @param ctx Kernal context. + * @param cache Cache. + * @param key Key. + * @param req Request. + * @param prepend Whether to prepend. + * @return Future of operation result. + * @throws IgniteCheckedException In case of any exception. + */ + private static IgniteFuture<?> appendOrPrepend( + final GridKernalContext ctx, + final GridCacheProjection<Object, Object> cache, + final Object key, GridRestCacheRequest req, final boolean prepend) throws IgniteCheckedException { + assert cache != null; + assert key != null; + assert req != null; + + final Object val = req.value(); + + if (val == null) + throw new IgniteCheckedException(GridRestCommandHandlerAdapter.missingParameter("val")); + + return ctx.closure().callLocalSafe(new Callable<Object>() { + @Override public Object call() throws Exception { + try (IgniteTx tx = cache.txStart(PESSIMISTIC, REPEATABLE_READ)) { + Object curVal = cache.get(key); + + if (curVal == null) + return false; + + // Modify current value with appendix one. + Object newVal = appendOrPrepend(curVal, val, !prepend); + + // Put new value asynchronously. + cache.putx(key, newVal); + + tx.commit(); + } + + return true; + } + }, false); + } + + /** + * Append or prepend new value to the current one. + * + * @param origVal Original value. + * @param appendVal Appendix value to add to the original one. + * @param appendPlc Append or prepend policy flag. + * @return Resulting value. + * @throws IgniteCheckedException In case of grid exceptions. + */ + private static Object appendOrPrepend(Object origVal, Object appendVal, boolean appendPlc) throws IgniteCheckedException { + // Strings. + if (appendVal instanceof String && origVal instanceof String) + return appendPlc ? origVal + (String)appendVal : (String)appendVal + origVal; + + // Maps. + if (appendVal instanceof Map && origVal instanceof Map) { + Map<Object, Object> origMap = (Map<Object, Object>)origVal; + Map<Object, Object> appendMap = (Map<Object, Object>)appendVal; + + Map<Object, Object> map = X.cloneObject(origMap, false, true); + + if (appendPlc) + map.putAll(appendMap); // Append. + else { + map.clear(); + map.putAll(appendMap); // Prepend. + map.putAll(origMap); + } + + for (Map.Entry<Object, Object> e : appendMap.entrySet()) // Remove zero-valued entries. + if (e.getValue() == null && map.get(e.getKey()) == null) + map.remove(e.getKey()); + + return map; + } + + // Generic collection. + if (appendVal instanceof Collection<?> && origVal instanceof Collection<?>) { + Collection<Object> origCol = (Collection<Object>)origVal; + Collection<Object> appendCol = (Collection<Object>)appendVal; + + Collection<Object> col = X.cloneObject(origCol, false, true); + + if (appendPlc) + col.addAll(appendCol); // Append. + else { + col.clear(); + col.addAll(appendCol); // Prepend. + col.addAll(origCol); + } + + return col; + } + + throw new IgniteCheckedException("Incompatible types [appendVal=" + appendVal + ", old=" + origVal + ']'); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(GridCacheCommandHandler.class, this); + } + + /** + * Creates a transformation function from {@link CacheCommand}'s results into {@link GridRestResponse}. + * + * @param c Cache instance to obtain affinity data. + * @param key Affinity key for previous operation. + * @return Rest response. + */ + private static IgniteClosure<IgniteFuture<?>, GridRestResponse> resultWrapper( + final GridCacheProjection<Object, Object> c, @Nullable final Object key) { + return new CX1<IgniteFuture<?>, GridRestResponse>() { + @Override public GridRestResponse applyx(IgniteFuture<?> f) throws IgniteCheckedException { + GridCacheRestResponse resp = new GridCacheRestResponse(); + + resp.setResponse(f.get()); + + if (key != null) + resp.setAffinityNodeId(c.cache().affinity().mapKeyToNode(key).id().toString()); + + return resp; + } + }; + } + + /** + * @param cacheName Cache name. + * @return If replicated cache with given name is locally available. + */ + private boolean replicatedCacheAvailable(String cacheName) { + GridCacheAdapter<Object,Object> cache = ctx.cache().internalCache(cacheName); + + return cache != null && cache.configuration().getCacheMode() == GridCacheMode.REPLICATED; + } + + /** + * Used for test purposes. + * + * @param cacheName Name of the cache. + * @return Instance on the named cache. + * @throws IgniteCheckedException If cache not found. + */ + protected GridCacheProjectionEx<Object, Object> localCache(String cacheName) throws IgniteCheckedException { + GridCacheProjectionEx<Object, Object> cache = (GridCacheProjectionEx<Object, Object>)ctx.cache().cache(cacheName); + + if (cache == null) + throw new IgniteCheckedException( + "Failed to find cache for given cache name (null for default cache): " + cacheName); + + return cache; + } + + /** + * @param ignite Grid instance. + * @param cacheName Name of the cache. + * @return Instance on the named cache. + * @throws IgniteCheckedException If cache not found. + */ + private static GridCacheProjectionEx<Object, Object> cache(Ignite ignite, String cacheName) throws IgniteCheckedException { + GridCache<Object, Object> cache = ignite.cache(cacheName); + + if (cache == null) + throw new IgniteCheckedException( + "Failed to find cache for given cache name (null for default cache): " + cacheName); + + return (GridCacheProjectionEx<Object, Object>)cache; + } + + /** + * Fixed result closure. + */ + private static final class FixedResult extends CX1<IgniteFuture<?>, Object> { + /** */ + private static final long serialVersionUID = 0L; + + /** Closure result. */ + private final Object res; + + /** + * @param res Closure result. + */ + private FixedResult(Object res) { + this.res = res; + } + + /** {@inheritDoc} */ + @Override public Object applyx(IgniteFuture<?> f) throws IgniteCheckedException { + f.get(); + + return res; + } + } + + /** + * Type alias. + */ + private abstract static class CacheCommand + extends IgniteClosure2X<GridCacheProjection<Object, Object>, GridKernalContext, IgniteFuture<?>> { + /** */ + private static final long serialVersionUID = 0L; + + // No-op. + } + + /** + * Type alias. + */ + private abstract static class CacheProjectionCommand + extends IgniteClosure2X<GridCacheProjection<Object, Object>, GridKernalContext, IgniteFuture<?>> { + /** */ + private static final long serialVersionUID = 0L; + + // No-op. + } + + /** + * Class for flagged cache operations. + */ + @GridInternal + private static class FlaggedCacheOperationCallable implements Callable<GridRestResponse>, Serializable { + /** */ + private static final long serialVersionUID = 0L; + + /** Client ID. */ + private UUID clientId; + + /** */ + private final String cacheName; + + /** */ + private final GridCacheFlag[] flags; + + /** */ + private final CacheProjectionCommand op; + + /** */ + private final Object key; + + /** */ + private final boolean keepPortable; + + /** */ + @IgniteInstanceResource + private Ignite g; + + /** + * @param clientId Client ID. + * @param cacheName Cache name. + * @param flags Flags. + * @param op Operation. + * @param key Key. + * @param keepPortable Keep portable flag. + */ + private FlaggedCacheOperationCallable(UUID clientId, String cacheName, GridCacheFlag[] flags, + CacheProjectionCommand op, Object key, boolean keepPortable) { + this.clientId = clientId; + this.cacheName = cacheName; + this.flags = flags; + this.op = op; + this.key = key; + this.keepPortable = keepPortable; + } + + /** {@inheritDoc} */ + @Override public GridRestResponse call() throws Exception { + GridCacheProjection<?, ?> prj = cache(g, cacheName).forSubjectId(clientId).flagsOn(flags); + + if (keepPortable) + prj = prj.keepPortable(); + + // Need to apply both operation and response transformation remotely + // as cache could be inaccessible on local node and + // exception processing should be consistent with local execution. + return op.apply((GridCacheProjection<Object, Object>)prj, ((GridKernal)g).context()). + chain(resultWrapper((GridCacheProjection<Object, Object>)prj, key)).get(); + } + } + + /** + * Class for cache operations. + */ + @GridInternal + private static class CacheOperationCallable implements Callable<GridRestResponse>, Serializable { + /** */ + private static final long serialVersionUID = 0L; + + /** Client ID. */ + private UUID clientId; + + /** */ + private final String cacheName; + + /** */ + private final CacheCommand op; + + /** */ + private final Object key; + + /** */ + @IgniteInstanceResource + private Ignite g; + + /** + * @param clientId Client ID. + * @param cacheName Cache name. + * @param op Operation. + * @param key Key. + */ + private CacheOperationCallable(UUID clientId, String cacheName, CacheCommand op, Object key) { + this.clientId = clientId; + this.cacheName = cacheName; + this.op = op; + this.key = key; + } + + /** {@inheritDoc} */ + @Override public GridRestResponse call() throws Exception { + final GridCacheProjection<Object, Object> cache = cache(g, cacheName).forSubjectId(clientId); + + // Need to apply both operation and response transformation remotely + // as cache could be inaccessible on local node and + // exception processing should be consistent with local execution. + return op.apply(cache, ((GridKernal)g).context()).chain(resultWrapper(cache, key)).get(); + } + } + + /** */ + private static class GetCommand extends CacheProjectionCommand { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final Object key; + + /** + * @param key Key. + */ + GetCommand(Object key) { + this.key = key; + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<?> applyx(GridCacheProjection<Object, Object> c, GridKernalContext ctx) { + return c.getAsync(key); + } + } + + /** */ + private static class GetAllCommand extends CacheProjectionCommand { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final Collection<Object> keys; + + /** + * @param keys Keys. + */ + GetAllCommand(Collection<Object> keys) { + this.keys = keys; + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<?> applyx(GridCacheProjection<Object, Object> c, GridKernalContext ctx) { + return c.getAllAsync(keys); + } + } + + /** */ + private static class PutAllCommand extends CacheProjectionCommand { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final Map<Object, Object> map; + + /** + * @param map Objects to put. + */ + PutAllCommand(Map<Object, Object> map) { + this.map = map; + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<?> applyx(GridCacheProjection<Object, Object> c, GridKernalContext ctx) { + return c.putAllAsync(map).chain(new FixedResult(true)); + } + } + + /** */ + private static class RemoveCommand extends CacheProjectionCommand { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final Object key; + + /** + * @param key Key. + */ + RemoveCommand(Object key) { + this.key = key; + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<?> applyx(GridCacheProjection<Object, Object> c, GridKernalContext ctx) { + return c.removexAsync(key); + } + } + + /** */ + private static class RemoveAllCommand extends CacheProjectionCommand { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final Collection<Object> keys; + + /** + * @param keys Keys to remove. + */ + RemoveAllCommand(Collection<Object> keys) { + this.keys = keys; + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<?> applyx(GridCacheProjection<Object, Object> c, GridKernalContext ctx) { + return (F.isEmpty(keys) ? c.removeAllAsync() : c.removeAllAsync(keys)) + .chain(new FixedResult(true)); + } + } + + /** */ + private static class CasCommand extends CacheProjectionCommand { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final Object exp; + + /** */ + private final Object val; + + /** */ + private final Object key; + + /** + * @param exp Expected previous value. + * @param val New value. + * @param key Key. + */ + CasCommand(Object exp, Object val, Object key) { + this.val = val; + this.exp = exp; + this.key = key; + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<?> applyx(GridCacheProjection<Object, Object> c, GridKernalContext ctx) { + return exp == null && val == null ? c.removexAsync(key) : + exp == null ? c.putxIfAbsentAsync(key, val) : + val == null ? c.removeAsync(key, exp) : + c.replaceAsync(key, exp, val); + } + } + + /** */ + private static class PutCommand extends CacheProjectionCommand { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final Object key; + + /** */ + private final Long ttl; + + /** */ + private final Object val; + + /** + * @param key Key. + * @param ttl TTL. + * @param val Value. + */ + PutCommand(Object key, Long ttl, Object val) { + this.key = key; + this.ttl = ttl; + this.val = val; + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<?> applyx(GridCacheProjection<Object, Object> c, GridKernalContext ctx) { + if (ttl != null && ttl > 0) { + Duration duration = new Duration(MILLISECONDS, ttl); + + c = ((GridCacheProjectionEx<Object, Object>)c).withExpiryPolicy(new ModifiedExpiryPolicy(duration)); + } + + return c.putxAsync(key, val); + } + } + + /** */ + private static class AddCommand extends CacheProjectionCommand { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final Object key; + + /** */ + private final Long ttl; + + /** */ + private final Object val; + + /** + * @param key Key. + * @param ttl TTL. + * @param val Value. + */ + AddCommand(Object key, Long ttl, Object val) { + this.key = key; + this.ttl = ttl; + this.val = val; + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<?> applyx(GridCacheProjection<Object, Object> c, GridKernalContext ctx) { + if (ttl != null && ttl > 0) { + Duration duration = new Duration(MILLISECONDS, ttl); + + c = ((GridCacheProjectionEx<Object, Object>)c).withExpiryPolicy(new ModifiedExpiryPolicy(duration)); + } + + return c.putxIfAbsentAsync(key, val); + } + } + + /** */ + private static class ReplaceCommand extends CacheProjectionCommand { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final Object key; + + /** */ + private final Long ttl; + + /** */ + private final Object val; + + /** + * @param key Key. + * @param ttl TTL. + * @param val Value. + */ + ReplaceCommand(Object key, Long ttl, Object val) { + this.key = key; + this.ttl = ttl; + this.val = val; + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<?> applyx(GridCacheProjection<Object, Object> c, GridKernalContext ctx) { + if (ttl != null && ttl > 0) { + Duration duration = new Duration(MILLISECONDS, ttl); + + c = ((GridCacheProjectionEx<Object, Object>)c).withExpiryPolicy(new ModifiedExpiryPolicy(duration)); + } + + return c.replacexAsync(key, val); + } + } + + /** */ + private static class IncrementCommand extends CacheCommand { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final Object key; + + /** */ + private final GridRestCacheRequest req; + + /** + * @param key Key. + * @param req Operation request. + */ + IncrementCommand(Object key, GridRestCacheRequest req) { + this.key = key; + this.req = req; + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<?> applyx(GridCacheProjection<Object, Object> c, GridKernalContext ctx) + throws IgniteCheckedException { + return incrementOrDecrement(c, (String)key, req, false); + } + } + + /** */ + private static class DecrementCommand extends CacheCommand { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final Object key; + + /** */ + private final GridRestCacheRequest req; + + /** + * @param key Key. + * @param req Operation request. + */ + DecrementCommand(Object key, GridRestCacheRequest req) { + this.key = key; + this.req = req; + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<?> applyx(GridCacheProjection<Object, Object> c, GridKernalContext ctx) throws IgniteCheckedException { + return incrementOrDecrement(c, (String)key, req, true); + } + } + + /** */ + private static class AppendCommand extends CacheProjectionCommand { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final Object key; + + /** */ + private final GridRestCacheRequest req; + + /** + * @param key Key. + * @param req Operation request. + */ + AppendCommand(Object key, GridRestCacheRequest req) { + this.key = key; + this.req = req; + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<?> applyx(GridCacheProjection<Object, Object> c, GridKernalContext ctx) + throws IgniteCheckedException { + return appendOrPrepend(ctx, c, key, req, false); + } + } + + /** */ + private static class PrependCommand extends CacheProjectionCommand { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private final Object key; + + /** */ + private final GridRestCacheRequest req; + + /** + * @param key Key. + * @param req Operation request. + */ + PrependCommand(Object key, GridRestCacheRequest req) { + this.key = key; + this.req = req; + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<?> applyx(GridCacheProjection<Object, Object> c, GridKernalContext ctx) + throws IgniteCheckedException { + return appendOrPrepend(ctx, c, key, req, true); + } + } + + /** */ + private static class MetricsCommand extends CacheCommand { + /** */ + private static final long serialVersionUID = 0L; + + /** {@inheritDoc} */ + @Override public IgniteFuture<?> applyx(GridCacheProjection<Object, Object> c, GridKernalContext ctx) { + GridCacheMetrics metrics = c.cache().metrics(); + + assert metrics != null; + + return new GridFinishedFuture<Object>(ctx, new GridCacheRestMetrics( + metrics.createTime(), metrics.readTime(), metrics.writeTime(), + metrics.reads(), metrics.writes(), metrics.hits(), metrics.misses())); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1b0e45a2/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheQueryCommandHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheQueryCommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheQueryCommandHandler.java new file mode 100644 index 0000000..c67dbd2 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheQueryCommandHandler.java @@ -0,0 +1,493 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.rest.handlers.cache; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.apache.ignite.cache.query.*; +import org.apache.ignite.cluster.*; +import org.apache.ignite.internal.*; +import org.apache.ignite.lang.*; +import org.apache.ignite.resources.*; +import org.gridgain.grid.kernal.processors.cache.*; +import org.gridgain.grid.kernal.processors.cache.query.*; +import org.apache.ignite.internal.processors.rest.*; +import org.apache.ignite.internal.processors.rest.client.message.GridClientCacheQueryRequest; +import org.apache.ignite.internal.processors.rest.handlers.*; +import org.apache.ignite.internal.processors.rest.request.*; +import org.apache.ignite.internal.util.future.*; +import org.apache.ignite.internal.util.lang.*; +import org.apache.ignite.internal.util.typedef.*; +import org.apache.ignite.internal.util.typedef.internal.*; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; + +import static org.apache.ignite.internal.processors.rest.GridRestCommand.*; + +/** + * Cache query command handler. + */ +public class GridCacheQueryCommandHandler extends GridRestCommandHandlerAdapter { + /** Supported commands. */ + private static final Collection<GridRestCommand> SUPPORTED_COMMANDS = U.sealList( + CACHE_QUERY_EXECUTE, + CACHE_QUERY_FETCH, + CACHE_QUERY_REBUILD_INDEXES + ); + + /** Query ID sequence. */ + private static final AtomicLong qryIdGen = new AtomicLong(); + + /** + * @param ctx Context. + */ + public GridCacheQueryCommandHandler(GridKernalContext ctx) { + super(ctx); + } + + /** {@inheritDoc} */ + @Override public Collection<GridRestCommand> supportedCommands() { + return SUPPORTED_COMMANDS; + } + + /** {@inheritDoc} */ + @Override public IgniteFuture<GridRestResponse> handleAsync(GridRestRequest req) { + assert req instanceof GridRestCacheQueryRequest; + assert SUPPORTED_COMMANDS.contains(req.command()); + + GridRestCacheQueryRequest qryReq = (GridRestCacheQueryRequest)req; + + UUID destId = qryReq.destinationId(); + String cacheName = qryReq.cacheName(); + + switch (qryReq.command()) { + case CACHE_QUERY_EXECUTE: { + return execute(destId, cacheName, new ExecuteQuery(qryReq)); + } + + case CACHE_QUERY_FETCH: { + return execute(destId, cacheName, new FetchQueryResults(qryReq)); + } + + case CACHE_QUERY_REBUILD_INDEXES: { + return broadcast(qryReq.cacheName(), new RebuildIndexes(qryReq.cacheName(), qryReq.className())); + } + + default: + return new GridFinishedFutureEx<>(new IgniteCheckedException("Unsupported query command: " + req.command())); + } + } + + /** + * @param cacheName Cache name. + * @return If replicated cache with given name is locally available. + */ + private boolean replicatedCacheAvailable(String cacheName) { + GridCacheAdapter<Object,Object> cache = ctx.cache().internalCache(cacheName); + + return cache != null && cache.configuration().getCacheMode() == GridCacheMode.REPLICATED; + } + + /** + * Executes given closure either locally or on specified node. + * + * @param destId Destination node ID. + * @param cacheName Cache name. + * @param c Closure to execute. + * @return Execution future. + */ + private IgniteFuture<GridRestResponse> execute(UUID destId, String cacheName, Callable<GridRestResponse> c) { + boolean locExec = destId == null || destId.equals(ctx.localNodeId()) || replicatedCacheAvailable(cacheName); + + if (locExec) + return ctx.closure().callLocalSafe(c, false); + else { + if (ctx.discovery().node(destId) == null) + return new GridFinishedFutureEx<>(new IgniteCheckedException("Destination node ID has left the grid (retry " + + "the query): " + destId)); + + try { + IgniteCompute comp = ctx.grid().compute(ctx.grid().forNodeId(destId)).withNoFailover().enableAsync(); + + comp.call(c); + + return comp.future(); + } + catch (IgniteCheckedException e) { + // Should not be thrown since uses asynchronous execution. + return new GridFinishedFutureEx<>(e); + } + } + } + + /** + * @param cacheName Cache name. + * @param c Closure to execute. + * @return Execution future. + */ + private IgniteFuture<GridRestResponse> broadcast(String cacheName, Callable<Object> c) { + IgniteCompute comp = ctx.grid().compute(ctx.grid().forCache(cacheName)).withNoFailover().enableAsync(); + + try { + comp.broadcast(c); + + IgniteFuture<Collection<Object>> fut = comp.future(); + + return fut.chain(new C1<IgniteFuture<Collection<Object>>, GridRestResponse>() { + @Override public GridRestResponse apply(IgniteFuture<Collection<Object>> fut) { + try { + fut.get(); + + return new GridRestResponse(); + } + catch (IgniteCheckedException e) { + throw new GridClosureException(e); + } + } + }); + } + catch (IgniteCheckedException e) { + // Should not be thrown since uses asynchronous execution. + return new GridFinishedFutureEx<>(e); + } + } + + /** + * @param qryId Query ID. + * @param wrapper Query future wrapper. + * @param locMap Queries map. + * @param locNodeId Local node ID. + * @return Rest response. + * @throws IgniteCheckedException If failed. + */ + private static GridRestResponse fetchQueryResults( + long qryId, + QueryFutureWrapper wrapper, + ConcurrentMap<QueryExecutionKey, QueryFutureWrapper> locMap, + UUID locNodeId + ) throws IgniteCheckedException { + if (wrapper == null) + throw new IgniteCheckedException("Failed to find query future (query has been expired)."); + + GridCacheQueryFutureAdapter<?, ?, ?> fut = wrapper.future(); + + Collection<Object> col = (Collection<Object>)fut.nextPage(); + + GridCacheRestResponse res = new GridCacheRestResponse(); + + GridCacheClientQueryResult qryRes = new GridCacheClientQueryResult(); + + if (col == null) { + col = Collections.emptyList(); + + qryRes.last(true); + + locMap.remove(new QueryExecutionKey(qryId), wrapper); + } + + qryRes.items(col); + qryRes.queryId(qryId); + qryRes.nodeId(locNodeId); + + res.setResponse(qryRes); + + return res; + } + + /** + * Creates class instance. + * + * @param cls Target class. + * @param clsName Implementing class name. + * @return Class instance. + * @throws IgniteCheckedException If failed. + */ + private static <T> T instance(Class<? extends T> cls, String clsName) throws IgniteCheckedException { + try { + Class<?> implCls = Class.forName(clsName); + + if (!cls.isAssignableFrom(implCls)) + throw new IgniteCheckedException("Failed to create instance (target class does not extend or implement " + + "required class or interface) [cls=" + cls.getName() + ", clsName=" + clsName + ']'); + + Constructor<?> ctor = implCls.getConstructor(); + + return (T)ctor.newInstance(); + } + catch (ClassNotFoundException e) { + throw new IgniteCheckedException("Failed to find target class: " + clsName, e); + } + catch (NoSuchMethodException e) { + throw new IgniteCheckedException("Failed to find constructor for provided arguments " + + "[clsName=" + clsName + ']', e); + } + catch (InstantiationException e) { + throw new IgniteCheckedException("Failed to instantiate target class " + + "[clsName=" + clsName + ']', e); + } + catch (IllegalAccessException e) { + throw new IgniteCheckedException("Failed to instantiate class (constructor is not available) " + + "[clsName=" + clsName + ']', e); + } + catch (InvocationTargetException e) { + throw new IgniteCheckedException("Failed to instantiate class (constructor threw an exception) " + + "[clsName=" + clsName + ']', e.getCause()); + } + } + + /** + * + */ + private static class ExecuteQuery implements IgniteCallable<GridRestResponse> { + /** */ + private static final long serialVersionUID = 0L; + + /** Injected grid. */ + @IgniteInstanceResource + private Ignite g; + + /** Query request. */ + private GridRestCacheQueryRequest req; + + /** + * @param req Request. + */ + private ExecuteQuery(GridRestCacheQueryRequest req) { + this.req = req; + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked", "IfMayBeConditional"}) + @Override public GridRestResponse call() throws Exception { + long qryId = qryIdGen.getAndIncrement(); + + GridCacheQueries<Object,Object> queries = g.cache(req.cacheName()).queries(); + + GridCacheQuery<?> qry; + + switch (req.type()) { + case SQL: + qry = queries.createSqlQuery(req.className(), req.clause()); + + break; + + case SQL_FIELDS: + qry = queries.createSqlFieldsQuery(req.clause()); + + break; + + case FULL_TEXT: + qry = queries.createFullTextQuery(req.className(), req.clause()); + + break; + + case SCAN: + qry = queries.createScanQuery(instance(IgniteBiPredicate.class, req.className())); + + break; + + default: + throw new IgniteCheckedException("Unsupported query type: " + req.type()); + } + + boolean keepPortable = req.keepPortable(); + + if (!keepPortable) { + if (req.type() != GridClientCacheQueryRequest.GridQueryType.SCAN && + (req.remoteReducerClassName() == null && req.remoteTransformerClassName() == null)) + // Do not deserialize values on server if not needed. + keepPortable = true; + } + + ((GridCacheQueryAdapter)qry).keepPortable(keepPortable); + ((GridCacheQueryAdapter)qry).subjectId(req.clientId()); + + if (req.pageSize() > 0) + qry = qry.pageSize(req.pageSize()); + + if (req.timeout() > 0) + qry = qry.timeout(req.timeout()); + + qry = qry.includeBackups(req.includeBackups()).enableDedup(req.enableDedup()).keepAll(false); + + GridCacheQueryFutureAdapter<?, ?, ?> fut; + + if (req.remoteReducerClassName() != null) + fut = (GridCacheQueryFutureAdapter<?, ?, ?>)qry.execute( + instance(IgniteReducer.class, req.remoteReducerClassName()), + req.queryArguments()); + else if (req.remoteTransformerClassName() != null) + fut = (GridCacheQueryFutureAdapter<?, ?, ?>)qry.execute( + instance(IgniteClosure.class, req.remoteTransformerClassName()), + req.queryArguments()); + else + fut = (GridCacheQueryFutureAdapter<?, ?, ?>)qry.execute(req.queryArguments()); + + ClusterNodeLocalMap<QueryExecutionKey, QueryFutureWrapper> locMap = + g.cluster().nodeLocalMap(); + + QueryFutureWrapper wrapper = new QueryFutureWrapper(fut); + + QueryFutureWrapper old = locMap.putIfAbsent(new QueryExecutionKey(qryId), wrapper); + + assert old == null; + + return fetchQueryResults(qryId, wrapper, locMap, g.cluster().localNode().id()); + } + } + + /** + * + */ + private static class FetchQueryResults implements IgniteCallable<GridRestResponse> { + /** */ + private static final long serialVersionUID = 0L; + + /** Injected grid. */ + @IgniteInstanceResource + private Ignite g; + + /** Query request. */ + private GridRestCacheQueryRequest req; + + /** + * @param req Request. + */ + private FetchQueryResults(GridRestCacheQueryRequest req) { + this.req = req; + } + + /** {@inheritDoc} */ + @Override public GridRestResponse call() throws Exception { + ClusterNodeLocalMap<QueryExecutionKey, QueryFutureWrapper> locMap = + g.cluster().nodeLocalMap(); + + return fetchQueryResults(req.queryId(), locMap.get(new QueryExecutionKey(req.queryId())), + locMap, g.cluster().localNode().id()); + } + } + + /** + * Rebuild indexes closure. + */ + private static class RebuildIndexes implements IgniteCallable<Object> { + /** */ + private static final long serialVersionUID = 0L; + + /** Injected grid. */ + @IgniteInstanceResource + private Ignite g; + + /** Cache name. */ + private String cacheName; + + /** Class name. */ + private String clsName; + + /** + * @param cacheName Cache name. + * @param clsName Optional class name to rebuild indexes for. + */ + private RebuildIndexes(String cacheName, String clsName) { + this.cacheName = cacheName; + this.clsName = clsName; + } + + /** {@inheritDoc} */ + @Override public Object call() throws Exception { + if (clsName == null) + g.cache(cacheName).queries().rebuildAllIndexes(); + else + g.cache(cacheName).queries().rebuildIndexes(clsName); + + return null; + } + } + + /** + * + */ + private static class QueryExecutionKey { + /** Query ID. */ + private long qryId; + + /** + * @param qryId Query ID. + */ + private QueryExecutionKey(long qryId) { + this.qryId = qryId; + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object o) { + if (this == o) + return true; + + if (!(o instanceof QueryExecutionKey)) + return false; + + QueryExecutionKey that = (QueryExecutionKey)o; + + return qryId == that.qryId; + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + return (int)(qryId ^ (qryId >>> 32)); + } + } + + /** + * Query future wrapper. + */ + private static class QueryFutureWrapper { + /** Query future. */ + private final GridCacheQueryFutureAdapter<?, ?, ?> qryFut; + + /** Last future use timestamp. */ + private volatile long lastUseTs; + + /** + * @param qryFut Query future. + */ + private QueryFutureWrapper(GridCacheQueryFutureAdapter<?, ?, ?> qryFut) { + this.qryFut = qryFut; + + lastUseTs = U.currentTimeMillis(); + } + + /** + * @return Query future. + */ + private GridCacheQueryFutureAdapter<?, ?, ?> future() { + lastUseTs = U.currentTimeMillis(); + + return qryFut; + } + + /** + * @return Last use timestamp. + */ + private long lastUseTimestamp() { + return lastUseTs; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1b0e45a2/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheRestMetrics.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheRestMetrics.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheRestMetrics.java new file mode 100644 index 0000000..f7d45c0 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheRestMetrics.java @@ -0,0 +1,215 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.rest.handlers.cache; + +import org.apache.ignite.internal.util.*; + +import java.util.*; + +/** + * Grid cache metrics for rest. + */ +public class GridCacheRestMetrics { + /** Create time. */ + private long createTime; + + /** Last read time. */ + private long readTime; + + /** Last update time. */ + private long writeTime; + + /** Number of reads. */ + private int reads; + + /** Number of writes. */ + private int writes; + + /** Number of hits. */ + private int hits; + + /** Number of misses. */ + private int misses; + + /** + * Constructor. + * + * @param createTime Create time. + * @param readTime Read time. + * @param writeTime Write time. + * @param reads Reads. + * @param writes Writes. + * @param hits Hits. + * @param misses Misses. + */ + public GridCacheRestMetrics(long createTime, long readTime, long writeTime, int reads, int writes, int hits, + int misses) { + this.createTime = createTime; + this.readTime = readTime; + this.writeTime = writeTime; + this.reads = reads; + this.writes = writes; + this.hits = hits; + this.misses = misses; + } + + /** + * Gets create time. + * + * @return Create time. + */ + public long getCreateTime() { + return createTime; + } + + /** + * Sets create time. + * + * @param createTime Create time. + */ + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + /** + * Gets read time. + * + * @return Read time. + */ + public long getReadTime() { + return readTime; + } + + /** + * Sets read time. + * + * @param readTime Read time. + */ + public void setReadTime(long readTime) { + this.readTime = readTime; + } + + /** + * Gets write time. + * + * @return Write time. + */ + public long getWriteTime() { + return writeTime; + } + + /** + * Sets write time. + * + * @param writeTime Write time. + */ + public void setWriteTime(long writeTime) { + this.writeTime = writeTime; + } + + /** + * Gets reads. + * + * @return Reads. + */ + public int getReads() { + return reads; + } + + /** + * Sets reads. + * + * @param reads Reads. + */ + public void setReads(int reads) { + this.reads = reads; + } + + /** + * Gets writes. + * + * @return Writes. + */ + public int getWrites() { + return writes; + } + + /** + * Sets writes. + * + * @param writes Writes. + */ + public void setWrites(int writes) { + this.writes = writes; + } + + /** + * Gets hits. + * + * @return Hits. + */ + public int getHits() { + return hits; + } + + /** + * Sets hits. + * + * @param hits Hits. + */ + public void setHits(int hits) { + this.hits = hits; + } + + /** + * Gets misses. + * + * @return Misses. + */ + public int getMisses() { + return misses; + } + + /** + * Sets misses. + * + * @param misses Misses. + */ + public void setMisses(int misses) { + this.misses = misses; + } + + /** + * Creates map with strings. + * + * @return Map. + */ + public Map<String, Long> map() { + Map<String, Long> map = new GridLeanMap<>(7); + + map.put("createTime", createTime); + map.put("readTime", readTime); + map.put("writeTime", writeTime); + map.put("reads", (long)reads); + map.put("writes", (long)writes); + map.put("hits", (long)hits); + map.put("misses", (long)misses); + + return map; + } +}
