org.bigbluebuttonproject.fileupload.document.impl.FileSystemSlideManager.java Source code

Java tutorial

Introduction

Here is the source code for org.bigbluebuttonproject.fileupload.document.impl.FileSystemSlideManager.java

Source

/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2008 by respective authors (see below).
*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation; either version 2.1 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* 
*/

package org.bigbluebuttonproject.fileupload.document.impl;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bigbluebuttonproject.fileupload.ISlideDatabase;
import org.bigbluebuttonproject.fileupload.SlideDescriptor;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

/**
 * This class is used as the BASE class where client services requests are routed. Service requests: fileUpload, getting Slides for viewing....
 * The requests are received by FileUploadCintroller class and routed here.
 * 
 * Some code from jGallery
 * 
 * @author ritzalam
 */
public class FileSystemSlideManager implements ISlideDatabase {

    /** The logger. */
    private final Log logger = LogFactory.getLog(getClass());
    // destination directory of the slides
    /** The base directory. */
    private String baseDirectory = null;

    /** The extracted folder. */
    private String extractedFolder = null;

    /** The output xml. */
    private PrintWriter outputXML = null;
    // used for generating slides XML 
    /** The Constant HEADER. */
    private static final String HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";

    /** The Constant PRESENTATIONS. */
    private static final String PRESENTATIONS = "<presentations>";

    /** The Constant PRESENTATIONS_END_TAG. */
    private static final String PRESENTATIONS_END_TAG = "</presentations>";

    /** The Constant PRESENTATION. */
    private static final String PRESENTATION = "<presentation id=\"slides\">";

    /** The Constant PRESENTATION_END_TAG. */
    private static final String PRESENTATION_END_TAG = "</presentation>";

    /** The Constant DESCRIPTION. */
    private static final String DESCRIPTION = "<description>";

    /** The Constant DESCRIPTION_END_TAG. */
    private static final String DESCRIPTION_END_TAG = "</description>";

    /** The Constant SLIDE. */
    private static final String SLIDE = "<slide>";

    /** The Constant SLIDE_END_TAG. */
    private static final String SLIDE_END_TAG = "</slide>";

    /** The Constant NAME. */
    private static final String NAME = "<name>";

    /** The Constant NAME_END_TAG. */
    private static final String NAME_END_TAG = "</name>";

    /** The Constant SOURCE. */
    private static final String SOURCE = "<source>";

    /** The Constant SOURCE_END_TAG. */
    private static final String SOURCE_END_TAG = "</source>";

    /** The Constant HOST. */
    private static final String HOST = "<host>";

    /** The Constant HOST_END_TAG. */
    private static final String HOST_END_TAG = "</host>";

    /** The Constant ROOM. */
    private static final String ROOM = "<room>";

    /** The Constant ROOM_END_TAG. */
    private static final String ROOM_END_TAG = "</room>";

    /** The Constant host. */
    private static final String host = "http://localhost:8080";

    /**
     * Setter for destination directory.
     * 
     * @param dest destination directory
     */
    public void setBaseDirectory(String dest) {
        this.baseDirectory = dest;
    }

    /**
     * Setter for extracted folder directory.
     * 
     * @param extractedFolder the extracted folder
     */
    public void setExtractedFolder(String extractedFolder) {
        this.extractedFolder = extractedFolder;
    }

