blob: 706abb73bed723a375167e325e581777a0cee552 [file] [log] [blame]
/**
* 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.hadoop.gateway.service.admin;
import org.apache.hadoop.gateway.services.GatewayServices;
import org.apache.hadoop.gateway.config.GatewayConfig;
import org.apache.hadoop.gateway.services.topology.TopologyService;
import org.apache.hadoop.gateway.topology.Topology;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.MediaType.APPLICATION_XML;
import static javax.ws.rs.core.Response.ok;
@Path("/api/v1")
public class TopologiesResource {
@Context
private HttpServletRequest request;
@GET
@Produces({APPLICATION_JSON, APPLICATION_XML})
@Path("topologies/{id}")
public Topology getTopology(@PathParam("id") String id) {
GatewayServices services = (GatewayServices) request.getServletContext()
.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
GatewayConfig config = (GatewayConfig) request.getServletContext().getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
TopologyService ts = services.getService(GatewayServices.TOPOLOGY_SERVICE);
for (Topology t : ts.getTopologies()) {
if(t.getName().equals(id)) {
try {
t.setUri(new URI( buildURI(t, config, request) ));
} catch (URISyntaxException se) {
t.setUri(null);
}
return t;
}
}
return null;
}
@GET
@Produces({APPLICATION_JSON, APPLICATION_XML})
@Path("topologies")
public SimpleTopologyWrapper getTopologies() {
GatewayServices services = (GatewayServices) request.getServletContext()
.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
TopologyService ts = services.getService(GatewayServices.TOPOLOGY_SERVICE);
ArrayList<SimpleTopology> st = new ArrayList<SimpleTopology>();
GatewayConfig conf = (GatewayConfig) request.getServletContext().getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
for (Topology t : ts.getTopologies()) {
st.add(getSimpleTopology(t, conf));
}
Collections.sort(st, new TopologyComparator());
SimpleTopologyWrapper stw = new SimpleTopologyWrapper();
for(SimpleTopology t : st){
stw.topologies.add(t);
}
return stw;
}
@PUT
@Consumes({APPLICATION_JSON, APPLICATION_XML})
@Path("topologies/{id}")
public Topology uploadTopology(@PathParam("id") String id, Topology t) {
GatewayServices gs = (GatewayServices) request.getServletContext()
.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
t.setName(id);
TopologyService ts = gs.getService(GatewayServices.TOPOLOGY_SERVICE);
ts.deployTopology(t);
return getTopology(id);
}
@DELETE
@Produces(APPLICATION_JSON)
@Path("topologies/{id}")
public Response deleteTopology(@PathParam("id") String id) {
boolean deleted = false;
if(!id.equals("admin")) {
GatewayServices services = (GatewayServices) request.getServletContext()
.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
TopologyService ts = services.getService(GatewayServices.TOPOLOGY_SERVICE);
for (Topology t : ts.getTopologies()) {
if(t.getName().equals(id)) {
ts.deleteTopology(t);
deleted = true;
}
}
}else{
deleted = false;
}
return ok().entity("{ \"deleted\" : " + deleted + " }").build();
}
private class TopologyComparator implements Comparator<SimpleTopology> {
@Override
public int compare(SimpleTopology t1, SimpleTopology t2) {
return t1.getName().compareTo(t2.getName());
}
}
String buildURI(Topology topology, GatewayConfig config, HttpServletRequest req){
String uri = buildXForwardBaseURL(req);
// Strip extra context
uri = uri.replace(req.getContextPath(), "");
// Add the gateway path
String gatewayPath;
if(config.getGatewayPath() != null){
gatewayPath = config.getGatewayPath();
}else{
gatewayPath = "gateway";
}
uri += "/" + gatewayPath;
uri += "/" + topology.getName();
return uri;
}
String buildHref(Topology t, HttpServletRequest req) {
String href = buildXForwardBaseURL(req);
// Make sure that the pathInfo doesn't have any '/' chars at the end.
String pathInfo = req.getPathInfo();
if(pathInfo.endsWith("/")) {
while(pathInfo.endsWith("/")) {
pathInfo = pathInfo.substring(0, pathInfo.length() - 1);
}
}
href += pathInfo + "/" + t.getName();
return href;
}
private SimpleTopology getSimpleTopology(Topology t, GatewayConfig config) {
String uri = buildURI(t, config, request);
String href = buildHref(t, request);
return new SimpleTopology(t, uri, href);
}
private String buildXForwardBaseURL(HttpServletRequest req){
final String X_Forwarded = "X-Forwarded-";
final String X_Forwarded_Context = X_Forwarded + "Context";
final String X_Forwarded_Proto = X_Forwarded + "Proto";
final String X_Forwarded_Host = X_Forwarded + "Host";
final String X_Forwarded_Port = X_Forwarded + "Port";
final String X_Forwarded_Server = X_Forwarded + "Server";
String baseURL = "";
// Get Protocol
if(req.getHeader(X_Forwarded_Proto) != null){
baseURL += req.getHeader(X_Forwarded_Proto) + "://";
} else {
baseURL += req.getProtocol() + "://";
}
// Handle Server/Host and Port Here
if (req.getHeader(X_Forwarded_Host) != null && req.getHeader(X_Forwarded_Port) != null){
// Double check to see if host has port
if(req.getHeader(X_Forwarded_Host).contains(req.getHeader(X_Forwarded_Port))){
baseURL += req.getHeader(X_Forwarded_Host);
} else {
// If there's no port, add the host and port together;
baseURL += req.getHeader(X_Forwarded_Host) + ":" + req.getHeader(X_Forwarded_Port);
}
} else if(req.getHeader(X_Forwarded_Server) != null && req.getHeader(X_Forwarded_Port) != null){
// Tack on the server and port if they're available. Try host if server not available
baseURL += req.getHeader(X_Forwarded_Server) + ":" + req.getHeader(X_Forwarded_Port);
} else if(req.getHeader(X_Forwarded_Port) != null) {
// if we at least have a port, we can use it.
baseURL += req.getServerName() + ":" + req.getHeader(X_Forwarded_Port);
} else {
// Resort to request members
baseURL += req.getServerName() + ":" + req.getLocalPort();
}
// Handle Server context
if( req.getHeader(X_Forwarded_Context) != null ) {
baseURL += req.getHeader( X_Forwarded_Context );
} else {
baseURL += req.getContextPath();
}
return baseURL;
}
// Uses member request variable
private String buildXForwardBaseURL(){
return buildXForwardBaseURL(request);
}
@XmlAccessorType(XmlAccessType.NONE)
public static class SimpleTopology {
@XmlElement
private String name;
@XmlElement
private String timestamp;
@XmlElement
private String uri;
@XmlElement
private String href;
public SimpleTopology() {}
public SimpleTopology(Topology t, String uri, String href) {
this.name = t.getName();
this.timestamp = Long.toString(t.getTimestamp());
this.uri = uri;
this.href = href;
}
public String getName() {
return name;
}
public void setName(String n) {
name = n;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
public static class SimpleTopologyWrapper{
@XmlElement(name="topology")
@XmlElementWrapper(name="topologies")
private List<SimpleTopology> topologies = new ArrayList<SimpleTopology>();
public List<SimpleTopology> getTopologies(){
return topologies;
}
public void setTopologies(List<SimpleTopology> ts){
this.topologies = ts;
}
}
}