com.limegroup.gnutella.archive.ArchiveContribution.java Source code

Java tutorial

Introduction

Here is the source code for com.limegroup.gnutella.archive.ArchiveContribution.java

Source

package com.limegroup.gnutella.archive;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPConnectionClosedException;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.io.CopyStreamException;
import org.apache.xerces.dom3.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;

import com.limegroup.gnutella.util.CommonUtils;

abstract class ArchiveContribution extends AbstractContribution {

    /**
     * @param media
     *        One of ArchiveConstants.MEDIA_*
     *        
     * @throws IllegalArgumentException
     *         If media is not valid
     */
    public ArchiveContribution(String username, String password, String title, String description, int media)
            throws DescriptionTooShortException {
        this(username, password, title, description, media, Archives.defaultCollectionForMedia(media),
                Archives.defaultTypesForMedia(media));
    }

    public ArchiveContribution(String username, String password, String title, String description, int media,
            int collection, int type) throws DescriptionTooShortException {
        setUsername(username);
        setPassword(password);
        setTitle(title);
        setDescription(description);
        setMedia(media);
        setCollection(collection);
        setType(type);
    }

    abstract protected String getFtpServer();

    abstract protected String getFtpPath();

    abstract protected boolean isFtpDirPreMade();

    abstract protected void checkin() throws IOException;

    /**
     * 
     * @throws UnknownHostException
     *         If the hostname cannot be resolved.
     *         
     * @throws SocketException
     *         If the socket timeout could not be set.
     *         
     * @throws FTPConnectionClosedException
     *         If the connection is closed by the server.
     *         
     * @throws LoginFailedException
     *         If the login fails.
     *         
     * @throws DirectoryChangeFailedException
     *         If changing to the directory provided by the internet
     *         archive fails.
     *         
     * @throws CopyStreamException
     *         If an I/O error occurs while in the middle of
     *         transferring a file.
     *         
     * @throws IOException
     *         If an I/O error occurs while sending a command or
     *         receiving a reply from the server
     *         
     * @throws IllegalStateException
     *          If the contribution object is not ready to upload
     *          (no username, password, server, etc. set)
     *          or if java's xml parser is configured badly
     */

    public void upload()
            throws UnknownHostException, SocketException, FTPConnectionClosedException, LoginFailedException,
            DirectoryChangeFailedException, CopyStreamException, RefusedConnectionException, IOException {

        final int NUM_XML_FILES = 2;
        final String META_XML_SUFFIX = "_meta.xml";
        final String FILES_XML_SUFFIX = "_files.xml";

        final String username = getUsername();
        final String password = getPassword();

        if (getFtpServer() == null) {
            throw new IllegalStateException("ftp server not set");
        }
        if (getFtpPath() == null) {
            throw new IllegalStateException("ftp path not set");
        }
        if (username == null) {
            throw new IllegalStateException("username not set");
        }
        if (password == null) {
            throw new IllegalStateException("password not set");
        }

        // calculate total number of files and bytes

        final String metaXmlString = serializeDocument(getMetaDocument());
        final String filesXmlString = serializeDocument(getFilesDocument());

        final byte[] metaXmlBytes = metaXmlString.getBytes();
        final byte[] filesXmlBytes = filesXmlString.getBytes();

        final int metaXmlLength = metaXmlBytes.length;
        final int filesXmlLength = filesXmlBytes.length;

        final Collection files = getFiles();

        final int totalFiles = NUM_XML_FILES + files.size();

        final String[] fileNames = new String[totalFiles];
        final long[] fileSizes = new long[totalFiles];

        final String metaXmlName = getIdentifier() + META_XML_SUFFIX;
        fileNames[0] = metaXmlName;
        fileSizes[0] = metaXmlLength;

        final String filesXmlName = getIdentifier() + FILES_XML_SUFFIX;
        fileNames[1] = filesXmlName;
        fileSizes[1] = filesXmlLength;

        int j = 2;
        for (Iterator i = files.iterator(); i.hasNext();) {
            final File f = (File) i.next();
            fileNames[j] = f.getRemoteFileName();
            fileSizes[j] = f.getFileSize();
            j++;
        }

        // init the progress mapping
        for (int i = 0; i < fileSizes.length; i++) {
            _fileNames2Progress.put(fileNames[i], new UploadFileProgress(fileSizes[i]));
            _totalUploadSize += fileSizes[i];
        }

        FTPClient ftp = new FTPClient();

        try {
            // first connect

            if (isCancelled()) {
                return;
            }
            ftp.enterLocalPassiveMode();

            if (isCancelled()) {
                return;
            }
            ftp.connect(getFtpServer());

            final int reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                throw new RefusedConnectionException(getFtpServer() + "refused FTP connection");
            }
            // now login
            if (isCancelled()) {
                return;
            }
            if (!ftp.login(username, password)) {
                throw new LoginFailedException();
            }

            try {

                // try to change the directory
                if (!ftp.changeWorkingDirectory(getFtpPath())) {
                    // if changing fails, make the directory
                    if (!isFtpDirPreMade() && !ftp.makeDirectory(getFtpPath())) {
                        throw new DirectoryChangeFailedException();
                    }

                    // now change directory, if it fails again bail
                    if (isCancelled()) {
                        return;
                    }
                    if (!ftp.changeWorkingDirectory(getFtpPath())) {
                        throw new DirectoryChangeFailedException();
                    }
                }

                if (isCancelled()) {
                    return;
                }
                connected();

                // upload xml files
                uploadFile(metaXmlName, new ByteArrayInputStream(metaXmlBytes), ftp);

                uploadFile(filesXmlName, new ByteArrayInputStream(filesXmlBytes), ftp);

                // now switch to binary mode
                if (isCancelled()) {
                    return;
                }
                ftp.setFileType(FTP.BINARY_FILE_TYPE);

                // upload contributed files
                for (final Iterator i = files.iterator(); i.hasNext();) {
                    final File f = (File) i.next();

                    uploadFile(f.getRemoteFileName(), new FileInputStream(f.getIOFile()), ftp);
                }
            } catch (InterruptedIOException ioe) {
                // we've been requested to cancel
                return;
            } finally {
                ftp.logout(); // we don't care if logging out fails
            }
        } finally {
            try {
                ftp.disconnect();
            } catch (IOException e) {
            } // don't care if disconnecting fails
        }

