/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) 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.wso2.carbon.registry.extensions.handlers;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.RegistryConstants;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.config.RegistryContext;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.jdbc.handlers.Handler;
import org.wso2.carbon.registry.core.jdbc.handlers.RequestContext;
import org.wso2.carbon.registry.core.utils.RegistryUtils;
import org.wso2.carbon.registry.extensions.handlers.utils.RESTServiceUtils;
import org.wso2.carbon.registry.extensions.handlers.utils.SwaggerProcessor;
import org.wso2.carbon.registry.extensions.handlers.utils.WADLProcessor;
import org.wso2.carbon.registry.extensions.utils.CommonConstants;
import org.wso2.carbon.registry.extensions.utils.CommonUtil;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
public class RESTServiceMediaTypeHandler extends Handler {
private static final Log log = LogFactory.getLog(RESTServiceMediaTypeHandler.class);
private static final String INTERFACE_ELEMENT_LOCAL_NAME = "interface";
private static final String SWAGGER_ELEMENT_LOCAL_NAME = "swagger";
private static final String WADL_ELEMENT_LOCAL_NAME = "wadl";
private String swaggerLocation;
private String wadlLocation;
/**
* Extracts the common location for swagger docs from registry.xml entry
*
* @param locationConfiguration location configuration element
*/
public void setSwaggerLocationConfiguration(OMElement locationConfiguration) {
Iterator confElements = locationConfiguration.getChildElements();
while (confElements.hasNext()) {
OMElement confElement = (OMElement) confElements.next();
if (CommonConstants.LOCATION_TAG.equals(confElement.getLocalName())) {
swaggerLocation = confElement.getText();
if (!swaggerLocation.startsWith(RegistryConstants.PATH_SEPARATOR)) {
swaggerLocation = RegistryConstants.PATH_SEPARATOR + swaggerLocation;
}
if (!swaggerLocation.endsWith(RegistryConstants.PATH_SEPARATOR)) {
swaggerLocation = swaggerLocation + RegistryConstants.PATH_SEPARATOR;
}
}
}
}
/**
* Extracts the common location for wadl from registry.xml entry
*
* @param locationConfiguration location configuration element
*/
public void setWadlLocationConfiguration(OMElement locationConfiguration) {
Iterator confElements = locationConfiguration.getChildElements();
while (confElements.hasNext()) {
OMElement confElement = (OMElement) confElements.next();
if (CommonConstants.LOCATION_TAG.equals(confElement.getLocalName())) {
wadlLocation = confElement.getText();
if (!wadlLocation.startsWith(RegistryConstants.PATH_SEPARATOR)) {
wadlLocation = RegistryConstants.PATH_SEPARATOR + wadlLocation;
}
if (!wadlLocation.endsWith(RegistryConstants.PATH_SEPARATOR)) {
wadlLocation = wadlLocation + RegistryConstants.PATH_SEPARATOR;
}
}
}
}
/**
* Processes the PUT action for REST Service artifacts.
*
* @param requestContext information about the current request.
* @throws RegistryException If fails due a handler specific error.
*/
@Override
public void put(RequestContext requestContext) throws RegistryException {
//Acquiring the update lock if available.
if (!CommonUtil.isUpdateLockAvailable()) {
return;
}
CommonUtil.acquireUpdateLock();
Registry registry = requestContext.getRegistry();
Resource resource = requestContext.getResource();
if (resource == null) {
throw new RegistryException(CommonConstants.RESOURCE_NOT_EXISTS);
}
Object resourceContent = resource.getContent();
OMElement serviceInfoElement;
String serviceInfo;
if (resourceContent instanceof String) {
serviceInfo = (String) resourceContent;
} else {
serviceInfo = RegistryUtils.decodeBytes((byte[]) resourceContent);
}
XMLStreamReader reader;
try {
reader = XMLInputFactory.newInstance().createXMLStreamReader(new StringReader(serviceInfo));
StAXOMBuilder builder = new StAXOMBuilder(reader);
serviceInfoElement = builder.getDocumentElement();
} catch (XMLStreamException e) {
StringBuilder msg = new StringBuilder("Error in parsing the service content of the service. ")
.append("The requested path to store the service: ")
.append(requestContext.getResourcePath().getPath()).append(".");
log.error(msg.toString());
throw new RegistryException(msg.toString(), e);
}
String serviceVersion = CommonUtil.getServiceVersion(serviceInfoElement);
if (serviceVersion.length() == 0) {
serviceVersion = CommonConstants.SERVICE_VERSION_DEFAULT_VALUE;
CommonUtil.setServiceVersion(serviceInfoElement, serviceVersion);
resource.setContent(serviceInfoElement.toString());
}
resource.setProperty(RegistryConstants.VERSION_PARAMETER_NAME, serviceVersion);
InputStream inputStream = null;
try {
//Retrieve WADL or Swagger url if available.
String swaggerUrl, wadlUrl;
SwaggerProcessor swaggerProcessor = null;
WADLProcessor wadlProcessor = null;
OMElement interfaceElement = serviceInfoElement.getFirstChildWithName(
new QName(CommonConstants.SERVICE_ELEMENT_NAMESPACE, INTERFACE_ELEMENT_LOCAL_NAME, ""));
String swaggerPath = null, wadlPath = null;
if (interfaceElement != null) {
swaggerUrl = RESTServiceUtils.getDefinitionURL(serviceInfoElement, SWAGGER_ELEMENT_LOCAL_NAME);
wadlUrl = RESTServiceUtils.getDefinitionURL(serviceInfoElement, WADL_ELEMENT_LOCAL_NAME);
interfaceElement.detach();
//Process swagger url if available
if (CommonUtil.isValidUrl(swaggerUrl)) {
requestContext.setSourceURL(swaggerUrl);
swaggerProcessor = new SwaggerProcessor(requestContext, false);
inputStream = new URL(swaggerUrl).openStream();
swaggerPath = swaggerProcessor.processSwagger(inputStream,
getChrootedLocation(requestContext.getRegistryContext(), swaggerLocation), swaggerUrl);
OMElement swaggerElement = interfaceElement.getFirstChildWithName(
new QName(CommonConstants.SERVICE_ELEMENT_NAMESPACE, SWAGGER_ELEMENT_LOCAL_NAME, ""));
swaggerElement.detach();
swaggerElement.setText(swaggerPath);
interfaceElement.addChild(swaggerElement);
}
//Process WADL url if available
if (CommonUtil.isValidUrl(wadlUrl)) {
requestContext.setSourceURL(wadlUrl);
wadlProcessor = new WADLProcessor(requestContext);
wadlProcessor.setCreateService(false);
wadlPath = wadlProcessor.importWADLToRegistry(requestContext, true);
OMElement wadlElement = interfaceElement.getFirstChildWithName(
new QName(CommonConstants.SERVICE_ELEMENT_NAMESPACE, WADL_ELEMENT_LOCAL_NAME, ""));
wadlElement.detach();
wadlElement.setText(wadlPath);
interfaceElement.addChild(wadlElement);
}
serviceInfoElement.addChild(interfaceElement);
}
String servicePath = RESTServiceUtils.addServiceToRegistry(requestContext, serviceInfoElement);
if (StringUtils.isNotBlank(swaggerPath)) {
swaggerProcessor.saveEndpointElement(servicePath);
CommonUtil.addDependency(registry, servicePath, swaggerPath);
}
if (StringUtils.isNotBlank(wadlPath)) {
wadlProcessor.saveEndpointElement(requestContext, servicePath, serviceVersion);
CommonUtil.addDependency(registry, servicePath, wadlPath);
}
requestContext.setProcessingComplete(true);
} catch (IOException e) {
throw new RegistryException("Cannot open a stream for the given URL, " + requestContext.getSourceURL(), e);
} finally {
CommonUtil.releaseUpdateLock();
CommonUtil.closeInputStream(inputStream);
}
}
/**
* Returns the root location of the Swagger.
*
* @param registryContext registry context
* @param resourceLocation resource location
* @return The root location of the Swagger.
*/
private String getChrootedLocation(RegistryContext registryContext, String resourceLocation) {
return RegistryUtils
.getAbsolutePath(registryContext, RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH + resourceLocation);
}
}