/*******************************************************************************
* Copyright (c) 2011 GigaSpaces Technologies Ltd. All rights reserved
*
* Licensed 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.cloudifysource.rest.controllers;
import java.io.IOException;
import java.io.Writer;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import org.cloudifysource.dsl.utils.IPUtils;
import org.cloudifysource.rest.command.CommandManager;
import org.cloudifysource.rest.out.OutputDispatcher;
import org.cloudifysource.rest.util.NotFoundHttpException;
import org.openspaces.admin.Admin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;
/**
* Spring MVC controller for the RESTful Admin API via a reflection-based
* implementation of dispatcher pattern
*
* - Accepts a generic uri path which denotes a specific Admin request
*
* - Parses and walks through the uri by activating getter methods to "dig into"
* the admin object hierarchy
*
* - Results marshaled as a generic document serialized to a JSON object
*
*
* Usage examples: http://localhost:8099/admin/ElasticServiceManagers/Managers
* http://localhost:8099/admin/GridServiceManagers/size
* http://localhost:8099/admin/Spaces
* http://localhost:8099/admin/VirtualMachines/VirtualMachines
* http://localhost:8099/admin/VirtualMachines/VirtualMachines/3
* http://localhost
* :8099/admin/VirtualMachines/VirtualMachines/3/Statistics/Machine
* /GridServiceAgents DETAILS:
* http://localhost:8099/admin/GridServiceManagers/Uids
* /49a6e2ef-5fd3-471a-94ff-c961a52ffd0f STATIST:
* http://localhost:8099/admin/GridServiceManagers
* /Uids/49a6e2ef-5fd3-471a-94ff-c961a52ffd0f
*
* Note that the wiring and marshaling services are provided by Spring framework
*
* Note 2: It is highly recommended that results will be viewed on FF with
* JsonView plugin
*
* @author giladh, adaml
*/
@Controller
@RequestMapping(value = "/admin/*")
public class AdminAPIController {
@Autowired(required = true)
private Admin admin;
private static final Logger logger = Logger
.getLogger(AdminAPIController.class.getName());
/**
* redirects to index view.
*
* @return a ModelAndView object with viewName = index
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView redirectToIndex() {
return new ModelAndView("index");
}
/**
* REST GET requests handler wrapper.
*
* @param httpServletRequest
* The request
* @return The response as a map
* @throws Exception
* Indicates the request failed
*/
@PreAuthorize("isFullyAuthenticated() and hasAnyRole('ROLE_CLOUDADMINS')")
@RequestMapping(value = "/**", method = RequestMethod.GET)
public @ResponseBody
Map<String, Object> get(final HttpServletRequest httpServletRequest)
throws Exception {
return getImplementation(httpServletRequest);
}
/**
* REST GET requests handler implementation Parses uri path activates
* appropriate getters serialize results into a document object and pass for
* JSON marshaling
*
* uri type processing ============ ============== http:/../getArr/ind/...
* => (intermed.) resolve to arr[ind] and continue processing
* http:/../getMap/key/... => (intermed.) resolve to map.get(key) and
* continue processing http:/../getList/ind/... => (intermed.) resolve to
* list(ind) and continue processing http:/../getObj => (final) return obj
* fields (by public getters) http:/../getArr => (final) return arr.length
* http:/../getList => (final) return list.size() http:/../getMap => (final)
* return comma-separated list of map keys
*
*
*/
private Map<String, Object> getImplementation(
final HttpServletRequest httpServletRequest) throws Exception {
// admin acts as root
final CommandManager manager = new CommandManager(httpServletRequest,
getAdmin());
manager.runCommands();
final String hostAddress = getRemoteHostAddress(httpServletRequest);
final String hostContext = httpServletRequest.getContextPath();
return OutputDispatcher.outputResultObjectToMap(manager, hostAddress,
hostContext);
}
private String getRemoteHostAddress(
final HttpServletRequest httpServletRequest) {
final String host = httpServletRequest.getServerName();
final int port = httpServletRequest.getServerPort();
String url = IPUtils.getRestProtocol() + "://" + IPUtils.getSafeIpAddress(host)
+ ":" + port;
return url;
}
public Admin getAdmin() {
return admin;
}
@ExceptionHandler(NotFoundHttpException.class)
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public void resolveNotFound(final Writer writer, final Exception e,
final HttpServletRequest request) throws IOException {
final String requestURL = request.getRequestURL().toString();
logger.log(Level.INFO, "Cannot find URL: " + requestURL, e);
writer.write("{\"status\":\"error\", \"error\":\""
+ "Cannot find URL: " + requestURL + "cause: " + e.getMessage()
+ "\"}");
}
@ExceptionHandler(Exception.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public void resolveInternalServerError(final Writer writer,
final Exception e) throws IOException {
logger.log(Level.WARNING, "caught exception", e);
writer.write("{\"status\":\"error\", \"error\":\"" + e.getMessage()
+ "\"}");
}
}