/**
* 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.drill.exec.server.rest;
import java.util.Collection;
import javax.annotation.security.PermitAll;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.SecurityContext;
import javax.xml.bind.annotation.XmlRootElement;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import org.apache.drill.exec.proto.CoordinationProtos.DrillbitEndpoint;
import org.apache.drill.exec.server.rest.DrillRestServer.UserAuthEnabled;
import org.apache.drill.exec.work.WorkManager;
import org.glassfish.jersey.server.mvc.Viewable;
import com.fasterxml.jackson.annotation.JsonCreator;
@Path("/")
@PermitAll
public class DrillRoot {
static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DrillRoot.class);
@Inject UserAuthEnabled authEnabled;
@Inject WorkManager work;
@Inject SecurityContext sc;
@GET
@Produces(MediaType.TEXT_HTML)
public Viewable getClusterInfo() {
return ViewableWithPermissions.create(authEnabled.get(), "/rest/index.ftl", sc, getClusterInfoJSON());
}
@GET
@Path("/cluster.json")
@Produces(MediaType.APPLICATION_JSON)
public ClusterInfo getClusterInfoJSON() {
final Collection<DrillbitInfo> drillbits = Sets.newTreeSet();
final Collection<String> mismatchedVersions = Sets.newTreeSet();
final DrillbitEndpoint currentDrillbit = work.getContext().getEndpoint();
final String currentVersion = currentDrillbit.getVersion();
for (DrillbitEndpoint endpoint : work.getContext().getBits()) {
final DrillbitInfo drillbit = new DrillbitInfo(endpoint,
currentDrillbit.equals(endpoint),
currentVersion.equals(endpoint.getVersion()));
if (!drillbit.isVersionMatch()) {
mismatchedVersions.add(drillbit.getVersion());
}
drillbits.add(drillbit);
}
return new ClusterInfo(drillbits, currentVersion, mismatchedVersions);
}
@XmlRootElement
public static class ClusterInfo {
private final Collection<DrillbitInfo> drillbits;
private final String currentVersion;
private final Collection<String> mismatchedVersions;
@JsonCreator
public ClusterInfo(Collection<DrillbitInfo> drillbits,
String currentVersion,
Collection<String> mismatchedVersions) {
this.drillbits = Sets.newTreeSet(drillbits);
this.currentVersion = currentVersion;
this.mismatchedVersions = Sets.newTreeSet(mismatchedVersions);
}
public Collection<DrillbitInfo> getDrillbits() {
return Sets.newTreeSet(drillbits);
}
public String getCurrentVersion() {
return currentVersion;
}
public Collection<String> getMismatchedVersions() {
return Sets.newTreeSet(mismatchedVersions);
}
}
public static class DrillbitInfo implements Comparable<DrillbitInfo> {
private final String address;
private final String userPort;
private final String controlPort;
private final String dataPort;
private final String version;
private final boolean current;
private final boolean versionMatch;
@JsonCreator
public DrillbitInfo(DrillbitEndpoint drillbit, boolean current, boolean versionMatch) {
this.address = drillbit.getAddress();
this.userPort = String.valueOf(drillbit.getUserPort());
this.controlPort = String.valueOf(drillbit.getControlPort());
this.dataPort = String.valueOf(drillbit.getDataPort());
this.version = Strings.isNullOrEmpty(drillbit.getVersion()) ? "Undefined" : drillbit.getVersion();
this.current = current;
this.versionMatch = versionMatch;
}
public String getAddress() {
return address;
}
public String getUserPort() { return userPort; }
public String getControlPort() { return controlPort; }
public String getDataPort() { return dataPort; }
public String getVersion() {
return version;
}
public boolean isCurrent() {
return current;
}
public boolean isVersionMatch() {
return versionMatch;
}
/**
* Method used to sort drillbits. Current drillbit goes first.
* Then drillbits with matching versions, after them drillbits with mismatching versions.
* Matching drillbits are sorted according address natural order,
* mismatching drillbits are sorted according version, address natural order.
*
* @param drillbitToCompare drillbit to compare against
* @return -1 if drillbit should be before, 1 if after in list
*/
@Override
public int compareTo(DrillbitInfo drillbitToCompare) {
if (this.isCurrent()) {
return -1;
}
if (drillbitToCompare.isCurrent()) {
return 1;
}
if (this.isVersionMatch() == drillbitToCompare.isVersionMatch()) {
if (this.version.equals(drillbitToCompare.getVersion())) {
return this.address.compareTo(drillbitToCompare.getAddress());
}
return this.version.compareTo(drillbitToCompare.getVersion());
}
return this.versionMatch ? -1 : 1;
}
}
}