        // now tell the Internet Archive that we're done
        if (isCancelled()) {
            return;
        }
        checkinStarted();

        if (isCancelled()) {
            return;
        }
        checkin();

        if (isCancelled()) {
            return;
        }
        checkinCompleted();
    }

    /**
     * 
     * @param fileName
     * @param input
     *         The input stream (not necessarily buffered).
     *        This stream will be closed by this method
     */
    private void uploadFile(String remoteFileName, InputStream input, FTPClient ftp)
            throws InterruptedIOException, IOException {
        fileStarted(remoteFileName);
        final InputStream fileStream = new BufferedInputStream(new UploadMonitorInputStream(input, this));

        try {
            if (isCancelled()) {
                throw new InterruptedIOException();
            }

            ftp.storeFile(remoteFileName, fileStream);
        } finally {
            fileStream.close();
        }

        if (isCancelled()) {
            throw new InterruptedIOException();
        }
        fileCompleted();
    }

    /**
     * @throws    IllegalStateException
     *          If java's xml parser configuration is bad
     */
    private Document getMetaDocument() {

        /*
         * Sample _meta.xml file:
         * 
         * <metadata>
         *   <collection>opensource_movies</collection>
         *   <mediatype>movies</mediatype>
         *   <title>My Home Movie</title>
         *   <runtime>2:30</runtime>
         *   <director>Joe Producer</director>
         * </metadata>    
         * 
         */

        final String METADATA_ELEMENT = "metadata";
        final String COLLECTION_ELEMENT = "collection";
        final String MEDIATYPE_ELEMENT = "mediatype";
        final String TITLE_ELEMENT = "title";
        final String DESCRIPTION_ELEMENT = "description";
        final String LICENSE_URL_ELEMENT = "licenseurl";
        final String UPLOAD_APPLICATION_ELEMENT = "upload_application";
        final String APPID_ATTR = "appid";
        final String APPID_ATTR_VALUE = "LimeWire";
        final String VERSION_ATTR = "version";
        final String UPLOADER_ELEMENT = "uploader";
        final String IDENTIFIER_ELEMENT = "identifier";
        final String TYPE_ELEMENT = "type";

        try {
            final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            final DocumentBuilder db = dbf.newDocumentBuilder();
            final Document document = db.newDocument();

            final Element metadataElement = document.createElement(METADATA_ELEMENT);
            document.appendChild(metadataElement);

            final Element collectionElement = document.createElement(COLLECTION_ELEMENT);
            metadataElement.appendChild(collectionElement);
            collectionElement.appendChild(document.createTextNode(Archives.getCollectionString(getCollection())));

            final Element mediatypeElement = document.createElement(MEDIATYPE_ELEMENT);
            metadataElement.appendChild(mediatypeElement);
            mediatypeElement.appendChild(document.createTextNode(Archives.getMediaString(getMedia())));

            final Element typeElement = document.createElement(TYPE_ELEMENT);
            metadataElement.appendChild(typeElement);
            typeElement.appendChild(document.createTextNode(Archives.getTypeString(getType())));

            final Element titleElement = document.createElement(TITLE_ELEMENT);
            metadataElement.appendChild(titleElement);
            titleElement.appendChild(document.createTextNode(getTitle()));

            final Element descriptionElement = document.createElement(DESCRIPTION_ELEMENT);
            metadataElement.appendChild(descriptionElement);
            descriptionElement.appendChild(document.createTextNode(getDescription()));

            final Element identifierElement = document.createElement(IDENTIFIER_ELEMENT);
            metadataElement.appendChild(identifierElement);
            identifierElement.appendChild(document.createTextNode(getIdentifier()));

            final Element uploadApplicationElement = document.createElement(UPLOAD_APPLICATION_ELEMENT);
            metadataElement.appendChild(uploadApplicationElement);
            uploadApplicationElement.setAttribute(APPID_ATTR, APPID_ATTR_VALUE);
            uploadApplicationElement.setAttribute(VERSION_ATTR, CommonUtils.getLimeWireVersion());

            final Element uploaderElement = document.createElement(UPLOADER_ELEMENT);
            metadataElement.appendChild(uploaderElement);
            uploaderElement.appendChild(document.createTextNode(getUsername()));

            //take licenseurl from the first File

            final Iterator filesIterator = getFiles().iterator();

            if (filesIterator.hasNext()) {
                final File firstFile = (File) filesIterator.next();
                final String licenseUrl = firstFile.getLicenseUrl();
                if (licenseUrl != null) {
                    final Element licenseUrlElement = document.createElement(LICENSE_URL_ELEMENT);
                    metadataElement.appendChild(licenseUrlElement);
                    licenseUrlElement.appendChild(document.createTextNode(licenseUrl));
                }
            }

            // now build user-defined elements
            final Map userFields = getFields();
            for (final Iterator i = userFields.keySet().iterator(); i.hasNext();) {
                final Object field = i.next();
                final Object value = userFields.get(field);

                if (field instanceof String) {
                    final Element e = document.createElement((String) field);
                    metadataElement.appendChild(e);

                    if (value != null && value instanceof String) {
                        e.appendChild(document.createTextNode((String) value));
                    }
                }
            }

            return document;

        } catch (final ParserConfigurationException e) {
            final IllegalStateException ise = new IllegalStateException();
            ise.initCause(e);
            throw ise;
        }
    }

    /**
     * @throws    IllegalStateException
     *          If java's xml configuration is bad
     * @return
     */

    private Document getFilesDocument() {
        /*
         * Sample _files.xml file:
         * 
         * <files>
         *   <file name="MyHomeMovie.mpeg" source="original">
          *     <runtime>2:30</runtime>
          *     <format>MPEG2</format>
          *   </file>
          * </files>    
         * 
         */

        final String FILES_ELEMENT = "files";

        try {
            final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            final DocumentBuilder db = dbf.newDocumentBuilder();
            final Document document = db.newDocument();

            final Element filesElement = document.createElement(FILES_ELEMENT);
            document.appendChild(filesElement);

            Collection files = getFiles();

            for (final Iterator i = files.iterator(); i.hasNext();) {
                final File file = (File) i.next();

                final Element fileElement = file.getElement(document);
                filesElement.appendChild(fileElement);
            }

            return document;

        } catch (final ParserConfigurationException e) {
            final IllegalStateException ise = new IllegalStateException();
            ise.initCause(e);
            throw ise;
        }

    }

    /**
     * @throws   IllegalStateException
     *          If java's DOMImplementationLS class is screwed up or
     *          this code is buggy
     * @param document
     * @return
     */
    private String serializeDocument(Document document) {

        try {
            System.setProperty(DOMImplementationRegistry.PROPERTY,
                    "org.apache.xerces.dom.DOMImplementationSourceImpl");
            final DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();

            final DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");

            final LSSerializer writer = impl.createLSSerializer();
            final String str = writer.writeToString(document);

            return str;

        } catch (final ClassNotFoundException e) {
            final IllegalStateException ise = new IllegalStateException();
            ise.initCause(e);
            throw ise;
        } catch (final InstantiationException e) {
            final IllegalStateException ise = new IllegalStateException();
            ise.initCause(e);
            throw ise;
        } catch (final IllegalAccessException e) {
            final IllegalStateException ise = new IllegalStateException();
            ise.initCause(e);
            throw ise;
        }

    }

}