    /**
     * This method create thumbImage of the image file given and save it in outFile.
     * Compression quality is also given. thumbBounds is used for calculating the size of the thumb.
     * 
     * @param infile slide image to create thumb
     * @param outfile output thumb file
     * @param compressionQuality the compression quality
     * @param thumbBounds the thumb bounds
     * 
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public void resizeImage(File infile, File outfile, float compressionQuality, int thumbBounds)
            throws IOException {
        // Retrieve jpg image to be resized
        Image image = ImageIO.read(infile);

        // get original image size for thumb size calculation
        int imageWidth = image.getWidth(null);
        int imageHeight = image.getHeight(null);

        float thumbRatio = (float) thumbBounds / Math.max(imageWidth, imageHeight);

        int thumbWidth = (int) (imageWidth * thumbRatio);
        int thumbHeight = (int) (imageHeight * thumbRatio);

        // draw original image to thumbnail image object and
        // scale it to the new size on-the-fly
        BufferedImage thumbImage = new BufferedImage(thumbWidth, thumbHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics2D = thumbImage.createGraphics();
        graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        graphics2D.drawImage(image, 0, 0, thumbWidth, thumbHeight, null);

        // Find a jpeg writer
        ImageWriter writer = null;
        Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpg");
        if (iter.hasNext()) {
            writer = (ImageWriter) iter.next();
        }

        ImageWriteParam iwp = writer.getDefaultWriteParam();
        iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        iwp.setCompressionQuality(compressionQuality);

        // Prepare output file
        ImageOutputStream ios = ImageIO.createImageOutputStream(outfile);
        writer.setOutput(ios);
        // write to the thumb image 
        writer.write(thumbImage);

        // Cleanup
        ios.flush();
        writer.dispose();
        ios.close();
    }

    /**
     * This method is used to generate SlideDescriptor List slide thumbs of the given conference room.
     * 
     * @param room conference room ID
     * 
     * @return List of Slide (thumb) Descriptors of all the slides of the conference room
     */
    public List<SlideDescriptor> getThumbnailsForRoom(Integer room) {
        logger.info("getting thumbnails for = [" + room + "]");
        // pointing to extracted folder directory
        File file = new File(baseDirectory + File.separator + room + File.separator + extractedFolder);

        // get all the files in the folder
        File[] files = file.listFiles();

        ArrayList<SlideDescriptor> listOfFiles = new ArrayList<SlideDescriptor>();
        // run through the File array
        for (int i = 0; i < files.length; i++) {
            if (!files[i].isDirectory()) {
                String filename = (String) files[i].getName();
                // get only the files that ends with ".jpg" and starts with "thumb-" in the directory
                if ((filename.endsWith(".jpg")) && (filename.startsWith("thumb-"))) {
                    logger.info("getting slide = [" + filename + "]");
                    SlideDescriptor slide = new SlideDescriptor(filename, room);
                    listOfFiles.add(slide);
                }
            }
        }

        Collections.sort(listOfFiles, new SlideComparator());

        return listOfFiles;
    }

    /**
     * This method returns the ArrayList of slideDescriptors that belongs to the given conference room.
     * 
     * @param room conference room ID
     * 
     * @return List of SlideDescriptor
     */
    public List<SlideDescriptor> getSlidesForRoom(Integer room) {
        logger.info("getting slides for = [" + room + "]");
        // pointing to extracted folder directory
        File file = new File(baseDirectory + File.separator + room + File.separator + extractedFolder);
        // get all the files in the folder
        File[] files = file.listFiles();

        ArrayList<SlideDescriptor> listOfFiles = new ArrayList<SlideDescriptor>();

        for (int i = 0; i < files.length; i++) {
            if (!files[i].isDirectory()) {
                String filename = (String) files[i].getName();
                // get only the files that end with ".jpg" and not start with "thumb-" in the directory
                if ((filename.endsWith(".swf")) && (!filename.startsWith("thumb-"))) {
                    logger.info("getting slide = [" + filename + "]");
                    SlideDescriptor slide = new SlideDescriptor(filename, room);
                    listOfFiles.add(slide);
                }
            }
        }

        Collections.sort(listOfFiles, new SlideComparator());

        return listOfFiles;
    }

    /**
     * This method loads the slide .swf files from the source folder and puts it in an ArratList and returns it.
     * 
     * @param sourceFolder directory of the source
     * 
     * @return ArrayList of slides
     */
    public ArrayList<File> getExtractedSlides(String sourceFolder) {
        logger.info("Slide folder = " + sourceFolder);
        // pointing to extracted folder directory
        File file = new File(sourceFolder);
        // get all the files in the folder
        File[] files = file.listFiles();
        // ArrayList to hold slide swf files
        ArrayList<File> listOfFiles = new ArrayList<File>();

        for (int i = 0; i < files.length; i++) {
            if (!files[i].isDirectory()) {
                String filename = (String) files[i].getName();
                // get only the files that end with ".swf" and not start with "thumb-" in the directory
                if ((filename.toLowerCase().endsWith(".swf")) && !(filename.toLowerCase().startsWith("thumb"))) {
                    listOfFiles.add(files[i]);
                }
            }
        }

        return listOfFiles;
    }

