/*
* Copyright 2014 JBoss Inc
*
* 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 io.apiman.manager.api.rest.impl;
import io.apiman.common.logging.IApimanLogger;
import io.apiman.common.util.MediaType;
import io.apiman.manager.api.beans.download.DownloadBean;
import io.apiman.manager.api.beans.download.DownloadType;
import io.apiman.manager.api.beans.system.SystemStatusBean;
import io.apiman.manager.api.config.Version;
import io.apiman.manager.api.core.IDownloadManager;
import io.apiman.manager.api.core.IStorage;
import io.apiman.manager.api.core.exceptions.StorageException;
import io.apiman.manager.api.core.logging.ApimanLogger;
import io.apiman.manager.api.exportimport.json.JsonExportWriter;
import io.apiman.manager.api.exportimport.json.JsonImportReader;
import io.apiman.manager.api.exportimport.manager.StorageExporter;
import io.apiman.manager.api.exportimport.manager.StorageImportDispatcher;
import io.apiman.manager.api.exportimport.read.IImportReader;
import io.apiman.manager.api.exportimport.write.IExportWriter;
import io.apiman.manager.api.migrator.DataMigrator;
import io.apiman.manager.api.rest.contract.ISystemResource;
import io.apiman.manager.api.rest.contract.exceptions.SystemErrorException;
import io.apiman.manager.api.rest.impl.util.ExceptionFactory;
import io.apiman.manager.api.security.ISecurityContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.MessageFormat;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.BooleanUtils;
/**
* Implementation of the System API.
*
* @author eric.wittmann@redhat.com
*/
@ApplicationScoped
public class SystemResourceImpl implements ISystemResource {
@Inject
private IStorage storage;
@Inject
private ISecurityContext securityContext;
@Inject
private Version version;
@Inject @ApimanLogger(IImportReader.class)
private IApimanLogger importLogger;
@Inject @ApimanLogger(IExportWriter.class)
private IApimanLogger exportLogger;
@Inject
private StorageExporter exporter;
@Inject
private StorageImportDispatcher importer;
@Inject
private DataMigrator migrator;
@Inject
private IDownloadManager downloadManager;
@Context
private HttpServletRequest request;
/**
* Constructor.
*/
public SystemResourceImpl() {
}
/**
* @see io.apiman.manager.api.rest.contract.ISystemResource#getStatus()
*/
@Override
public SystemStatusBean getStatus() {
SystemStatusBean rval = new SystemStatusBean();
rval.setId("apiman-manager-api"); //$NON-NLS-1$
rval.setName("API Manager REST API"); //$NON-NLS-1$
rval.setDescription("The API Manager REST API is used by the API Manager UI to get stuff done. You can use it to automate any apiman task you wish. For example, create new Organizations, Plans, Clients, and APIs."); //$NON-NLS-1$
rval.setMoreInfo("http://www.apiman.io/latest/api-manager-restdocs.html"); //$NON-NLS-1$
rval.setUp(getStorage() != null);
if (getVersion() != null) {
rval.setVersion(getVersion().getVersionString());
rval.setBuiltOn(getVersion().getVersionDate());
}
return rval;
}
/**
* @see io.apiman.manager.api.rest.contract.ISystemResource#exportData(java.lang.String)
*/
@Override
public Response exportData(String download) {
if (BooleanUtils.toBoolean(download)) {
try {
DownloadBean dbean = downloadManager.createDownload(DownloadType.exportJson, "/system/export"); //$NON-NLS-1$
return Response.ok(dbean, MediaType.APPLICATION_JSON).build();
} catch (StorageException e) {
throw new SystemErrorException(e);
}
} else {
if (!securityContext.isAdmin())
throw ExceptionFactory.notAuthorizedException();
return exportData();
}
}
/**
* @see io.apiman.manager.api.rest.contract.ISystemResource#exportData()
*/
@Override
public Response exportData() {
StreamingOutput stream = new StreamingOutput() {
@Override
public void write(OutputStream os) throws IOException, WebApplicationException {
IExportWriter writer = new JsonExportWriter(os, exportLogger);
getExporter().init(writer);
getExporter().export();
os.flush();
}
};
return Response
.ok(stream, MediaType.APPLICATION_JSON)
.header("Content-Disposition", "attachment; filename=api-manager-export.json") //$NON-NLS-1$ //$NON-NLS-2$
.build();
}
/**
* @see io.apiman.manager.api.rest.contract.ISystemResource#importData()
*/
@Override
public Response importData() {
if (!securityContext.isAdmin())
throw ExceptionFactory.notAuthorizedException();
// First, stream the import data to a temporary file. We do this so
// that we can stream the import logging statements back to the HTTP
// response. We can't stream the inbound data into the importer
// *and* stream the importer's logging output back to the HTTP
// response at the same time due to the nature of HTTP.
File tempFile;
InputStream data;
try {
tempFile = File.createTempFile("apiman_import", ".json"); //$NON-NLS-1$ //$NON-NLS-2$
tempFile.deleteOnExit();
data = request.getInputStream();
FileUtils.copyInputStreamToFile(data, tempFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
final File importFile = tempFile;
// Next, do the import and stream the import logging output back to
// the HTTP response output stream.
StreamingOutput stream = new StreamingOutput() {
@Override
public void write(final OutputStream output) throws IOException, WebApplicationException {
final PrintWriter writer = new PrintWriter(output);
IApimanLogger logger = new IApimanLogger() {
@Override
public void warn(String message) {
writer.println("WARN: " + message); //$NON-NLS-1$
writer.flush();
}
@Override
public void warn(String message, Object... args) {
warn(MessageFormat.format(message, args));
}
@Override
public void trace(String message) {
writer.println("TRACE: " + message); //$NON-NLS-1$
writer.flush();
}
@Override
public void trace(String message, Object... args) {
trace(MessageFormat.format(message, args));
}
@Override
public void info(String message) {
writer.println("INFO: " + message); //$NON-NLS-1$
writer.flush();
}
@Override
public void info(String message, Object... args) {
info(MessageFormat.format(message, args));
}
@Override
public void error(String message, Throwable error) {
writer.println("ERROR: " + message); //$NON-NLS-1$
error.printStackTrace(writer);
writer.flush();
}
@Override
public void error(Throwable error) {
writer.println("ERROR: " + error.getMessage()); //$NON-NLS-1$
error.printStackTrace(writer);
writer.flush();
}
@Override
public void error(Throwable error, String message, Object... args) {
error(MessageFormat.format(message, args), error);
}
@Override
public void debug(String message) {
writer.println("DEBUG: " + message); //$NON-NLS-1$
writer.flush();
}
@Override
public void debug(String message, Object... args) {
debug(MessageFormat.format(message, args));
}
};
File migratedImportFile = File.createTempFile("apiman_import_migrated", ".json"); //$NON-NLS-1$ //$NON-NLS-2$
migratedImportFile.deleteOnExit();
// Migrate the data (if necessary)
migrator.setLogger(logger);
migrator.migrate(importFile, migratedImportFile);
// Now import the migrated data
InputStream importData = null;
IImportReader reader;
try {
importData = new FileInputStream(migratedImportFile);
reader = new JsonImportReader(logger, importData);
} catch (IOException e) {
IOUtils.closeQuietly(importData);
throw new SystemErrorException(e);
}
try {
importer.setLogger(logger);
importer.start();
reader.setDispatcher(importer);
reader.read();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
IOUtils.closeQuietly(importData);
FileUtils.deleteQuietly(importFile);
FileUtils.deleteQuietly(migratedImportFile);
}
}
};
return Response.ok(stream).build();
}
/**
* @return the storage
*/
public IStorage getStorage() {
return storage;
}
/**
* @param storage the storage to set
*/
public void setStorage(IStorage storage) {
this.storage = storage;
}
/**
* @return the version
*/
public Version getVersion() {
return version;
}
/**
* @param version the version to set
*/
public void setVersion(Version version) {
this.version = version;
}
/**
* @return the exporter
*/
public StorageExporter getExporter() {
return exporter;
}
/**
* @param exporter the exporter to set
*/
public void setExporter(StorageExporter exporter) {
this.exporter = exporter;
}
/**
* @return the securityContext
*/
public ISecurityContext getSecurityContext() {
return securityContext;
}
/**
* @param securityContext the securityContext to set
*/
public void setSecurityContext(ISecurityContext securityContext) {
this.securityContext = securityContext;
}
}