/*******************************************************************************
* Copyright (c) 2015 IBH SYSTEMS GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBH SYSTEMS GmbH - initial API and implementation
*******************************************************************************/
package org.eclipse.packagedrone.repo.importer.http;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.mail.internet.ContentDisposition;
import javax.mail.internet.ParseException;
import org.eclipse.packagedrone.VersionInformation;
import org.eclipse.packagedrone.job.JobInstance.Context;
import org.eclipse.packagedrone.repo.importer.ImportContext;
import org.eclipse.packagedrone.repo.importer.Importer;
import org.eclipse.packagedrone.repo.importer.ImporterDescription;
import org.eclipse.packagedrone.repo.importer.SimpleImporterDescription;
import org.eclipse.packagedrone.utils.Strings;
import org.eclipse.packagedrone.web.LinkTarget;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class HttpImporter implements Importer
{
private final static Logger logger = LoggerFactory.getLogger ( HttpImporter.class );
public static final String ID = "http";
private static final SimpleImporterDescription DESCRIPTION;
private static final int COPY_BUFFER_SIZE = Integer.getInteger ( "drone.importer.http.copyBufferSize", 4096 * 10 );
private final Gson gson;
public HttpImporter ()
{
this.gson = new GsonBuilder ().create ();
}
static
{
DESCRIPTION = new SimpleImporterDescription ();
DESCRIPTION.setId ( ID );
DESCRIPTION.setLabel ( "HTTP Importer" );
DESCRIPTION.setDescription ( "Import artifacts by downloading the provided URL" );
DESCRIPTION.setStartTarget ( new LinkTarget ( "/import/{token}/http/start" ) );
}
@Override
public ImporterDescription getDescription ()
{
return DESCRIPTION;
}
@Override
public void runImport ( final ImportContext context, final String configuration ) throws Exception
{
final Configuration cfg = this.gson.fromJson ( configuration, Configuration.class );
logger.debug ( "Get URL: {}", cfg.getUrl () );
final URL url = new URL ( cfg.getUrl () );
final Path file = Files.createTempFile ( "import", null );
final URLConnection con = url.openConnection ();
con.setRequestProperty ( "User-Agent", VersionInformation.USER_AGENT );
String name;
final Context job = context.getJobContext ();
try ( final InputStream in = con.getInputStream ();
OutputStream out = new BufferedOutputStream ( new FileOutputStream ( file.toFile () ) ) )
{
final long length = con.getContentLengthLong ();
if ( length > 0 )
{
job.beginWork ( String.format ( "Downloading %s", Strings.bytes ( length ) ), length );
}
// manual copy
final byte[] buffer = new byte[COPY_BUFFER_SIZE];
int rc;
while ( ( rc = in.read ( buffer ) ) > 0 )
{
out.write ( buffer, 0, rc );
job.worked ( rc );
}
job.complete ();
// get the name inside here, since this will properly clean up if something fails
name = makeName ( cfg, url, con );
if ( name == null )
{
throw new IllegalStateException ( String.format ( "Unable to determine name for %s", cfg.getUrl () ) );
}
}
catch ( final Exception e )
{
logger.debug ( "Failed to download", e );
Files.deleteIfExists ( file );
throw e;
}
context.scheduleImport ( file, name );
}
public static String makeName ( final Configuration cfg, final URL url, final URLConnection con )
{
String name = cfg.getAlternateName ();
if ( name == null || name.isEmpty () )
{
name = fromContentDisposition ( con.getHeaderField ( "Content-Disposition" ) );
}
if ( name == null || name.isEmpty () )
{
name = fromPath ( url.getPath () );
}
return name;
}
private static String fromContentDisposition ( final String field )
{
if ( field == null || field.isEmpty () )
{
return null;
}
try
{
final ContentDisposition cd = new ContentDisposition ( field );
return cd.getParameter ( "filename" );
}
catch ( final ParseException e )
{
return null;
}
}
private static String fromPath ( final String path )
{
if ( path == null )
{
return null;
}
final String[] segs = path.split ( "/" );
if ( segs.length == 0 )
{
return null;
}
return segs[segs.length - 1];
}
}