    /**
     * This method saves the MultipartFile given as parameter( temporary stored file format)
     * And it also return instance of file which is saved in saveDir.
     * 
     * @param multipartFile temporary storage of uploaded file
     * @param room conference room ID
     * 
     * @return file pointing to the new file stored
     * 
     * @throws IOException Signals that an I/O exception has occurred.
     * 
     * @see MultipartFile API
     */
    public File saveUploadedFile(MultipartFile multipartFile, Integer room) throws IOException {
        String filename = multipartFile.getOriginalFilename().replace(' ', '_');

        File saveDir = new File(baseDirectory + File.separator + room);

        if (!saveDir.exists()) {
            saveDir.mkdirs();
        }

        File file = new File(saveDir.getAbsolutePath() + File.separator + filename);
        // store multipartFile in permanent storage
        multipartFile.transferTo(file);

        return file;
    }

    /**
     * This method copies the contents of the file (in our case, slides) to the OutputStream given.
     * OutputStream given to this method (as parameter) is the connection stream to the client.
     * This tells us that this function streams the slides to the client.
     * 
     * @param room conference room ID
     * @param name name of the slide
     * @param os the os
     * 
     * @see FileCopyUtils API
     */
    public void streamImage(Integer room, String name, OutputStream os) {

        File file = new File(
                baseDirectory + File.separator + room + File.separator + extractedFolder + File.separator + name);

        InputStream is = null;

        try {
            is = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            logger.error("File not found. \n " + e.getMessage());
        }

        try {
            if (is != null) {
                // streaming the contents(slide) in is to os which points to client connection
                FileCopyUtils.copy(is, os);
            }
        } catch (IOException e) {
            logger.error("Error reading file.\n" + e.getMessage());
        }
    }

    /**
     * This method basically copies the contents of the file (in our case, slide XML description) to the OutputStream given.
     * OutputStream given to method (as parameter) is the connection stream to the client.
     * This tells us that this function streams the slides to the client.
     * 
     * @param room conference room ID
     * @param name name of the slide
     * @param os the os
     * 
     * @see FileCopyUtils API
     */
    public void getXml(Integer room, String name, OutputStream os) {
        File file = new File(baseDirectory + File.separator + room + File.separator + name);

        InputStream is = null;

        try {
            is = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            logger.error("File not found. \n " + e.getMessage());
        }

        try {
            if (is != null) {
                // streaming the contents (slide XML) in is to os which points to client connection
                FileCopyUtils.copy(is, os);
            }
        } catch (IOException e) {
            logger.error("Error reading file.\n" + e.getMessage());
        }
    }

