diff --git a/src/main/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponse.java b/src/main/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponse.java index aa5515db90f..a1afde168e6 100644 --- a/src/main/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponse.java +++ b/src/main/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponse.java @@ -26,6 +26,7 @@ import com.google.common.collect.Sets; import org.elasticsearch.action.ShardOperationFailedException; import org.elasticsearch.action.support.broadcast.BroadcastOperationResponse; import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.routing.ShardRouting; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ToXContent; @@ -44,7 +45,7 @@ public class IndicesStatsResponse extends BroadcastOperationResponse implements private ShardStats[] shards; - private ImmutableMap shardStatsMap; + private ImmutableMap shardStatsMap; IndicesStatsResponse() { @@ -53,21 +54,18 @@ public class IndicesStatsResponse extends BroadcastOperationResponse implements IndicesStatsResponse(ShardStats[] shards, ClusterState clusterState, int totalShards, int successfulShards, int failedShards, List shardFailures) { super(totalShards, successfulShards, failedShards, shardFailures); this.shards = shards; - this.shardStatsMap = buildShardsStatsMap(); } - private ImmutableMap buildShardsStatsMap() { - ImmutableMap.Builder mb = ImmutableMap.builder(); + public ImmutableMap asMap() { + if (shardStatsMap == null) { + ImmutableMap.Builder mb = ImmutableMap.builder(); + for (ShardStats ss : shards) { + mb.put(ss.getShardRouting(), ss.getStats()); + } - for (ShardStats ss : shards) { - mb.put(ss.getShardRouting().globalId(), ss.getStats()); + shardStatsMap = mb.build(); } - - return mb.build(); - } - - public ImmutableMap asMap() { - return this.shardStatsMap; + return shardStatsMap; } public ShardStats[] getShards() { diff --git a/src/main/java/org/elasticsearch/cluster/routing/ImmutableShardRouting.java b/src/main/java/org/elasticsearch/cluster/routing/ImmutableShardRouting.java index 51cd458c27a..75ba2aadd23 100644 --- a/src/main/java/org/elasticsearch/cluster/routing/ImmutableShardRouting.java +++ b/src/main/java/org/elasticsearch/cluster/routing/ImmutableShardRouting.java @@ -84,29 +84,6 @@ public class ImmutableShardRouting implements Streamable, Serializable, ShardRou this.version = version; } - @Override - public String globalId() { - String pri = "r"; - if (this.primary()) { - pri = "p"; - } - - String node = "unassigned"; - if (null != this.currentNodeId()) { - node = this.currentNodeId(); - } - - StringBuilder sb = new StringBuilder(); - sb.append(getIndex()); - sb.append("/"); - sb.append(this.shardId().id()); - sb.append("/"); - sb.append(pri); - sb.append("/"); - sb.append(node); - return sb.toString(); - } - @Override public String index() { return this.index; @@ -198,10 +175,9 @@ public class ImmutableShardRouting implements Streamable, Serializable, ShardRou /** * Reads a {@link ImmutableShardRouting} instance of a shard from an {@link InputStream} - * + * * @param in {@link InputStream} to read the entry from * @return {@link ImmutableShardRouting} instances read from the given {@link InputStream} - * * @throws IOException if some exception occurs during the read operations */ public static ImmutableShardRouting readShardRoutingEntry(StreamInput in) throws IOException { @@ -213,12 +189,11 @@ public class ImmutableShardRouting implements Streamable, Serializable, ShardRou /** * Reads a routingentry from an inputstream with given index and * shardId. - * - * @param in inputstream to read the entry from + * + * @param in inputstream to read the entry from * @param index shards index - * @param id id of the shard + * @param id id of the shard * @return Shard routing entry read - * * @throws IOException if some exception occurs during the read operations */ public static ImmutableShardRouting readShardRoutingEntry(StreamInput in, String index, int shardId) throws IOException { @@ -230,11 +205,10 @@ public class ImmutableShardRouting implements Streamable, Serializable, ShardRou /** * Read information from an inputstream with given index and * shardId. - * - * @param in inputstream to read the entry from + * + * @param in inputstream to read the entry from * @param index shards index - * @param id id of the shard - * + * @param id id of the shard * @throws IOException if some exception occurs during the read operations */ public void readFrom(StreamInput in, String index, int shardId) throws IOException { @@ -262,9 +236,10 @@ public class ImmutableShardRouting implements Streamable, Serializable, ShardRou public void readFrom(StreamInput in) throws IOException { readFrom(in, in.readString(), in.readVInt()); } - + /** * Writes shard information to {@link StreamOutput} without writing index name and shard id + * * @param out {@link StreamOutput} to write shard information to * @throws IOException if something happens during write */ diff --git a/src/main/java/org/elasticsearch/cluster/routing/ShardRouting.java b/src/main/java/org/elasticsearch/cluster/routing/ShardRouting.java index e960e471a31..385fba94bab 100644 --- a/src/main/java/org/elasticsearch/cluster/routing/ShardRouting.java +++ b/src/main/java/org/elasticsearch/cluster/routing/ShardRouting.java @@ -87,7 +87,7 @@ public interface ShardRouting extends Streamable, Serializable, ToXContent { /** * Returns true iff the this shard is currently relocating to * another node. Otherwise false - * + * * @see ShardRoutingState#RELOCATING */ boolean relocating(); @@ -131,11 +131,6 @@ public interface ShardRouting extends Streamable, Serializable, ToXContent { */ ShardIterator shardsIt(); - /** - * String identifier to uniquely refer to this shard routing (once it's assigned). - */ - String globalId(); - /** * Does not write index name and shard id */ diff --git a/src/main/java/org/elasticsearch/common/Table.java b/src/main/java/org/elasticsearch/common/Table.java new file mode 100644 index 00000000000..a7237d74fb3 --- /dev/null +++ b/src/main/java/org/elasticsearch/common/Table.java @@ -0,0 +1,125 @@ +/* + * Licensed to ElasticSearch and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. ElasticSearch 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.elasticsearch.common; + +import com.google.common.collect.ImmutableMap; +import org.elasticsearch.ElasticSearchIllegalArgumentException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + */ +public class Table { + + private List headers = new ArrayList(); + private List> rows = new ArrayList>(); + + private List currentCells; + + private boolean inHeaders = false; + + public Table startHeaders() { + inHeaders = true; + currentCells = new ArrayList(); + return this; + } + + public Table endHeaders() { + inHeaders = false; + headers = currentCells; + currentCells = null; + return this; + } + + public Table startRow() { + if (headers.isEmpty()) { + throw new ElasticSearchIllegalArgumentException("no headers added..."); + } + currentCells = new ArrayList(headers.size()); + return this; + } + + public Table endRow() { + if (currentCells.size() != headers.size()) { + throw new ElasticSearchIllegalArgumentException("mismatch on number of cells in a row compared to header"); + } + rows.add(currentCells); + currentCells = null; + return this; + } + + public Table addCell(Object value) { + return addCell(value, ""); + } + + public Table addCell(Object value, String attributes) { + if (!inHeaders) { + if (currentCells.size() == headers.size()) { + throw new ElasticSearchIllegalArgumentException("can't add more cells to a row than the header"); + } + } + Map mAttr; + if (attributes.length() == 0) { + if (inHeaders) { + mAttr = ImmutableMap.of(); + } else { + // get the attributes of the header cell we are going to add to + mAttr = headers.get(currentCells.size()).attr; + } + } else { + mAttr = new HashMap(); + if (!inHeaders) { + // get the attributes of the header cell we are going to add + mAttr.putAll(headers.get(currentCells.size()).attr); + } + String[] sAttrs = Strings.split(attributes, ";"); + for (String sAttr : sAttrs) { + if (sAttr.length() == 0) { + continue; + } + int idx = sAttr.indexOf('='); + mAttr.put(sAttr.substring(0, idx), sAttr.substring(idx + 1)); + } + } + currentCells.add(new Cell(value, mAttr)); + return this; + } + + public List getHeaders() { + return this.headers; + } + + public Iterable> getRows() { + return rows; + } + + public static class Cell { + public final Object value; + public final Map attr; + + Cell(Object value, Map attr) { + this.value = value; + this.attr = attr; + } + } +} diff --git a/src/main/java/org/elasticsearch/common/table/Align.java b/src/main/java/org/elasticsearch/common/table/Align.java deleted file mode 100644 index cad9f0f90d8..00000000000 --- a/src/main/java/org/elasticsearch/common/table/Align.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to ElasticSearch and Shay Banon under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. ElasticSearch 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.elasticsearch.common.table; - -public enum Align { - LEFT((byte) 0), - CENTER((byte) 1), - RIGHT((byte) 2); - - private byte id; - - Align (byte id) { - this.id = id; - } -} diff --git a/src/main/java/org/elasticsearch/common/table/Cell.java b/src/main/java/org/elasticsearch/common/table/Cell.java deleted file mode 100644 index e5c26ca2106..00000000000 --- a/src/main/java/org/elasticsearch/common/table/Cell.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to ElasticSearch and Shay Banon under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. ElasticSearch 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.elasticsearch.common.table; - -/** - * A String container that supports alignment. - */ -public class Cell { - private final String content; - - private final Align align; - - private final byte width; - - public Cell(String content) { - this.content = content; - this.align = Align.LEFT; - this.width = (byte) content.length(); - } - - public Cell(String content, Align align) { - this.content = content; - this.align = align; - this.width = (byte) content.length(); - } - - public Cell(String content, Align align, byte width) { - this.content = content; - this.align = align; - this.width = width; - } - - public byte width() { - return this.width; - } - - public Align align() { - return this.align; - } - - public static String pad(String orig, byte width, Align align) { - StringBuilder s = new StringBuilder(); - byte leftOver = (byte) (width - orig.length()); - if (leftOver > 0 && align == Align.LEFT) { - s.append(orig); - for (byte i = 0; i < leftOver; i++) { - s.append(" "); - } - } else if (leftOver > 0 && align == Align.RIGHT) { - for (byte i = 0; i < leftOver; i++) { - s.append(" "); - } - s.append(orig); - } else { - s.append(orig); - } - return s.toString(); - } - - public String toString(byte outWidth, Align outAlign) { - return pad(content, outWidth, outAlign); - } - - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("["); - sb.append(align()); - sb.append("]"); - sb.append(content); - return sb.toString(); - } -} diff --git a/src/main/java/org/elasticsearch/common/table/Row.java b/src/main/java/org/elasticsearch/common/table/Row.java deleted file mode 100644 index 12805276dab..00000000000 --- a/src/main/java/org/elasticsearch/common/table/Row.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to ElasticSearch and Shay Banon under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. ElasticSearch 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.elasticsearch.common.table; - -import java.util.ArrayList; - -/** - * - */ -public class Row { - private final ArrayList cells; - - private final ArrayList widths; - - public Row () { - this.cells = new ArrayList(); - this.widths = new ArrayList(); - } - - public ArrayList cells() { - return this.cells; - } - - public int size () { - return cells.size(); - } - - public Row addCell(Cell cell) { - cells.add(cell); - widths.add(cell.width()); - return this; - } - - public Row addCell(String content) { - addCell(new Cell(content)); - return this; - } - - public Row addCell(String content, Align align) { - addCell(new Cell(content, align)); - return this; - } -} diff --git a/src/main/java/org/elasticsearch/common/table/Table.java b/src/main/java/org/elasticsearch/common/table/Table.java deleted file mode 100644 index 5aacaf54449..00000000000 --- a/src/main/java/org/elasticsearch/common/table/Table.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to ElasticSearch and Shay Banon under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. ElasticSearch 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.elasticsearch.common.table; - -import java.util.ArrayList; - -/** - * A generic table renderer. Can optionally print header row. - * Will justify all cells in a column to the widest one. All rows need - * to have same number of cells. - * - * Eg, new Table.addRow(new Row().addCell("foo").addCell("bar")).render() - */ -public class Table { - private ArrayList cols; - - private byte numcols; - - private byte height; - - public Table() { - this.cols = new ArrayList(); - this.numcols = 0; - this.height = 0; - } - - public Table addRow(Row row) { - addRow(row, false); - return this; - } - - public void ensureCapacity(int size) { - if (numcols < size) { - for (int i = 0; i < (size - numcols); i++) { - cols.add(new Column()); - } - } - } - - public Table addRow(Row row, boolean header) { - ensureCapacity(row.size()); - byte curCol = 0; - for (Cell cell : row.cells()) { - Column col = cols.get(curCol); - col.addCell(cell, header); - curCol += 1; - } - numcols = curCol; - height += 1; - return this; - } - - public String render() { - return render(false); - } - - public String render(boolean withHeaders) { - StringBuilder out = new StringBuilder(); - for (byte i = 0; i < height; i++) { - StringBuilder row = new StringBuilder(); - for (Column col : cols) { - Cell cell = col.getCell(i); - boolean headerRowWhenNotWantingHeaders = i == 0 && !withHeaders && col.hasHeader(); - if (! headerRowWhenNotWantingHeaders) { - row.append(cell.toString(col.width(), col.align())); - row.append(" "); - } - } - out.append(row.toString().trim()); - out.append("\n"); - } - return out.toString(); - } - - private class Column { - private boolean hasHeader; - - private ArrayList cells; - - private byte width; - - private Align align; - - Column () { - cells = new ArrayList(); - width = 0; - hasHeader = false; - align = Align.LEFT; - } - - public Column addCell(Cell cell) { - addCell(cell, false); - return this; - } - - public Column addCell(Cell cell, boolean header) { - cells.add(cell); - - if (header) { - hasHeader = true; - } - - if (cell.width() > width) { - width = cell.width(); - } - - if (align != cell.align()) { - align = cell.align(); - } - - return this; - } - - public Cell getCell(int index) { - return cells.get(index); - } - - public Align align() { - return this.align; - } - - public byte width() { - return this.width; - } - - public boolean hasHeader() { - return this.hasHeader; - } - } -} diff --git a/src/main/java/org/elasticsearch/rest/action/RestActionModule.java b/src/main/java/org/elasticsearch/rest/action/RestActionModule.java index 35418a4d429..8643df0f017 100644 --- a/src/main/java/org/elasticsearch/rest/action/RestActionModule.java +++ b/src/main/java/org/elasticsearch/rest/action/RestActionModule.java @@ -67,7 +67,6 @@ import org.elasticsearch.rest.action.admin.indices.warmer.delete.RestDeleteWarme import org.elasticsearch.rest.action.admin.indices.warmer.get.RestGetWarmerAction; import org.elasticsearch.rest.action.admin.indices.warmer.put.RestPutWarmerAction; import org.elasticsearch.rest.action.bulk.RestBulkAction; -import org.elasticsearch.rest.action.cat.RestMasterAction; import org.elasticsearch.rest.action.cat.RestShardsAction; import org.elasticsearch.rest.action.count.RestCountAction; import org.elasticsearch.rest.action.delete.RestDeleteAction; @@ -85,9 +84,7 @@ import org.elasticsearch.rest.action.search.RestMultiSearchAction; import org.elasticsearch.rest.action.search.RestSearchAction; import org.elasticsearch.rest.action.search.RestSearchScrollAction; import org.elasticsearch.rest.action.suggest.RestSuggestAction; - import org.elasticsearch.rest.action.termvector.RestTermVectorAction; - import org.elasticsearch.rest.action.update.RestUpdateAction; import java.util.List; @@ -186,6 +183,5 @@ public class RestActionModule extends AbstractModule { bind(RestExplainAction.class).asEagerSingleton(); bind(RestShardsAction.class).asEagerSingleton(); - bind(RestMasterAction.class).asEagerSingleton(); } } diff --git a/src/main/java/org/elasticsearch/rest/action/cat/RestMasterAction.java b/src/main/java/org/elasticsearch/rest/action/cat/RestMasterAction.java deleted file mode 100644 index 08f5206bb10..00000000000 --- a/src/main/java/org/elasticsearch/rest/action/cat/RestMasterAction.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to ElasticSearch and Shay Banon under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. ElasticSearch 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.elasticsearch.rest.action.cat; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest; -import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; -import org.elasticsearch.client.Client; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.table.Row; -import org.elasticsearch.common.table.Table; -import org.elasticsearch.common.transport.InetSocketTransportAddress; -import org.elasticsearch.rest.*; - -import java.io.IOException; - -import static org.elasticsearch.rest.RestRequest.Method.GET; - -public class RestMasterAction extends BaseRestHandler { - @Inject - public RestMasterAction(Settings settings, Client client, RestController controller) { - super(settings, client); - controller.registerHandler(GET, "/_cat/master", this); - } - - @Override - public void handleRequest(final RestRequest request, final RestChannel channel) { - final boolean verbose = request.paramAsBoolean("verbose", false); - final StringBuilder out = new StringBuilder(); - - final ClusterStateRequest clusterStateRequest = new ClusterStateRequest(); clusterStateRequest.listenerThreaded(false); - clusterStateRequest.filterMetaData(true); - clusterStateRequest.local(false); - - client.admin().cluster().state(clusterStateRequest, new ActionListener() { - @Override - public void onResponse(final ClusterStateResponse clusterStateResponse) { - try { - RestStatus status = RestStatus.OK; - Table tab = new Table(); - tab.addRow(new Row() - .addCell("id") - .addCell("transport addr") - .addCell("name"), true); - tab.addRow(new Row() - .addCell(clusterStateResponse.getState().nodes().masterNode().id()) - .addCell(((InetSocketTransportAddress)clusterStateResponse.getState().nodes() - .masterNode().address()).address().getAddress().getHostAddress()) - .addCell(clusterStateResponse.getState().nodes().masterNode().name())); - - channel.sendResponse(new StringRestResponse(status, tab.render(verbose))); - } catch (Throwable e) { - onFailure(e); - } - } - - @Override - public void onFailure(Throwable e) { - try { - channel.sendResponse(new XContentThrowableRestResponse(request, e)); - } catch (IOException e1) { - logger.error("Failed to send failure response", e1); - } - } - }); - } -} diff --git a/src/main/java/org/elasticsearch/rest/action/cat/RestShardsAction.java b/src/main/java/org/elasticsearch/rest/action/cat/RestShardsAction.java index 5d8acd45f1f..ad28b3f0d2c 100644 --- a/src/main/java/org/elasticsearch/rest/action/cat/RestShardsAction.java +++ b/src/main/java/org/elasticsearch/rest/action/cat/RestShardsAction.java @@ -22,22 +22,24 @@ package org.elasticsearch.rest.action.cat; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest; import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; +import org.elasticsearch.action.admin.indices.stats.CommonStats; import org.elasticsearch.action.admin.indices.stats.IndicesStatsRequest; import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; import org.elasticsearch.client.Client; -import org.elasticsearch.cluster.routing.*; +import org.elasticsearch.cluster.routing.ShardRouting; +import org.elasticsearch.common.Table; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.table.Row; -import org.elasticsearch.common.table.Table; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.rest.*; +import org.elasticsearch.rest.action.support.RestTable; import java.io.IOException; import static org.elasticsearch.rest.RestRequest.Method.GET; public class RestShardsAction extends BaseRestHandler { + @Inject public RestShardsAction(Settings settings, Client client, RestController controller) { super(settings, client); @@ -46,12 +48,10 @@ public class RestShardsAction extends BaseRestHandler { @Override public void handleRequest(final RestRequest request, final RestChannel channel) { - final boolean verbose = request.paramAsBoolean("verbose", false); - final StringBuilder out = new StringBuilder(); - - final ClusterStateRequest clusterStateRequest = new ClusterStateRequest(); clusterStateRequest.listenerThreaded(false); + final ClusterStateRequest clusterStateRequest = new ClusterStateRequest(); clusterStateRequest.filterMetaData(true); - clusterStateRequest.local(false); + clusterStateRequest.local(request.paramAsBoolean("local", clusterStateRequest.local())); + clusterStateRequest.masterNodeTimeout(request.paramAsTime("master_timeout", clusterStateRequest.masterNodeTimeout())); client.admin().cluster().state(clusterStateRequest, new ActionListener() { @Override @@ -60,9 +60,8 @@ public class RestShardsAction extends BaseRestHandler { client.admin().indices().stats(indicesStatsRequest, new ActionListener() { @Override public void onResponse(IndicesStatsResponse indicesStatsResponse) { - RestStatus status = RestStatus.OK; try { - channel.sendResponse(new StringRestResponse(status, process(clusterStateResponse, indicesStatsResponse, verbose))); + channel.sendResponse(RestTable.buildResponse(buildTable(clusterStateResponse, indicesStatsResponse), request, channel)); } catch (Throwable e) { onFailure(e); } @@ -90,64 +89,41 @@ public class RestShardsAction extends BaseRestHandler { }); } - private String process(ClusterStateResponse state, IndicesStatsResponse stats, boolean headers) { - Table tab = new Table(); - if (headers) { - tab.addRow(new Row() - .addCell("index") - .addCell("shard") - .addCell("replica") - .addCell("state") - .addCell("docs") - .addCell("size") - .addCell("bytes") - .addCell("host") - .addCell("node"), true); - } + private Table buildTable(ClusterStateResponse state, IndicesStatsResponse stats) { + Table table = new Table(); + table.startHeaders() + .addCell("index", "default=true;") + .addCell("shard", "default=true;") + .addCell("p/r", "default=true;") + .addCell("state", "default=true;") + .addCell("docs", "default=true;") + .addCell("store", "default=true;") + .addCell("ip", "default=true;") + .addCell("node", "default=true;") + .endHeaders(); for (ShardRouting shard : state.getState().routingTable().allShards()) { - Row row = new Row(); - String pri = "r"; - StringBuilder host = new StringBuilder(); - String docs = ""; - String size = ""; - String bytes = ""; - String nodeName = ""; + CommonStats shardStats = stats.asMap().get(shard); + table.startRow(); + + table.addCell(shard.index()); + table.addCell(shard.id()); + table.addCell(shard.primary() ? "p" : "r"); + table.addCell(shard.state()); + table.addCell(shardStats == null ? null : shardStats.getDocs().getCount()); + table.addCell(shardStats == null ? null : shardStats.getStore().getSize()); if (shard.assignedToNode()) { - host.append(((InetSocketTransportAddress) state.getState().nodes().get(shard.currentNodeId()).address()).address().getAddress().getHostAddress()); - nodeName = state.getState().nodes().get(shard.currentNodeId()).name(); + table.addCell(((InetSocketTransportAddress) state.getState().nodes().get(shard.currentNodeId()).address()).address().getAddress().getHostAddress()); + table.addCell(state.getState().nodes().get(shard.currentNodeId()).name()); + } else { + table.addCell(null); + table.addCell(null); } - if (shard.relocating()) { - host.append(" -> "); - host.append(((InetSocketTransportAddress) state.getState().nodes().get(shard.relocatingNodeId()).address()).address().getAddress().getHostAddress()); - host.append(state.getState().nodes().get(shard.relocatingNodeId()).name()); - } - - if (null != stats.asMap().get(shard.globalId())) { - size = stats.asMap().get(shard.globalId()).getStore().size().toString(); - bytes = new Long(stats.asMap().get(shard.globalId()).getStore().getSizeInBytes()).toString(); - docs = new Long(stats.asMap().get(shard.globalId()).getDocs().getCount()).toString(); - } - - if (shard.primary()) { - pri = "p"; - } - - row.addCell(shard.index()) - .addCell(new Integer(shard.shardId().id()).toString()) - .addCell(pri) - .addCell(shard.state().toString()) - .addCell(docs) - .addCell(size) - .addCell(bytes) - .addCell(host.toString()) - .addCell(nodeName); - tab.addRow(row); + table.endRow(); } - return tab.render(headers); + return table; } - } diff --git a/src/main/java/org/elasticsearch/rest/action/support/RestTable.java b/src/main/java/org/elasticsearch/rest/action/support/RestTable.java new file mode 100644 index 00000000000..09cdc490db7 --- /dev/null +++ b/src/main/java/org/elasticsearch/rest/action/support/RestTable.java @@ -0,0 +1,215 @@ +/* + * Licensed to ElasticSearch and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. ElasticSearch 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.elasticsearch.rest.action.support; + +import org.elasticsearch.common.Booleans; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.Table; +import org.elasticsearch.common.unit.ByteSizeValue; +import org.elasticsearch.common.unit.SizeValue; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.rest.*; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + */ +public class RestTable { + + public static RestResponse buildResponse(Table table, RestRequest request, RestChannel channel) throws Exception { + XContentType xContentType = XContentType.fromRestContentType(request.param("format", request.header("Content-Type"))); + if (xContentType != null) { + return buildXContentBuilder(table, request, channel); + } + return buildTextPlainResponse(table, request, channel); + } + + public static RestResponse buildXContentBuilder(Table table, RestRequest request, RestChannel channel) throws Exception { + XContentBuilder builder = RestXContentBuilder.restContentBuilder(request); + Set displayHeaders = buildDisplayHeaders(table, request); + + List headers = table.getHeaders(); + builder.startArray(); + for (List row : table.getRows()) { + builder.startObject(); + for (int i = 0; i < headers.size(); i++) { + String headerName = headers.get(i).value.toString(); + if (displayHeaders.contains(headerName)) { + builder.field(headerName, renderValue(request, row.get(i).value)); + } + } + builder.endObject(); + } + builder.endArray(); + return new XContentRestResponse(request, RestStatus.OK, builder); + } + + public static RestResponse buildTextPlainResponse(Table table, RestRequest request, RestChannel channel) { + int[] width = buildWidths(table, request); + Set displayHeaders = buildDisplayHeaders(table, request); + + boolean verbose = request.paramAsBoolean("v", true); + StringBuilder out = new StringBuilder(); + if (verbose) { + // print the headers + for (int i = 0; i < width.length; i++) { + String headerName = table.getHeaders().get(i).value.toString(); + if (displayHeaders.contains(headerName)) { + pad(table.getHeaders().get(i), width[i], request, out); + out.append(" "); + } + } + out.append("\n"); + } + for (List row : table.getRows()) { + for (int i = 0; i < width.length; i++) { + String headerName = table.getHeaders().get(i).value.toString(); + if (displayHeaders.contains(headerName)) { + pad(row.get(i), width[i], request, out); + out.append(" "); + } + } + out.append("\n"); + } + + return new StringRestResponse(RestStatus.OK, out.toString()); + } + + private static Set buildDisplayHeaders(Table table, RestRequest request) { + String pHeaders = request.param("headers"); + Set display; + if (pHeaders != null) { + display = Strings.commaDelimitedListToSet(pHeaders); + } else { + display = new HashSet(); + for (Table.Cell cell : table.getHeaders()) { + String d = cell.attr.get("default"); + if (Booleans.parseBoolean(d, true)) { + display.add(cell.value.toString()); + } + } + } + return display; + } + + private static int[] buildWidths(Table table, RestRequest request) { + int[] width = new int[table.getHeaders().size()]; + for (int col = 0; col < width.length; col++) { + String v = renderValue(request, table.getHeaders().get(col).value); + int vWidth = v == null ? 0 : v.length(); + if (width[col] < vWidth) { + width[col] = vWidth; + } + } + + for (List row : table.getRows()) { + for (int col = 0; col < width.length; col++) { + String v = renderValue(request, row.get(col).value); + int vWidth = v == null ? 0 : v.length(); + if (width[col] < vWidth) { + width[col] = vWidth; + } + } + } + return width; + } + + private static void pad(Table.Cell cell, int width, RestRequest request, StringBuilder out) { + String sValue = renderValue(request, cell.value); + int length = sValue == null ? 0 : sValue.length(); + byte leftOver = (byte) (width - length); + String textAlign = cell.attr.get("text-align"); + if (textAlign == null) { + textAlign = "left"; + } + if (leftOver > 0 && textAlign.equals("right")) { + for (byte i = 0; i < leftOver; i++) { + out.append(" "); + } + if (sValue != null) { + out.append(sValue); + } + } else { + if (sValue != null) { + out.append(sValue); + } + for (byte i = 0; i < leftOver; i++) { + out.append(" "); + } + } + } + + private static String renderValue(RestRequest request, Object value) { + if (value == null) { + return null; + } + if (value instanceof ByteSizeValue) { + ByteSizeValue v = (ByteSizeValue) value; + String resolution = request.param("bytes"); + if ("b".equals(resolution)) { + return Long.toString(v.bytes()); + } else if ("k".equals(resolution)) { + return Long.toString(v.kb()); + } else if ("m".equals(resolution)) { + return Long.toString(v.mb()); + } else if ("g".equals(resolution)) { + return Long.toString(v.gb()); + } else { + return v.toString(); + } + } + if (value instanceof SizeValue) { + SizeValue v = (SizeValue) value; + String resolution = request.param("size"); + if ("b".equals(resolution)) { + return Long.toString(v.singles()); + } else if ("k".equals(resolution)) { + return Long.toString(v.kilo()); + } else if ("m".equals(resolution)) { + return Long.toString(v.mega()); + } else if ("g".equals(resolution)) { + return Long.toString(v.giga()); + } else { + return v.toString(); + } + } + if (value instanceof TimeValue) { + TimeValue v = (TimeValue) value; + String resolution = request.param("time"); + if ("ms".equals(resolution)) { + return Long.toString(v.millis()); + } else if ("s".equals(resolution)) { + return Long.toString(v.seconds()); + } else if ("m".equals(resolution)) { + return Long.toString(v.minutes()); + } else if ("h".equals(resolution)) { + return Long.toString(v.hours()); + } else { + return v.toString(); + } + } + // Add additional built in data points we can render based on request parameters? + return value.toString(); + } +}