Index: lams_learning/src/java/org/lamsfoundation/lams/learning/export/Portfolio.java =================================================================== diff -u -r2579fb9a7e2c8581699bca77eb894f25e06eb249 -r61af83f89920627fddfc62ef81dc712130058157 --- lams_learning/src/java/org/lamsfoundation/lams/learning/export/Portfolio.java (.../Portfolio.java) (revision 2579fb9a7e2c8581699bca77eb894f25e06eb249) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/export/Portfolio.java (.../Portfolio.java) (revision 61af83f89920627fddfc62ef81dc712130058157) @@ -35,6 +35,7 @@ private String exportID; private String exportTmpDir; + private String contentFolderID; private String lessonName; private String lessonDescription; private ActivityPortfolio[] activityPortfolios; @@ -67,18 +68,35 @@ public void setExportTmpDir(String exportTmpDir) { this.exportTmpDir = exportTmpDir; } + + /** + * @return Returns the 32-character content folder name. + */ + public String getContentFolderID() { + return contentFolderID; + } + + /** + * @param contentFolderID The 32-character content folder name to set. + */ + public void setContentFolderID(String contentFolderID) { + this.contentFolderID = contentFolderID; + } + public String getNotebookDir() { return notebookDir; } public void setNotebookDir(String notebookDir) { this.notebookDir = notebookDir; } + /** * @return Returns the toolPortfolios. */ public ActivityPortfolio[] getActivityPortfolios() { return activityPortfolios; } + /** * @param toolPortfolios The toolPortfolios to set. */ Index: lams_learning/src/java/org/lamsfoundation/lams/learning/export/service/ExportPortfolioService.java =================================================================== diff -u -ra47f62d9ef96db1cddec04678d6d828f37c23d81 -r61af83f89920627fddfc62ef81dc712130058157 --- lams_learning/src/java/org/lamsfoundation/lams/learning/export/service/ExportPortfolioService.java (.../ExportPortfolioService.java) (revision a47f62d9ef96db1cddec04678d6d828f37c23d81) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/export/service/ExportPortfolioService.java (.../ExportPortfolioService.java) (revision 61af83f89920627fddfc62ef81dc712130058157) @@ -297,6 +297,7 @@ Portfolio portfolio = new Portfolio(exportID); portfolio.setExportTmpDir(tempDirectoryName); + portfolio.setContentFolderID(lesson.getLearningDesign().getContentFolderID()); portfolio.setLessonName(lesson.getLessonName()); portfolio.setLessonDescription(lesson.getLessonDescription()); portfolio.setLessonStartDate(lesson.getStartDateTime()); Index: lams_learning/src/java/org/lamsfoundation/lams/learning/export/web/action/ImageBundler.java =================================================================== diff -u --- lams_learning/src/java/org/lamsfoundation/lams/learning/export/web/action/ImageBundler.java (revision 0) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/export/web/action/ImageBundler.java (revision 61af83f89920627fddfc62ef81dc712130058157) @@ -0,0 +1,234 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +/* $Id$ */ + +package org.lamsfoundation.lams.learning.export.web.action; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.lamsfoundation.lams.util.Configuration; +import org.lamsfoundation.lams.util.ConfigurationKeys; + +/** + * Auxiliary class for supporting portfolio export. Copying all images and files + * uploaded by user into export temporary folder. + * + * @author AndreyB + * + */ +public class ImageBundler { + + private static Logger log = Logger.getLogger(ImageBundler.class); + + Map filesToCopy = null; + List directoriesRequired = null; + String outputDirectory = null; + String contentFolderId = null; + String lamsWwwPath = null; + String lamsCentralPath = null; + + /** + * @param outputDirectory directory for the export + * @param contentFolderId the 32-character content folder name + */ + public ImageBundler(String outputDirectory, String contentFolderId) { + filesToCopy = new HashMap(); + directoriesRequired = new ArrayList(); + this.outputDirectory = outputDirectory; + this.contentFolderId = contentFolderId; + + String lamsEarDir = Configuration.get(ConfigurationKeys.LAMS_EAR_DIR); + if ( lamsEarDir == null ) { + log.error("Unable to get path to the LAMS ear from the configuration file - the exported portfolios will be missing User generated content and FCKEditor smileys."); + } else { + lamsWwwPath = lamsEarDir + File.separator + "lams-www.war"; + lamsCentralPath = lamsEarDir + File.separator + "lams-central.war"; + } + } + + /** Bundle all images and files uploaded by user, also FCKEditor smileys. + * + * @throws IOException + */ + public void bundleImages( ) throws IOException + { + File www = new File(lamsWwwPath); + if ( lamsWwwPath != null && www.canRead() && www.isDirectory() ) { + log.debug("Copying user generated content from path " + lamsWwwPath); + + // build up a list of images to copy + setupImageList(); + + // build up a list of themes to copy + setupFileList(); + } + + File central = new File(lamsCentralPath); + if ( lamsCentralPath != null && central.canRead() && central.isDirectory() ) { + log.debug("Copying FCKeditor smileys from path " + lamsCentralPath); + + // build up a list of images to copy + setupFCKEditorSmileysList(); + } + + // now copy all those files + createDirectories(); + for ( Map.Entry fileEntry : filesToCopy.entrySet() ) { + copyFile((String)fileEntry.getKey(), (File)fileEntry.getValue()); + } + } + + /** + * Creates list of files uploaded by user that should be exported. + */ + private void setupFileList() { + String fileDirectory = lamsWwwPath + File.separatorChar + "secure" + + File.separatorChar + contentFolderId + File.separatorChar + + "File"; + String outputFileDirectory = outputDirectory + File.separatorChar + + contentFolderId + File.separatorChar + "File"; + directoriesRequired.add(outputFileDirectory); + + File dir = new File(fileDirectory); + if ( ! dir.canRead() || ! dir.isDirectory() ) { + log.debug("Unable to read file directory " + dir.getAbsolutePath()); + } else { + File[] files = dir.listFiles(); + for ( File imageFile: files ) { + filesToCopy.put(outputFileDirectory+File.separatorChar+imageFile.getName(),imageFile); + } + } + } + + /** + * Creates list of Images uploaded by user that should be exported. + */ + private void setupImageList() { + String imageDirectory = lamsWwwPath + File.separatorChar + "secure" + + File.separatorChar + contentFolderId + File.separatorChar + + "Image"; + String outputImageDirectory = outputDirectory + File.separatorChar + + contentFolderId + File.separatorChar + "Image"; + directoriesRequired.add(outputImageDirectory); + + File dir = new File(imageDirectory); + if ( ! dir.canRead() || ! dir.isDirectory() ) { + log.debug("Unable to read image directory " + dir.getAbsolutePath()); + } else { + File[] files = dir.listFiles(); + for ( File imageFile: files ) { + filesToCopy.put(outputImageDirectory+File.separatorChar+imageFile.getName(),imageFile); + } + } + } + + /** + * Creates list of FCKEditor smiley files that should be exported. + */ + private void setupFCKEditorSmileysList() { + String imageDirectory = lamsCentralPath + File.separatorChar + + "fckeditor" + File.separatorChar + "editor" + + File.separatorChar + "images" + File.separatorChar + "smiley" + + File.separatorChar + "msn"; + String outputImageDirectory = outputDirectory + File.separatorChar + + "fckeditor" + File.separatorChar + "editor" + + File.separatorChar + "images" + File.separatorChar + "smiley" + + File.separatorChar + "msn"; + directoriesRequired.add(outputImageDirectory); + + File dir = new File(imageDirectory); + if ( ! dir.canRead() || ! dir.isDirectory() ) { + log.debug("Unable to read image directory " + dir.getAbsolutePath()); + } else { + File[] files = dir.listFiles(); + for ( File imageFile: files ) { + filesToCopy.put(outputImageDirectory+File.separatorChar+imageFile.getName(),imageFile); + } + } + } + + private void createDirectories() { + + for ( String directoryPath: directoriesRequired) { + File dir = new File(directoryPath); + if ( ! dir.mkdirs() ) { + log.error("Unable to create directory for export portfolio: "+directoryPath); + } + } + } + + private void copyFile(String filePath, File file) throws IOException { + + FileInputStream is = new FileInputStream(file); + OutputStream os = null; + try { + + int bufLen = 1024; // 1 Kbyte + byte[] buf = new byte[1024]; // output buffer + os = new FileOutputStream(filePath); + + BufferedInputStream in = new BufferedInputStream(is); + int len = 0; + while((len = in.read(buf,0,bufLen)) != -1){ + os.write(buf,0,len); + } + + } catch ( IOException e ) { + String message = "Unable to write out file needed for export portfolio. File was "+filePath; + log.error(message,e); + throw e; + + } finally { + + try { + if ( is != null ) + is.close(); + } catch (IOException e1) { + String message = "Unable to close input export portfolio file due to IOException"; + log.warn(message,e1); + } + + try { + if ( os != null ) + os.close(); + } catch (IOException e2) { + String message = "Unable to close output export portfolio file due to IOException"; + log.warn(message,e2); + } + } + + + } +} + + \ No newline at end of file Index: lams_learning/src/java/org/lamsfoundation/lams/learning/export/web/action/MainExportServlet.java =================================================================== diff -u -r363085e014b2143574ecd005b67e3fc48096acb4 -r61af83f89920627fddfc62ef81dc712130058157 --- lams_learning/src/java/org/lamsfoundation/lams/learning/export/web/action/MainExportServlet.java (.../MainExportServlet.java) (revision 363085e014b2143574ecd005b67e3fc48096acb4) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/export/web/action/MainExportServlet.java (.../MainExportServlet.java) (revision 61af83f89920627fddfc62ef81dc712130058157) @@ -24,10 +24,20 @@ /* $$Id$$ */ package org.lamsfoundation.lams.learning.export.web.action; +import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.URLEncoder; +import java.util.Collection; +import java.util.Iterator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.servlet.ServletException; import javax.servlet.http.Cookie; @@ -36,6 +46,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.apache.commons.io.FileUtils; import org.apache.log4j.Logger; import org.lamsfoundation.lams.learning.export.ExportPortfolioConstants; import org.lamsfoundation.lams.learning.export.ExportPortfolioException; @@ -139,14 +150,20 @@ exportService.generateMainPage(request, portfolios, cookies); if(portfolios.getNotebookPortfolios() != null) - if(portfolios.getNotebookPortfolios().length > 0) + if(portfolios.getNotebookPortfolios().length > 0) exportService.generateNotebookPage(request, portfolios, cookies); + + //correct all image links in created htmls. + replaceImageFolderLinks(portfolios.getContentFolderID()); - //bundle the stylesheet with the package CSSBundler bundler = new CSSBundler(request, cookies, exportTmpDir, exportService.getUserThemes()); bundler.bundleStylesheet(); + //bundle all user uploaded content and FCKEditor smileys with the package + ImageBundler imageBundler = new ImageBundler(exportTmpDir, portfolios.getContentFolderID()); + imageBundler.bundleImages(); + // zip up the contents of the temp export folder using a constant name String exportZipDir = exportService.zipPortfolio(ExportPortfolioConstants.EXPORT_TEMP_FILENAME, exportTmpDir); /* -- Used for testing timeout change the export url in exportWaitingPage to @@ -173,5 +190,86 @@ } } + + /** + * Corrects links in all html files in temporary directory and its subdirectories. + * + * @param contentFolderID 32-character content folder name + */ + private void replaceImageFolderLinks(String contentFolderID) { + File tempDir = new File(exportTmpDir); + // finds all the html extension files + Collection jspFiles = FileUtils.listFiles(tempDir, new String[] { "html" }, true); + + // iterates thru the collection and sends this + for (Iterator it = jspFiles.iterator(); it.hasNext(); ) { + Object element = it.next(); + log.debug("Correcting links in file " + element.toString()); + replaceImageFolderLinks(element.toString(), contentFolderID); + } + } + + /** + * Corrects links in current particular html file. + * + * @param filename filename + * @param contentFolderID 32-character content folder name + */ + private void replaceImageFolderLinks(String filename, String contentFolderID) { + try { + // String to find + String fckeditorpath = "/lams//www/secure/" + contentFolderID; + String fckeditorsmiley = "/lams//fckeditor/editor/images/smiley"; + + // Replacing string + String newfckeditorpath = "../" + contentFolderID; + String newfckeditorsmiley = "../fckeditor/editor/images/smiley"; + + File fin = new File(filename); + //Open and input stream + FileInputStream fis = new FileInputStream(fin); + + BufferedReader in = new BufferedReader(new InputStreamReader(fis)); + + // The pattern matches control characters + Pattern p = Pattern.compile(fckeditorpath); + Matcher m = p.matcher(""); + + Pattern p2 = Pattern.compile(fckeditorsmiley); + Matcher m2 = p2.matcher(""); + + + String aLine = null; + String output = ""; + + while((aLine = in.readLine()) != null) { + m.reset(aLine); + + // Replace the p matching pattern with the newfckeditorpath + String firstpass = m.replaceAll(newfckeditorpath); + + // Replace the p2 matching patterns with the newfckeditorsmiley + m2.reset(firstpass); + String result = m2.replaceAll(newfckeditorsmiley); + + output = output + result + "\n"; + } + in.close(); + + // open output file + + File fout = new File(filename); + FileOutputStream fos = + new FileOutputStream(fout); + BufferedWriter out = new BufferedWriter(new OutputStreamWriter(fos)); + + out.write(output); + out.newLine(); + out.close(); + } catch(IOException e) { + log.error("Unable to correct imagefolder links in file " + filename, e); + } + } + }