    /**
     * This method creates XML formatted string (default slide description of the conference room) that is ready to be sent to the client.
     * 
     * @param room conference room ID
     * 
     * @see createXml()
     */
    public void createDefaultXml(Integer room) {
        String slidesXml = HEADER + "\n";
        slidesXml += PRESENTATIONS + "\n" + "\t" + PRESENTATION + "\n";
        slidesXml += "\t\t" + DESCRIPTION;

        String description = "Presentation Slides";
        slidesXml += description + DESCRIPTION_END_TAG + "\n";
        slidesXml += PRESENTATION_END_TAG + PRESENTATIONS_END_TAG;

        try {
            outputXML = new PrintWriter(
                    new FileWriter(baseDirectory + File.separator + room + File.separator + "slides.xml"));
            outputXML.print(slidesXml);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        finally {
            if (outputXML != null) {
                outputXML.close();
            }
        }
    }

    /**
     * Gets the slides in xml.
     * 
     * @param room the room
     * 
     * @return the slides in xml
     * 
     * @see createXml()
     */
    public String getSlidesInXml(Integer room) {
        return createXml(room);
    }

    /**
     * This method creates XML formatted string (slide description of the conference room) that is ready to be sent to the client.
     * 
     * @param room conference room ID
     * 
     * @return slide description XML string
     */
    public String createXml(Integer room) {
        List<SlideDescriptor> slides = getSlidesForRoom(room);

        String slidesXml = HEADER + "\n";
        slidesXml += PRESENTATIONS + "\n" + "\t" + PRESENTATION + "\n";
        slidesXml += "\t\t" + DESCRIPTION;

        String description = "Presentation Slides";
        slidesXml += description + DESCRIPTION_END_TAG + "\n";
        slidesXml += HOST + host + HOST_END_TAG + "\n";
        slidesXml += ROOM + room + ROOM_END_TAG + "\n";

        logger.info("slidesXml = " + slidesXml);

        for (Iterator it = slides.iterator(); it.hasNext();) {
            slidesXml += SLIDE + NAME;
            SlideDescriptor slide = (SlideDescriptor) it.next();
            slidesXml += slide.getName() + NAME_END_TAG;
            slidesXml += SLIDE_END_TAG + "\n";
        }

        slidesXml += PRESENTATION_END_TAG + PRESENTATIONS_END_TAG;

        try {
            outputXML = new PrintWriter(
                    new FileWriter(baseDirectory + File.separator + room + File.separator + "slides.xml"));
            outputXML.print(slidesXml);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        finally {
            if (outputXML != null) {
                outputXML.close();
            }
        }

        return slidesXml;
    }

    /**
     * TODO Auto-generated method stub.
     */
    public void clearDatabase() {
        // TODO Auto-generated method stub

    }

    /**
     * Getter for destination directory.
     * 
     * @return dest destination directory
     */
    public String getBaseDirectory() {
        return baseDirectory;
    }

    /**
     * Getter for extracted folder directory.
     * 
     * @return extractedFolder
     */
    public String getExtractedFolder() {
        return extractedFolder;
    }

    /**
     * Internal class used to compare two slides and check for differences.
     */
    private class SlideComparator implements Comparator {

        /**
         * Method to perform the actual comparison and sorting of files
         * This would be called automatically when this comparator is used
         * by a Collections.sort call
         * 
         * @param a1 first file to compare
         * @param a2 second file to compare
         * 
         * @return 0 if the files are equal, 1 if a1 is above a2, -1 if a2 is above a1
         */
        public int compare(Object a1, Object a2) {
            SlideDescriptor file1 = null;
            SlideDescriptor file2 = null;
            if (a1 instanceof SlideDescriptor) {
                file1 = (SlideDescriptor) a1;
            }
            if (a2 instanceof SlideDescriptor) {
                file2 = (SlideDescriptor) a2;
            }

            int number1 = 0;
            int number2 = 0;
            if (file1 != null) {
                number1 = getNumberFromFile(file1.getName());
            }
            if (file2 != null) {
                number2 = getNumberFromFile(file2.getName());
            }

            if (number1 > number2)
                return 1;
            else if (number1 < number2)
                return -1;

            return 0;
        }

        /**
         * Wrapper method to safely determine if the passed object equals this.
         * 
         * @param obj to check
         * 
         * @return true if the objects are equal
         */
        public boolean equals(Object obj) {
            return obj != null && this.equals(obj);
        }

        /**
         * Convience method to get numbers from a filename, in the hope of
         * ordering the files properly
         * For example, a file named Slide2.jpg would extract as 2, and therefore
         * could be sorted about 3, etc.
         * 
         * @param name of the file
         * 
         * @return numbers in the file, or -1 on error / no numbers present
         */
        private int getNumberFromFile(String name) {
            try {
                String toReturn = "";
                char current;
                for (int i = 0; i < name.length(); i++) {
                    current = name.charAt(i);
                    if (Character.isDigit(current)) {
                        toReturn += current;
                    }
                    if (current == '.') {
                        break;
                    }
                }
                return Integer.parseInt(toReturn);
            } catch (Exception failed) {
                return -1;
            }
        }
    }
}