/* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*
*/
package com.emc.storageos.api.service.impl.resource.utils;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
import com.emc.storageos.cinder.model.UsageAndLimits;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
public class CinderApiUtils {
private static final Logger _log = LoggerFactory.getLogger(CinderApiUtils.class);
private CinderApiUtils() {
}
private static final String XML = "xml";
private static final String JSON = "json";
private static final String ACCEPT = "Accept";
private static final String XML_REGULAR_EXP = ".*application/xml.*";
private static final String JSON_REGULAR_EXP = ".*application/json.*";
/**
* Unmodifiable map used to keep key value for the Http Response code
*/
private static final Map<Integer, String> ERROR_CODE_MAP =
Collections.unmodifiableMap(new HashMap<Integer, String>() {
private static final long serialVersionUID = 1L;
{
put(400, "badRequest");
put(404, "itemNotFound");
}
});
/**
* method for getting http response based on Pojo and http header
*
* @param obj Pojo object
* @param obj header http request header expectedcode
* @return Response Object
*/
public static Response getCinderResponse(Object obj, HttpHeaders header, boolean isJsonRootElementRequired, int expectedCode) {
String mediaType = getMediaType(header);
if (StringUtils.isNotEmpty(mediaType)) {
if (mediaType.equals(XML)) {
_log.debug("Requested Media type : XML");
return Response.ok().entity(obj).build();
} else if (mediaType.equals(JSON)) {
_log.debug("Requested Media type : JSON");
ObjectMapper objectMapper = new ObjectMapper();
if (isJsonRootElementRequired) {
objectMapper.enable(SerializationConfig.Feature.WRAP_ROOT_VALUE);
}
try {
String jsonResponse = objectMapper.writeValueAsString(obj);
_log.debug("Expected return code ={}",expectedCode);
return Response.status(expectedCode).entity(jsonResponse).build();
} catch (JsonGenerationException e) {
throw APIException.badRequests.parameterIsNotValid(obj.getClass().getName());
} catch (JsonMappingException e) {
throw APIException.badRequests.parameterIsNotValid(obj.getClass().getName());
} catch (IOException e) {
throw APIException.internalServerErrors.ioWriteError(obj.getClass().getName());
}
}
}
return Response.status(415).entity("Unsupported Media Type")
.build();
}
/**
* method for getting media type based on http header
*
* @param header http header request
* @return media type in String
*/
public static String getMediaType(HttpHeaders header) {
Pattern jsonPattern = Pattern.compile(JSON_REGULAR_EXP);
Pattern xmlPattern = Pattern.compile(XML_REGULAR_EXP);
MultivaluedMap<String, String> headersInfo = header.getRequestHeaders();
List<String> mediaTypes = headersInfo.get(ACCEPT);
for (String mediaType : mediaTypes) {
if (jsonPattern.matcher(mediaType).matches()) {
return JSON;
} else if (xmlPattern.matcher(mediaType).matches()) {
return XML;
}
}
return null;
}
/**
* This function converts Map to xml format
*
* @param map Hash Map
* @param root root Element Name
* @return XML object in String form
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws DOMException
*/
public static Object convertMapToXML(Map<String, ? extends Object> map, String root,Class<?> clazz) throws DOMException, IllegalArgumentException, IllegalAccessException {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder;
Document document = null;
LSSerializer lsSerializer = null;
try {
documentBuilder = documentBuilderFactory.newDocumentBuilder();
document = documentBuilder.newDocument();
Element rootElement = document.createElement(root);
if (null != rootElement) {
document.appendChild(rootElement);
for (Entry<String, ? extends Object> entry : map.entrySet()) {
Element mapElement = document.createElement(entry.getKey());
if(entry.getValue() instanceof String){
mapElement.setTextContent(entry.getValue().toString());
}
else{
Method[] methods = clazz.getDeclaredMethods();
String getterPrefix = "get";
for ( Method method : methods ) {
String methodName = method.getName();
if(methodName.startsWith("get")){
String fieldName = methodName.substring(getterPrefix.length(),getterPrefix.length()+1).toLowerCase();
fieldName = fieldName + methodName.substring(getterPrefix.length()+1);
Element subElement = document.createElement(fieldName);
try {
subElement.setTextContent(String.valueOf(method.invoke(clazz.cast(entry.getValue()))));
} catch (SecurityException e) {
_log.info("The getter method {} for the field led to security exception {}", methodName);
}catch (Exception e) {
_log.info("The getter method {} for the field failed with exception {}", methodName, e.toString());
}
mapElement.appendChild(subElement);
}
}
}
rootElement.appendChild(mapElement);
}
}
DOMImplementationLS domImplementation = (DOMImplementationLS) document
.getImplementation();
lsSerializer = domImplementation.createLSSerializer();
} catch (ParserConfigurationException e) {
throw APIException.internalServerErrors.ioWriteError(root);
}
return lsSerializer.writeToString(document);
}
/**
* Create error message according to OpenStack environment in JSON
*
* @param errCode
* Response error code
* @param errMsg
* Error message
* JSON Message should be in this format:
* {"badRequest":{"message":"Invalid volume: Volume still has 1 dependent snapshots", "code":400}}
*/
public static Response createErrorResponse(int errCode, String errMsg) {
JSONObject outerJsonObj = new JSONObject();
JSONObject innerJsonObj = new JSONObject();
try {
outerJsonObj.put(ERROR_CODE_MAP.get(errCode), innerJsonObj);
innerJsonObj.put("code", errCode);
innerJsonObj.put("message", errMsg);
} catch (JSONException e) {
_log.error("Error occured while creating JSON error message");
}
return Response.status(errCode).entity(outerJsonObj.toString()).build();
}
/**
* Util function to split the string and send the value at required position
*
* @param str
* String to split
* @param delimiter
* @param position
* @return
*/
public static String splitString(String str, String delimiter, int position) {
String[] stringArray = str.split(delimiter);
return stringArray[position];
}
/**
* Format the Calendar instance
*
* @param cal
* @return Formatted calendar
*/
public static String timeFormat(Calendar cal) {
return new java.text.SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z").format(cal.getTimeInMillis());
}
}