diff options
author | Kurt Zenker <kz@openoffice.org> | 2004-05-19 12:12:58 +0000 |
---|---|---|
committer | Kurt Zenker <kz@openoffice.org> | 2004-05-19 12:12:58 +0000 |
commit | 5ee716fd275c63d9c45dac21d3703b7b9917055a (patch) | |
tree | 067ae001af4eae9788fe5bcc6364d4ed9652cad0 /wizards/com/sun/star/wizards/web/Process.java | |
parent | 33f5dac62192411d47245e179c4c199187e143f3 (diff) |
INTEGRATION: CWS qwizards1 (1.1.2); FILE ADDED
2004/05/05 19:16:07 rpiterman 1.1.2.10: Changed HIDs
Added own Frame as house-pet
Issue number:
Submitted by:
Reviewed by:
2004/03/19 17:15:23 rpiterman 1.1.2.9: removed the "Publishing..." resource and all its references.
2004/03/12 16:16:56 rpiterman 1.1.2.8: documentation and small implementation-fixes
2004/03/11 12:45:03 rpiterman 1.1.2.7: changed to use FileAccess.connectURLs(folder,filename) static method
2004/03/09 12:09:30 rpiterman 1.1.2.6: further developement
2004/03/05 19:11:49 rpiterman 1.1.2.5: Further developement
2004/02/20 18:11:12 rpiterman 1.1.2.4: changes were made to use the Field Support of the DataAware model (beta)
2004/02/10 18:46:37 rpiterman 1.1.2.3: added GNU license text
2004/02/10 18:35:21 rpiterman 1.1.2.2: Many changes that may only be described as further developement.
2003/11/04 17:47:56 rpiterman 1.1.2.1: Core-Functionality of the web wizard. The functionality that acts when the user clicks "finish" is delegated to this class.
Diffstat (limited to 'wizards/com/sun/star/wizards/web/Process.java')
-rw-r--r-- | wizards/com/sun/star/wizards/web/Process.java | 821 |
1 files changed, 821 insertions, 0 deletions
diff --git a/wizards/com/sun/star/wizards/web/Process.java b/wizards/com/sun/star/wizards/web/Process.java new file mode 100644 index 000000000000..6e4902e98dd7 --- /dev/null +++ b/wizards/com/sun/star/wizards/web/Process.java @@ -0,0 +1,821 @@ +/************************************************************************* + * + * $RCSfile: Process.java,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: kz $ $Date: 2004-05-19 13:12:58 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + */ +package com.sun.star.wizards.web; + +import java.io.*; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; + +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +//import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.*; + +import com.sun.star.lang.XMultiServiceFactory; + +import com.sun.star.wizards.common.*; +import com.sun.star.wizards.ui.event.*; +import com.sun.star.wizards.web.data.*; +import com.sun.star.wizards.web.export.Exporter; + + + +/** + * @author rpiterman + * This class is used to process a CGSession object + * and generate a site. </br> + * it does the following: <br/> + * 1. create a temporary directory.<br/> + * 2. export documents to the temporary directory.<br/> + * 3. generate the TOC page, includes copying images from the + * web wizard work directory and other layout files.<br/> + * 4. publish, or copy, from the temporary directory to + * different destinations.<br/> + * 5. delete the temporary directory.<br/> + * <br/> + * to follow up the status/errors it uses a TaskListener object, + * and an ErrorHandler. <br/> + * in practice, the TaskListener is the status dialog, + * and the Errorhandler does the interaction with the user, + * if something goes wrong.<br/> + * Note that this class takes it in count that + * the given session object is prepared for it - + * all preparations are done in WWD_Events.finishWizard methods. + * <br/> + * <br/> + * + * note on error handling: <br/> + * on "catch" clauses I tries to decide whether the + * exception is fatal or not. For fatal exception an error message + * is displayed (or rather: the errorHandler is being called...) + * and a false is returned. + * In less-fatal errors, the errorHandler "should decide" which means, + * the user is given the option to "OK" or to "Cancel" and depending + * on that interaction I cary on. + */ +public class Process implements Runnable, WebWizardConst, ProcessErrors { + + private static final int TASKS_PER_DOC = 5; + private static final int TASKS_PER_XSL = 2; + private static final int TASKS_PER_PUBLISH = 2; + + private static final int TASKS_IN_PREPARE = 1; + private static final int TASKS_IN_EXPORT = 2; + private static final int TASKS_IN_GENERATE = 2; + private static final int TASKS_IN_PUBLISH = 2; + private static final int TASKS_IN_FINISHUP = 1; + + private CGSettings settings; + private XMultiServiceFactory xmsf; + + private ErrorHandler errorHandler; + + + private String tempDir; + private FileAccess fileAccess; + private UCB ucb; + + public Task myTask; + + /** + * This is a cache for exporters, so I do not need to + * instanciate the same exporter more than once. + */ + private Map exporters = new Hashtable(3); + + private boolean result; + + public Process( + CGSettings settings, + XMultiServiceFactory xmsf, + ErrorHandler er + ) + throws Exception + { + this.xmsf = xmsf; + this.settings = settings; + fileAccess = new FileAccess(xmsf); + errorHandler = er; + + ucb = new UCB(xmsf); + + int taskSteps = getTaskSteps(); + myTask = new Task(TASK,TASK_PREPARE, taskSteps); + + } + + + /** + * @return to how many destinations should the + * generated site be published. + */ + private int countPublish() { + int count = 0; + ConfigSet publishers = settings.cp_DefaultSession.cp_Publishing; + for (int i = 0; i<publishers.getSize(); i++) + if (((CGPublish)publishers.getElementAt(i)).cp_Publish) + count++; + return count; + } + + /** + * @return the number of task steps that this + * session should have + */ + private int getTaskSteps() { + int docs = settings.cp_DefaultSession.cp_Content.cp_Documents.getSize(); + int xsl = 0; + try { + xsl = settings.cp_DefaultSession.getLayout().getTemplates(xmsf).size(); + } + catch (Exception ex) { + } + int publish = countPublish(); + int taskSteps = + TASKS_IN_PREPARE + + TASKS_IN_EXPORT + docs * TASKS_PER_DOC + + TASKS_IN_GENERATE + xsl * TASKS_PER_XSL + + TASKS_IN_PUBLISH + publish * TASKS_PER_PUBLISH + + TASKS_IN_FINISHUP; + return taskSteps; + } + + /** + * does the job + */ + public void run() { + + + myTask.start(); + + try { + + try { + /* + * I use here '&&' so if one of the + * methods returns false, the next + * will not be called. + */ + result = createTempDir(myTask) + && export(myTask) + && generate(tempDir,myTask) + && publish(tempDir,myTask); + + } + finally { + //cleanup must be called. + result = result & cleanup(myTask); + } + } + catch (Exception ex) { + result = false; + } + + if (!result) + myTask.fail(); + + //this is a bug protection. + while (myTask.getStatus() < myTask.getMax()) + myTask.advance(true); + + } + + /** + * creates a temporary directory. + * @param task + * @return true should continue + */ + private boolean createTempDir(Task task) { + + tempDir = fileAccess.createNewDir(getSOTempDir(xmsf), "wwiztemp"); + if (tempDir == null) { + error(null,null,ERROR_MKDIR,ErrorHandler.ERROR_PROCESS_FATAL); + return false; + } + else { + task.advance(true); + return true; + } + } + + /** + * @param xmsf + * @return the staroffice /openoffice temporary directory + */ + static String getSOTempDir(XMultiServiceFactory xmsf) { + try { + String s = FileAccess.getOfficePath(xmsf,"Temp",""); + return s; + } + catch (Exception e) {} + return null; + } + + // CLEANUP + + /** + * delete the temporary directory + * @return true should continue + */ + private boolean cleanup(Task task) { + + task.setSubtaskName(TASK_FINISH); + boolean b = cleanup(tempDir); + if (!b) + error(null,null,ERROR_CLEANUP,ErrorHandler.ERROR_WARNING); + task.advance(b); + return b; + } + + /** + * deletes the given directory + * @param dir the directory to delete + * @return true if should continue + */ + private boolean cleanup(String dir) { + + boolean success = true; + + if (dir != null && fileAccess.exists(dir,false)) { + + String[] files = fileAccess.listFiles(dir,true); + + for (int i = 0; i < files.length; i++) { + if (fileAccess.isDirectory(files[i])) + success = success && cleanup(files[i]); + else + success = success && fileAccess.delete(files[i]); + + } + } + return success && fileAccess.delete(dir); + } + + /** + * This method is used to copy style files to a target + * Directory: css and background. + * Note that this method is static since it is + * also used when displaying a "preview" + */ + public static void copyMedia(UCB copy, CGSettings settings, String targetDir, Task task ) throws Exception { + + //1. .css + String sourceDir = FileAccess.connectURLs(settings.workPath , "styles"); + String filename = settings.cp_DefaultSession.getStyle().cp_CssHref; + copy.copy(sourceDir,filename,targetDir,"style.css"); + + task.advance(true); + + //2. background image + String background = settings.cp_DefaultSession.cp_Design.cp_BackgroundImage; + if (background != null && !background.equals("")) { + sourceDir = FileAccess.getParentDir(background); + filename = background.substring(sourceDir.length()); + copy.copy(sourceDir,filename,targetDir + "/images","background.gif"); + } + + task.advance(true); + } + + /** + * Copy "static" files (which are always the same, + * thus not user-input-dependant) to a target directory. + * Note that this method is static since it is + * also used when displaying a "preview" + * @param copy + * @param settings + * @param targetDir + * @throws Exception + */ + public static void copyStaticImages(UCB copy, CGSettings settings, String targetDir) + throws Exception + { + copy.copy(FileAccess.connectURLs(settings.workPath , "images") ,targetDir+"/images"); + } + + + /** + * publish the given directory. + * @param dir the source directory to publish from + * @param task task tracking. + * @return true if should continue + */ + private boolean publish(String dir, Task task ) { + task.setSubtaskName(TASK_PUBLISH_PREPARE); + ConfigSet set = settings.cp_DefaultSession.cp_Publishing; + try { + + copyMedia(ucb, settings, dir,task); + copyStaticImages(ucb,settings,dir); + task.advance(true); + } + catch (Exception ex) { + //error in copying media + error(ex, "", ERROR_PUBLISH_MEDIA, ErrorHandler.ERROR_PROCESS_FATAL); + return false; + } + + boolean result = true; + + for (int i = 0; i < set.getSize(); i++) { + + CGPublish p = (CGPublish)set.getElementAt(i); + + if (p.cp_Publish) { + + String key = (String)set.getKey(p); + task.setSubtaskName(key); + + if (!publish(dir, p, ucb, task)) { + return false; + } + + } + } + + return result; + } + + /** + * publish the given directory to the + * given target CGPublish. + * @param dir the dir to copy from + * @param publish the object that specifies the target + * @param copy ucb encapsulation + * @param task task tracking + * @return true if should continue + */ + private boolean publish(String dir,CGPublish publish,UCB copy,Task task) { + try { + copy.deleteDirContent(publish.url); + task.advance(true); + copy.copy(dir,publish.url); + task.advance(true); + return true; + } catch (Exception e) { + task.advance(false); + return error(e,publish, ERROR_PUBLISH,ErrorHandler.ERROR_NORMAL_IGNORE); + } + } + + + //GENERATING METHODS + + /** + * Generates the TOC pages for the current session. + * @param targetDir generating to this directory. + */ + public boolean generate(String targetDir, Task task) { + boolean result = false; + task.setSubtaskName(TASK_GENERATE_PREPARE); + + + CGLayout layout = settings.cp_DefaultSession.getLayout(); + + try { + /* + * here I create the DOM of the TOC to pass to the XSL + */ + Document doc = (Document)settings.cp_DefaultSession.createDOM(); + generate(xmsf,layout,doc ,fileAccess,targetDir,task); + + } + catch (Exception ex) { + error(ex, "" , ERROR_GENERATE_XSLT ,ErrorHandler.ERROR_PROCESS_FATAL); + return false; + } + + /* copy files which are not xsl from layout directory to + * website root. + */ + try { + + task.setSubtaskName(TASK_GENERATE_COPY); + + copyLayoutFiles(ucb,fileAccess,settings,layout,targetDir); + + task.advance(true); + + result = true; + } + catch (Exception ex) { + task.advance(false); + return error(ex,null,ERROR_GENERATE_COPY,ErrorHandler.ERROR_NORMAL_ABORT); + } + + + + return result; + + } + + /** + * copies layout files which are not .xsl files + * to the target directory. + * @param ucb UCB encapsulatzion object + * @param fileAccess filaAccess encapsulation object + * @param settings web wizard settings + * @param layout the layout object + * @param targetDir the target directory to copy to + * @throws Exception + */ + public static void copyLayoutFiles(UCB ucb, FileAccess fileAccess, CGSettings settings, CGLayout layout, String targetDir) + throws Exception + { + String filesPath = fileAccess.getURL( + FileAccess.connectURLs(settings.workPath , "layouts/"), layout.cp_FSName ); + ucb.copy(filesPath,targetDir,new ExtensionVerifier("xsl")); + String icon = settings.cp_DefaultSession.cp_GeneralInfo.cp_Icon; + if ((icon!=null) && (!icon.equals(""))) { + String icon2 = FileAccess.connectURLs(targetDir , "images/favicon.ico"); + fileAccess.copy(icon,icon2); + } + } + + /** + * generates the TOC page for the given layout. + * This method might generate more than one file, depending + * on how many .xsl files are in the + * directory specifies by the given layout object. + * @param xmsf + * @param layout specifies the layout to use. + * @param doc the DOM representation of the web wizard session + * @param fileAccess encapsulation of FileAccess + * @param targetPath target directory + * @param task + * @throws Exception + */ + public static void generate( + XMultiServiceFactory xmsf, + CGLayout layout, + Document doc, + FileAccess fileAccess, + String targetPath, + Task task) + throws Exception + { + /* + * a map that contains xsl templates. the keys are the xsl file names. + */ + Map templates = layout.getTemplates(xmsf); + + task.advance(true,TASK_GENERATE_XSL); + + /* + * each template generates a page. + */ + for (Iterator i = templates.keySet().iterator() ; i.hasNext(); ) { + + String key = ""; + + key = (String)i.next(); + + Transformer transformer = ((Templates)templates.get(key)).newTransformer(); + + doc.normalize(); + + task.advance(true); + + /* + * The target file name is like the xsl template filename + * without the .xsl extension. + */ + String fn = fileAccess.getPath( targetPath, key.substring(0,key.length()-4)); + File f = new File(fn); + + transformer.transform( new DOMSource(doc), new StreamResult(f) ); + + task.advance(true); + } + + + + } + + + /** + * I broke the export method to two methods + * in a time where a tree with more than one contents was planned. + * I left it that way, because it may be used in the future. + * @param task + * @return + */ + private boolean export(Task task) { + + return export(settings.cp_DefaultSession.cp_Content, tempDir, task); + + } + + /** + * This method could actually, with light modification, use recursion. + * In the present situation, where we only use a "flat" list of + * documents, instead of the original plan to use a tree, + * the recursion is not implemented. + * @param content the content ( directory-like, contains documents) + * @param dir (target directory for exporting this content. + * @param task + * @return true if should continue + */ + private boolean export(CGContent content, String dir, Task task) { + int toPerform = 1; + String contentDir = dir; + + try { + + task.setSubtaskName(TASK_EXPORT_PREPARE); + + /* 1. create a content directory. + * each content (at the moment there is only one :-( ) + * is created in its own directory. + * faileure here is fatal. + */ + contentDir = fileAccess.createNewDir(dir,content.cp_Name); + if (contentDir == null || contentDir.equals("") ) + throw new IOException("Directory " + dir + " could not be created."); + content.dirName = fileAccess.getFilename(contentDir); + + task.advance(true,TASK_EXPORT_DOCUMENTS); + toPerform--; + + /*2. export all documents and sub contents. + * (at the moment, only documents, no subcontents) + */ + Object item = null; + for (int i = 0; i < content.cp_Documents.getSize(); i++) { + try { + item = content.cp_Documents.getElementAt(i); + /* + * In present this is always the case. + * may be in the future, when + * a tree is used, it will be abit different. + */ + if (item instanceof CGDocument) { + if (!export((CGDocument) item, contentDir,task)) + return false; + } + else + /* + * we never get here since we + * did not implement sub-contents. + */ + if (!export((CGContent) item, contentDir,task)) + return false; + } + catch (SecurityException sx) { + // nonfatal + if (!error(sx,item, ERROR_EXPORT_SECURITY,ErrorHandler.ERROR_NORMAL_IGNORE)) + return false; + result = false; + } + } + } + catch (IOException iox) { + //nonfatal + return error(iox,content,ERROR_EXPORT_IO,ErrorHandler.ERROR_NORMAL_IGNORE); + + } + catch (SecurityException se) { + //nonfatal + return error(se,content,ERROR_EXPORT_SECURITY,ErrorHandler.ERROR_NORMAL_IGNORE); + } + failTask(task,toPerform); + return true; + + } + + /** + * exports a single document + * @param doc the document to export + * @param dir the target directory + * @param task task tracking + * @return true if should continue + */ + private boolean export(CGDocument doc, String dir,Task task) { + + //first I check if the document was already validated... + if (!doc.valid) + try { + doc.validate(xmsf,null); + } + catch (Exception ex){ + //fatal + error(ex,doc,ERROR_DOC_VALIDATE,ErrorHandler.ERROR_PROCESS_FATAL); + return false; + } + //get the exporter specified for this document + CGExporter exporter = (CGExporter)settings.cp_Exporters.getElement(doc.cp_Exporter); + + + try { + + /* + * here I calculate the destination filename. + * I take the original filename (docFilename), substract the extension, (docExt) -> (fn) + * and find an available filename which starts with + * this filename, but with the new extension. (destExt) + */ + String docFilename = fileAccess.getFilename(doc.cp_URL); + + String docExt = FileAccess.getExtension(docFilename); + String fn = doc.localFilename.substring(0,doc.localFilename.length()-docExt.length()-1); //filename without extension + + /* + * the copyExporter does not change + * the extension of the target... + */ + String destExt = ( + exporter.cp_Extension.equals("") + ? FileAccess.getExtension(docFilename) + : exporter.cp_Extension + ); + + /* if this filter needs to export to its own directory... + * this is the case in, for example, impress html export + */ + if (exporter.cp_OwnDirectory) { //+++ + dir = fileAccess.createNewDir(dir, fn ); + doc.dirName = fileAccess.getFilename(dir); + } + + /* + * if two files with the same name + * need to be exported ? So here + * i get a new filename, so I do not + * overwrite files... + */ + String file = fileAccess.getNewFile(dir,fn,destExt); + + + /* set filename with extension. + * this will be used by the exporter, + * and to generate the TOC. + */ + doc.urlFilename = fileAccess.getFilename(file); + + task.advance(true); + + try { + //export + getExporter(exporter).export(doc, file, xmsf, task); + task.advance(true); + } + /* + * getExporter(..) throws + * IllegalAccessException, InstantiationException, ClassNotFoundException + * export() throws Exception + */ + catch (Exception ex) { + //nonfatal + if (!error(ex, doc, ERROR_EXPORT, ErrorHandler.ERROR_NORMAL_IGNORE)) + return false; + } + } + catch (Exception ex) { + //nonfatal + if (!error(ex,doc,ERROR_EXPORT_MKDIR,ErrorHandler.ERROR_NORMAL_ABORT)) + return false; + } + + return true; + + } + + /** + * submit an error. + * @param ex the exception + * @param arg1 error argument + * @param arg2 error argument 2 + * @param errType error type + * @return the interaction result + */ + private boolean error(Exception ex, Object arg1, int arg2, int errType) { + result = false; + return errorHandler.error(ex,arg1,arg2,errType); + } + + + /** + * advances the given task in the given count of steps, + * marked as failed. + * @param task the task to advance + * @param count the number of steps to advance + */ + private void failTask(Task task, int count) { + while (count-- > 0) + task.advance(false); + } + + /** + * creates an instance of the exporter class + * as specified by the + * exporter object. + * @param export specifies the exporter to be created + * @return the Exporter instance + * @throws ClassNotFoundException + * @throws IllegalAccessException + * @throws InstantiationException + */ + private Exporter createExporter(CGExporter export) + throws ClassNotFoundException, + IllegalAccessException, + InstantiationException + { + Exporter e = (Exporter) Class.forName(export.cp_ExporterClass).newInstance(); + e.init(export); + return e; + } + + /** + * searches the an exporter for the given CGExporter object + * in the cache. + * If its not there, creates it, stores it in the cache and + * returns it. + * @param export specifies the needed exporter. + * @return an Exporter instance + * @throws ClassNotFoundException thrown when using Class.forName(string) + * @throws IllegalAccessException thrown when using Class.forName(string) + * @throws InstantiationException thrown when using Class.forName(string) + */ + private Exporter getExporter(CGExporter export) + throws ClassNotFoundException, + IllegalAccessException, + InstantiationException + { + Exporter exp = (Exporter)exporters.get(export); + if (exp == null) { + exp = createExporter(export); + exporters.put(export,exp); + } + return exp; + } + + /** + * @return tru if everything went smooth, false + * if error(s) accured. + */ + public boolean getResult() { + return (myTask.getFailed() == 0) && result; + } + +} |