blob: 316690138a0e6b3b49da3441479209e78141a617 [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.knox.gateway.util;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.knox.gateway.GatewayMessages;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
import org.apache.knox.gateway.model.DescriptorConfiguration;
import org.apache.knox.gateway.model.ProviderConfiguration;
import org.apache.knox.gateway.model.Topology;
import org.xml.sax.SAXException;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Locale;
/**
* A helper class to convert topology xml file to descriptor and provider
* model.
*/
public class TopologyToDescriptor {
private static final GatewayMessages LOG = MessagesFactory
.get(GatewayMessages.class);
private static final ObjectMapper mapper = new ObjectMapper();
private static final String SCHEMA_FILE = "/conf/topology-v1.xsd";
static {
/* skip printing out null fields */
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
private String topologyPath;
private String providerName;
private String descriptorName;
private String discoveryUrl;
private String discoveryUser;
private String discoveryPasswordAlias;
private String discoveryType;
private String cluster;
private String providerConfigDir;
private String descriptorConfigDir;
private boolean force;
public TopologyToDescriptor() {
super();
}
/**
* A function that validates the given topology
*/
private void validateTopology(final String xsd, final String topologyFile)
throws IOException, SAXException {
try (InputStream topologyFileStream = Files
.newInputStream(Paths.get(topologyFile))) {
final Source xmlSource = new StreamSource(topologyFileStream);
final Schema schema = getSchema(xsd);
final Validator validator = schema.newValidator();
validator.validate(xmlSource);
} catch (IOException | SAXException e) {
LOG.errorValidatingTopology(topologyFile);
throw e;
}
}
private Topology parseTopology(final String xsd, final String topologyFile)
throws JAXBException, SAXException, IOException {
try (InputStream topologyFileStream = Files
.newInputStream(Paths.get(topologyFile))) {
final Schema schema = getSchema(xsd);
final JAXBContext jc = JAXBContext.newInstance(Topology.class);
final Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setSchema(schema);
return (Topology) unmarshaller.unmarshal(topologyFileStream);
} catch (SAXException | JAXBException | IOException e) {
LOG.errorParsingTopology(topologyFile);
throw e;
}
}
private Schema getSchema(final String xsd) throws SAXException {
final SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
final URL schemaUrl = TopologyToDescriptor.class.getResource(xsd);
return schemaFactory.newSchema(schemaUrl);
}
/**
* Validate topology
*
* @throws IOException Exception on validating file.
* @throws SAXException Exception on parsing XML.
*/
public void validate() throws IOException, SAXException {
validateTopology(SCHEMA_FILE, topologyPath);
}
/**
* Convert topology to provider and descriptor
*
* @throws IOException Exception on validating file.
* @throws JAXBException Exception on parsing XML.
* @throws SAXException Exception on parsing XML.
*/
public void convert() throws IOException, JAXBException, SAXException {
final Topology topology = parseTopology(SCHEMA_FILE, topologyPath);
saveProvider(topology);
saveDescriptor(topology, providerName);
}
private void saveProvider(final Topology topology) throws IOException {
try {
final ProviderConfiguration provider = new ProviderConfiguration();
if (topology.getProviders() != null) {
provider.setProviders(topology.getProviders());
}
final File providerFile = new File(
providerConfigDir + File.separator + providerName);
fileCheck(providerFile);
mapper.writerWithDefaultPrettyPrinter()
.writeValue(providerFile, provider);
} catch (final IOException e) {
LOG.errorSavingProviderConfiguration(providerName, topologyPath,
e.toString());
throw e;
}
}
private void saveDescriptor(final Topology topology,
final String providerName) throws IOException {
final DescriptorConfiguration descriptorConfiguration = new DescriptorConfiguration();
descriptorConfiguration
.setProviderConfig(FilenameUtils.removeExtension(providerName));
if (!StringUtils.isBlank(discoveryUrl)) {
descriptorConfiguration.setDiscoveryAddress(discoveryUrl);
}
if (!StringUtils.isBlank(discoveryUser)) {
descriptorConfiguration.setDiscoveryUser(discoveryUser);
}
if (!StringUtils.isBlank(discoveryPasswordAlias)) {
descriptorConfiguration.setDiscoveryPasswordAlias(discoveryPasswordAlias);
}
if (!StringUtils.isBlank(discoveryType)) {
descriptorConfiguration.setDiscoveryType(discoveryType);
}
if (!StringUtils.isBlank(cluster)) {
descriptorConfiguration.setCluster(cluster);
}
if (topology.getName() != null) {
descriptorConfiguration.setName(topology.getName());
}
if (topology.getApplications() != null) {
descriptorConfiguration.setApplications(topology.getApplications());
}
if (topology.getServices() != null) {
descriptorConfiguration.setServices(topology.getServices());
}
final File descriptorFile = new File(
descriptorConfigDir + File.separator + descriptorName);
fileCheck(descriptorFile);
try {
mapper.writerWithDefaultPrettyPrinter()
.writeValue(descriptorFile, descriptorConfiguration);
} catch (IOException e) {
LOG.errorSavingDescriptorConfiguration(descriptorName, topologyPath,
e.toString());
throw e;
}
}
/**
* Check whether the file exists and can be overwritten.
*
* @param file
* @throws IOException
*/
private void fileCheck(final File file) throws IOException {
if (!force && file.exists()) {
throw new IOException(String
.format(Locale.ROOT, "File %s already exist, use --force option to overwrite.",
file.getAbsolutePath()));
}
/* make sure file and directories are in place */
Files.createDirectories(file.toPath().getParent());
file.createNewFile();
}
public void setDiscoveryUrl(String discoveryUrl) {
this.discoveryUrl = discoveryUrl;
}
public void setDiscoveryUser(String discoveryUser) {
this.discoveryUser = discoveryUser;
}
public void setDiscoveryPasswordAlias(String discoveryPasswordAlias) {
this.discoveryPasswordAlias = discoveryPasswordAlias;
}
public void setDiscoveryType(String discoveryType) {
this.discoveryType = discoveryType;
}
public void setCluster(String cluster) {
this.cluster = cluster;
}
public void setTopologyPath(String topologyPath) {
this.topologyPath = topologyPath;
}
public void setProviderName(String providerName) {
this.providerName = providerName;
}
public void setDescriptorName(String descriptorName) {
this.descriptorName = descriptorName;
}
public void setProviderConfigDir(String providerConfigDir) {
this.providerConfigDir = providerConfigDir;
}
public void setDescriptorConfigDir(String descriptorConfigDir) {
this.descriptorConfigDir = descriptorConfigDir;
}
public void setForce(boolean force) {
this.force = force;
}
}