/* * SiteAddFormHandler.java * * This work is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * This work 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * * Copyright (c) 2004-2006 Per Cederberg. All rights reserved. */ package org.liquidsite.app.admin; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Date; import java.util.Enumeration; import java.util.Iterator; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.liquidsite.app.admin.view.AdminView; import org.liquidsite.core.content.Content; import org.liquidsite.core.content.ContentException; import org.liquidsite.core.content.ContentFile; import org.liquidsite.core.content.ContentFolder; import org.liquidsite.core.content.ContentManager; import org.liquidsite.core.content.ContentPage; import org.liquidsite.core.content.ContentSecurityException; import org.liquidsite.core.content.ContentSite; import org.liquidsite.core.content.ContentTemplate; import org.liquidsite.core.content.ContentTranslator; import org.liquidsite.core.content.Domain; import org.liquidsite.core.content.PersistentObject; import org.liquidsite.core.content.User; import org.liquidsite.core.web.FormValidationException; import org.liquidsite.core.web.Request; import org.liquidsite.core.web.Request.FileParameter; /** * The site add request handler. This class handles the add workflow * for the site view. * * @author Per Cederberg, <per at percederberg dot net> * @version 1.0 */ class SiteAddFormHandler extends AdminFormHandler { /** * Creates a new site add request handler. */ public SiteAddFormHandler() { super("site.html", "add-site.html", false); } /** * Displays a form for the specified workflow step. This method * will NOT be called when returning to the start page. * * @param request the request object * @param step the workflow step * * @throws ContentException if the database couldn't be accessed * properly * @throws ContentSecurityException if the user didn't have the * required permissions */ protected void displayStep(Request request, int step) throws ContentException, ContentSecurityException { String category = request.getParameter("category", ""); PersistentObject parent = AdminUtils.getReference(request); if (step == 1) { AdminView.SITE.viewAddObject(request, parent); } else if (category.equals("domain")) { AdminView.SITE.viewEditDomain(request, parent, null); } else if (category.equals("site")) { AdminView.SITE.viewEditSite(request, parent); } else if (category.equals("folder")) { AdminView.SITE.viewEditFolder(request, parent, null); } else if (category.equals("page")) { AdminView.SITE.viewEditPage(request, (Content) parent); } else if (category.equals("file")) { AdminView.SITE.viewEditFile(request, (Content) parent); } else if (category.equals("translator")) { AdminView.SITE.viewEditTranslator(request, (Content) parent); } else if (category.equals("template")) { AdminView.SITE.viewEditTemplate(request, parent, null); } else { AdminView.SITE.viewAddObject(request, parent); } } /** * Validates a form for the specified workflow step. If the form * validation fails in this step, the form page for the workflow * step will be displayed again with an 'error' attribute * containing the message in the validation exception. * * @param request the request object * @param step the workflow step * * @throws ContentException if the database couldn't be accessed * properly * @throws ContentSecurityException if the user didn't have the * required permissions * @throws FormValidationException if the form request data * validation failed */ protected void validateStep(Request request, int step) throws ContentException, ContentSecurityException, FormValidationException { SiteEditFormHandler edit = SiteEditFormHandler.getInstance(); String category = request.getParameter("category", ""); String message; if (step == 1) { if (category.equals("")) { message = "No content category specified"; throw new FormValidationException("category", message); } } else { if (category.equals("file")) { validateFile(request); } else { edit.validateStep(request, step); } } } /** * Validates a site file add form. * * @param request the request object * * @throws ContentException if the database couldn't be accessed * properly * @throws ContentSecurityException if the user didn't have the * required permissions * @throws FormValidationException if the form request data * validation failed */ private void validateFile(Request request) throws ContentException, ContentSecurityException, FormValidationException { ContentManager manager = AdminUtils.getContentManager(); FileParameter param; Content content; String name; String message; param = request.getFileParameter("upload"); if (param == null || param.getSize() <= 0) { message = "No file upload specified"; throw new FormValidationException("upload", message); } if (request.getParameter("unpack", "").equals("true")) { if (!param.getName().endsWith(".zip")) { message = "Uploaded file must have .zip " + "extension to be unpacked"; throw new FormValidationException("upload", message); } } else { name = request.getParameter("name"); if (name == null || name.equals("")) { name = convertFileName(param.getName()); } content = (Content) AdminUtils.getReference(request); content = manager.getContentChild(request.getUser(), content, name); if (content != null) { message = "Another object with identical name " + "already exists in the parent folder"; throw new FormValidationException("name", message); } } } /** * Handles a validated form for the specified workflow step. This * method returns the next workflow step, i.e. the step used when * calling the display method. If the special zero (0) workflow * step is returned, the workflow is assumed to have terminated. * Note that this method also allows additional validation to * occur. By returning the incoming workflow step number and * setting the appropriate request attributes the same results as * in the normal validate method can be achieved. For recoverable * errors, this is the recommended course of action. * * @param request the request object * @param step the workflow step * * @return the next workflow step, or * zero (0) if the workflow has finished * * @throws ContentException if the database couldn't be accessed * properly * @throws ContentSecurityException if the user didn't have the * required permissions */ protected int handleStep(Request request, int step) throws ContentException, ContentSecurityException { String category = request.getParameter("category", ""); Object parent = AdminUtils.getReference(request); if (step == 1) { return 2; } else if (category.equals("domain")) { handleAddDomain(request, (Domain) parent); } else if (category.equals("site")) { handleAddSite(request, (Domain) parent); } else if (category.equals("folder")) { handleAddFolder(request, (Content) parent); } else if (category.equals("page")) { handleAddPage(request, (Content) parent); } else if (category.equals("file")) { handleAddFile(request, (Content) parent); } else if (category.equals("translator")) { handleAddTranslator(request, (Content) parent); } else if (category.equals("template")) { handleAddTemplate(request, parent); } return 0; } /** * Handles the add domain form. The parent domain object must be * specified in case the uses chooses to go back to the * previous step. * * @param request the request object * @param parent the parent domain object * * @throws ContentException if the database couldn't be accessed * properly * @throws ContentSecurityException if the user didn't have the * required permissions */ private void handleAddDomain(Request request, Domain parent) throws ContentException, ContentSecurityException { ContentManager manager = AdminUtils.getContentManager(); Domain domain; Iterator iter; String param; String name; String descr; domain = new Domain(manager, request.getParameter("name")); domain.setDescription(request.getParameter("description")); domain.setMailFrom(request.getParameter("mailaddress")); iter = request.getAllParameters().keySet().iterator(); while (iter.hasNext()) { param = iter.next().toString(); if (param.startsWith("host.") && param.endsWith(".name")) { param = param.substring(0, param.length() - 5); name = request.getParameter(param + ".name"); descr = request.getParameter(param + ".description"); domain.addHost(name, descr); } } domain.save(request.getUser()); AdminView.SITE.setSiteTreeFocus(request, domain); } /** * Handles the add site form. * * @param request the request object * @param parent the parent domain object * * @throws ContentException if the database couldn't be accessed * properly * @throws ContentSecurityException if the user didn't have the * required permissions */ private void handleAddSite(Request request, Domain parent) throws ContentException, ContentSecurityException { ContentManager manager = AdminUtils.getContentManager(); User user = request.getUser(); ContentSite site; site = new ContentSite(manager, parent); site.setName(request.getParameter("name")); site.setProtocol(request.getParameter("protocol")); site.setHost(request.getParameter("host")); site.setPort(Integer.parseInt(request.getParameter("port"))); site.setDirectory(request.getParameter("dir")); site.setAdmin(request.getParameter("admin", "").equals("true")); site.setComment(request.getParameter("comment")); if (request.getParameter("action", "").equals("publish")) { site.setRevisionNumber(1); site.setOnlineDate(new Date()); } site.save(user); AdminView.SITE.setSiteTreeFocus(request, site); } /** * Handles the add folder form. * * @param request the request object * @param parent the parent content object * * @throws ContentException if the database couldn't be accessed * properly * @throws ContentSecurityException if the user didn't have the * required permissions */ private void handleAddFolder(Request request, Content parent) throws ContentException, ContentSecurityException { ContentManager manager = AdminUtils.getContentManager(); User user = request.getUser(); ContentFolder folder; folder = new ContentFolder(manager, parent); folder.setName(request.getParameter("name")); folder.setComment(request.getParameter("comment")); if (request.getParameter("action", "").equals("publish")) { folder.setRevisionNumber(1); folder.setOnlineDate(new Date()); } folder.save(user); AdminView.SITE.setSiteTreeFocus(request, folder); } /** * Handles the add page form. * * @param request the request object * @param parent the parent content object * * @throws ContentException if the database couldn't be accessed * properly * @throws ContentSecurityException if the user didn't have the * required permissions */ private void handleAddPage(Request request, Content parent) throws ContentException, ContentSecurityException { ContentManager manager = AdminUtils.getContentManager(); ContentPage page; Map params = request.getAllParameters(); Iterator iter = params.keySet().iterator(); String name; String value; int id; page = new ContentPage(manager, parent); page.setName(request.getParameter("name")); try { id = Integer.parseInt(request.getParameter("template")); } catch (NumberFormatException ignore) { id = 0; } page.setTemplateId(id); page.setComment(request.getParameter("comment")); while (iter.hasNext()) { name = iter.next().toString(); if (name.startsWith("element.")) { value = params.get(name).toString(); page.setElement(name.substring(8), value); } } if (request.getParameter("action", "").equals("publish")) { page.setRevisionNumber(1); page.setOnlineDate(new Date()); } page.save(request.getUser()); AdminView.SITE.setSiteTreeFocus(request, page); } /** * Handles the add file form. * * @param request the request object * @param parent the parent content object * * @throws ContentException if the database couldn't be accessed * properly * @throws ContentSecurityException if the user didn't have the * required permissions */ private void handleAddFile(Request request, Content parent) throws ContentException, ContentSecurityException { ContentManager manager = AdminUtils.getContentManager(); FileParameter param; ContentFile file; String name; try { param = request.getFileParameter("upload"); if (request.getParameter("unpack", "").equals("true")) { handleAddZipFile(request, parent, param.write()); } else { name = convertFileName(param.getName()); file = new ContentFile(manager, parent, name); name = request.getParameter("name"); if (name == null || name.equals("")) { name = file.getFileName(); } file.setName(name); file.setComment(request.getParameter("comment")); if (request.getParameter("action", "").equals("publish")) { file.setRevisionNumber(1); file.setOnlineDate(new Date()); } file.save(request.getUser()); param.write(file.getFile()); AdminView.SITE.setSiteTreeFocus(request, file); } } catch (IOException e) { throw new ContentException(e.getMessage()); } } /** * Handles the add file form for ZIP file unpacking. The ZIP file * will be removed by this method once processed. * * @param request the request object * @param parent the parent content object * @param file the ZIP file to process * * @throws ContentException if the database couldn't be accessed * properly or if the ZIP file contained errors * @throws ContentSecurityException if the user didn't have the * required permissions */ private void handleAddZipFile(Request request, Content parent, File file) throws ContentException, ContentSecurityException { ZipFile zip; ZipEntry entry; Enumeration entries; boolean publish; Content content; try { publish = request.getParameter("action", "").equals("publish"); zip = new ZipFile(file); entries = zip.entries(); while (entries.hasMoreElements()) { entry = (ZipEntry) entries.nextElement(); content = zipCreateContent(entry, parent, request.getParameter("comment"), publish, request.getUser()); if (content instanceof ContentFile) { zipExtract(zip, entry, ((ContentFile) content).getFile()); } } zip.close(); } catch (IOException e) { throw new ContentException(e.getMessage()); } finally { file.delete(); } } /** * Handles the add translator form. * * @param request the request object * @param parent the parent content object * * @throws ContentException if the database couldn't be accessed * properly * @throws ContentSecurityException if the user didn't have the * required permissions */ private void handleAddTranslator(Request request, Content parent) throws ContentException, ContentSecurityException { ContentManager manager = AdminUtils.getContentManager(); ContentTranslator translator; int id; translator = new ContentTranslator(manager, parent); translator.setName(request.getParameter("name")); try { id = Integer.parseInt(request.getParameter("section")); } catch (NumberFormatException ignore) { id = 0; } translator.setType(ContentTranslator.SECTION_TYPE); translator.setSectionId(id); translator.setComment(request.getParameter("comment")); if (request.getParameter("action", "").equals("publish")) { translator.setRevisionNumber(1); translator.setOnlineDate(new Date()); } translator.save(request.getUser()); AdminView.SITE.setSiteTreeFocus(request, translator); } /** * Handles the add template form. * * @param request the request object * @param parent the parent domain or template object * * @throws ContentException if the database couldn't be accessed * properly * @throws ContentSecurityException if the user didn't have the * required permissions */ private void handleAddTemplate(Request request, Object parent) throws ContentException, ContentSecurityException { ContentManager manager = AdminUtils.getContentManager(); ContentTemplate template; Map params = request.getAllParameters(); Iterator iter = params.keySet().iterator(); String name; String value; if (parent instanceof Domain) { template = new ContentTemplate(manager, (Domain) parent); } else { template = new ContentTemplate(manager, (ContentTemplate) parent); } template.setName(request.getParameter("name")); template.setComment(request.getParameter("comment")); while (iter.hasNext()) { name = iter.next().toString(); if (name.startsWith("element.")) { value = params.get(name).toString(); template.setElement(name.substring(8), value); } } if (request.getParameter("action", "").equals("publish")) { template.setRevisionNumber(1); template.setOnlineDate(new Date()); } template.save(request.getUser()); AdminView.SITE.setSiteTreeFocus(request, template); } /** * Creates the content object for a ZIP archive entry. The content * object will either be a new object or a new revision. * * @param entry the ZIP archive entry * @param parent the parent content object * @param comment the content comment * @param publish the publish flag * @param user the user performing the operation * * @return the content object created * * @throws ContentException if the database couldn't be accessed * properly * @throws ContentSecurityException if the user didn't have the * required permissions */ private Content zipCreateContent(ZipEntry entry, Content parent, String comment, boolean publish, User user) throws ContentException, ContentSecurityException { ContentManager manager = AdminUtils.getContentManager(); Content content; String name; String fileName; int pos; name = entry.getName(); if (name.endsWith("/")) { name = name.substring(0, name.length() - 1); } while (name.indexOf('/') >= 0) { pos = name.indexOf('/'); if (pos == 0) { name = name.substring(1); } else { fileName = convertFileName(name.substring(0, pos)); content = manager.getContentChild(user, parent, fileName); if (content == null) { content = new ContentFolder(manager, parent); content.setName(fileName); content.setComment(comment); if (publish) { content.setRevisionNumber(1); content.setOnlineDate(new Date()); } content.save(user); } parent = content; name = name.substring(pos + 1); } } name = convertFileName(name); content = manager.getContentChild(user, parent, name); if (content == null) { if (entry.isDirectory()) { content = new ContentFolder(manager, parent); } else { content = new ContentFile(manager, parent, name); } content.setName(name); if (publish) { content.setRevisionNumber(1); content.setOnlineDate(new Date()); } } else { content.setRevisionNumber(0); if (content instanceof ContentFile) { ((ContentFile) content).setFileName(name); } if (publish) { content.setRevisionNumber(content.getMaxRevisionNumber() + 1); content.setOnlineDate(new Date()); content.setOfflineDate(null); } } content.setComment(comment); content.save(user); return content; } /** * Extracts a file from a ZIP archive. The contents of the file * will be saved in the specified file. * * @param zip the ZIP archive * @param entry the ZIP archive entry to extract * @param dest the destination file * * @throws IOException if the file date couldn't be extracted or * written correctly */ private void zipExtract(ZipFile zip, ZipEntry entry, File dest) throws IOException { InputStream in; FileOutputStream out; byte[] buffer = new byte[4096]; int size; in = zip.getInputStream(entry); out = new FileOutputStream(dest); try { do { size = in.read(buffer); if (size > 0) { out.write(buffer, 0, size); } } while (size > 0); } finally { try { in.close(); } catch (IOException ignore) { // Do nothing } try { out.close(); } catch (IOException ignore) { // Do nothing } } } }