0001: /*
0002: * File : $Source: /usr/local/cvs/opencms/src/org/opencms/importexport/CmsExport.java,v $
0003: * Date : $Date: 2008-02-27 12:05:48 $
0004: * Version: $Revision: 1.94 $
0005: *
0006: * This library is part of OpenCms -
0007: * the Open Source Content Management System
0008: *
0009: * Copyright (c) 2002 - 2008 Alkacon Software GmbH (http://www.alkacon.com)
0010: *
0011: * This library is free software; you can redistribute it and/or
0012: * modify it under the terms of the GNU Lesser General Public
0013: * License as published by the Free Software Foundation; either
0014: * version 2.1 of the License, or (at your option) any later version.
0015: *
0016: * This library is distributed in the hope that it will be useful,
0017: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0018: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0019: * Lesser General Public License for more details.
0020: *
0021: * For further information about Alkacon Software GmbH, please see the
0022: * company website: http://www.alkacon.com
0023: *
0024: * For further information about OpenCms, please see the
0025: * project website: http://www.opencms.org
0026: *
0027: * You should have received a copy of the GNU Lesser General Public
0028: * License along with this library; if not, write to the Free Software
0029: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0030: */
0031:
0032: package org.opencms.importexport;
0033:
0034: import org.opencms.configuration.CmsConfigurationManager;
0035: import org.opencms.db.CmsResourceState;
0036: import org.opencms.file.CmsFile;
0037: import org.opencms.file.CmsFolder;
0038: import org.opencms.file.CmsGroup;
0039: import org.opencms.file.CmsObject;
0040: import org.opencms.file.CmsProject;
0041: import org.opencms.file.CmsProperty;
0042: import org.opencms.file.CmsResource;
0043: import org.opencms.file.CmsResourceFilter;
0044: import org.opencms.file.CmsUser;
0045: import org.opencms.file.CmsVfsException;
0046: import org.opencms.i18n.CmsMessageContainer;
0047: import org.opencms.main.CmsEvent;
0048: import org.opencms.main.CmsException;
0049: import org.opencms.main.CmsLog;
0050: import org.opencms.main.I_CmsEventListener;
0051: import org.opencms.main.OpenCms;
0052: import org.opencms.relations.CmsRelation;
0053: import org.opencms.relations.CmsRelationFilter;
0054: import org.opencms.report.CmsShellReport;
0055: import org.opencms.report.I_CmsReport;
0056: import org.opencms.security.CmsAccessControlEntry;
0057: import org.opencms.security.CmsOrganizationalUnit;
0058: import org.opencms.security.CmsRole;
0059: import org.opencms.security.CmsRoleViolationException;
0060: import org.opencms.util.CmsDataTypeUtil;
0061: import org.opencms.util.CmsDateUtil;
0062: import org.opencms.util.CmsFileUtil;
0063: import org.opencms.util.CmsUUID;
0064: import org.opencms.util.CmsXmlSaxWriter;
0065: import org.opencms.workplace.CmsWorkplace;
0066:
0067: import java.io.FileOutputStream;
0068: import java.io.IOException;
0069: import java.io.StringWriter;
0070: import java.util.ArrayList;
0071: import java.util.Collections;
0072: import java.util.HashSet;
0073: import java.util.Iterator;
0074: import java.util.List;
0075: import java.util.Set;
0076: import java.util.zip.ZipEntry;
0077: import java.util.zip.ZipOutputStream;
0078:
0079: import org.apache.commons.codec.binary.Base64;
0080: import org.apache.commons.logging.Log;
0081:
0082: import org.dom4j.Document;
0083: import org.dom4j.DocumentHelper;
0084: import org.dom4j.Element;
0085: import org.dom4j.io.SAXWriter;
0086: import org.xml.sax.SAXException;
0087:
0088: /**
0089: * Provides the functionality to export files from the OpenCms VFS to a ZIP file.<p>
0090: *
0091: * The ZIP file written will contain a copy of all exported files with their contents.
0092: * It will also contain a <code>manifest.xml</code> file in which all meta-information
0093: * about this files are stored, like permissions etc.<p>
0094: *
0095: * @author Alexander Kandzior
0096: * @author Michael Emmerich
0097: * @author Michael Moossen
0098: *
0099: * @version $Revision: 1.94 $
0100: *
0101: * @since 6.0.0
0102: */
0103: public class CmsExport {
0104:
0105: /** The log object for this class. */
0106: private static final Log LOG = CmsLog.getLog(CmsExport.class);
0107:
0108: private static final int SUB_LENGTH = 4096;
0109:
0110: /** Counter for the export. */
0111: private int m_exportCount;
0112:
0113: /** Set of all exported files, required for preventing redundant sibling export. */
0114: private Set m_exportedResources;
0115:
0116: /** The export ZIP stream to write resources to. */
0117: private ZipOutputStream m_exportZipStream;
0118:
0119: /** The export parameters. */
0120: private CmsExportParameters m_parameters;
0121:
0122: /** The top level file node where all resources are appended to. */
0123: private Element m_resourceNode;
0124:
0125: /** The SAX writer to write the output to. */
0126: private SAXWriter m_saxWriter;
0127:
0128: /** Cache for previously added super folders. */
0129: private List m_super Folders;
0130:
0131: /**
0132: * Constructs a new uninitialized export, required for special subclass data export.<p>
0133: */
0134: public CmsExport() {
0135:
0136: // empty constructor
0137: }
0138:
0139: /** The cms context. */
0140: private CmsObject m_cms;
0141:
0142: /** The report. */
0143: private I_CmsReport m_report;
0144:
0145: /**
0146: * Constructs a new export.<p>
0147: *
0148: * @param cms the cms context
0149: * @param report the report
0150: *
0151: * @throws CmsRoleViolationException if the current user has not the required role
0152: */
0153: public CmsExport(CmsObject cms, I_CmsReport report)
0154: throws CmsRoleViolationException {
0155:
0156: m_cms = cms;
0157: m_report = report;
0158:
0159: // check if the user has the required permissions
0160: OpenCms.getRoleManager().checkRole(getCms(),
0161: CmsRole.DATABASE_MANAGER);
0162:
0163: }
0164:
0165: /**
0166: * Export the data.<p>
0167: *
0168: * @param parameters the export parameters
0169: *
0170: * @throws CmsImportExportException if something goes wrong
0171: */
0172: public void exportData(CmsExportParameters parameters)
0173: throws CmsImportExportException {
0174:
0175: m_parameters = parameters;
0176: m_exportCount = 0;
0177:
0178: // clear all caches
0179: getReport().println(
0180: Messages.get().container(Messages.RPT_CLEARCACHE_0),
0181: I_CmsReport.FORMAT_NOTE);
0182: OpenCms.fireCmsEvent(new CmsEvent(
0183: I_CmsEventListener.EVENT_CLEAR_CACHES,
0184: Collections.EMPTY_MAP));
0185:
0186: try {
0187: Element exportNode = openExportFile();
0188:
0189: if (m_parameters.getModuleInfo() != null) {
0190: // add the module element
0191: exportNode.add(m_parameters.getModuleInfo());
0192: // write the XML
0193: digestElement(exportNode, m_parameters.getModuleInfo());
0194: }
0195:
0196: // export account data only if selected
0197: if (m_parameters.isExportAccountData()) {
0198: Element accountsElement = exportNode
0199: .addElement(CmsImportVersion7.N_ACCOUNTS);
0200: getSaxWriter().writeOpen(accountsElement);
0201:
0202: exportOrgUnits(accountsElement);
0203:
0204: getSaxWriter().writeClose(accountsElement);
0205: exportNode.remove(accountsElement);
0206: }
0207:
0208: // export resource data only if selected
0209: if (m_parameters.isExportResourceData()) {
0210: exportAllResources(exportNode, m_parameters
0211: .getResources());
0212: }
0213:
0214: // export project data only if selected
0215: if (m_parameters.isExportProjectData()) {
0216: Element projectsElement = exportNode
0217: .addElement(CmsImportVersion7.N_PROJECTS);
0218: getSaxWriter().writeOpen(projectsElement);
0219:
0220: exportProjects(projectsElement);
0221:
0222: getSaxWriter().writeClose(projectsElement);
0223: exportNode.remove(projectsElement);
0224: }
0225:
0226: closeExportFile(exportNode);
0227: } catch (SAXException se) {
0228: getReport().println(se);
0229:
0230: CmsMessageContainer message = Messages
0231: .get()
0232: .container(
0233: Messages.ERR_IMPORTEXPORT_ERROR_EXPORTING_TO_FILE_1,
0234: getExportFileName());
0235: if (LOG.isDebugEnabled()) {
0236: LOG.debug(message.key(), se);
0237: }
0238:
0239: throw new CmsImportExportException(message, se);
0240: } catch (IOException ioe) {
0241: getReport().println(ioe);
0242:
0243: CmsMessageContainer message = Messages
0244: .get()
0245: .container(
0246: Messages.ERR_IMPORTEXPORT_ERROR_EXPORTING_TO_FILE_1,
0247: getExportFileName());
0248: if (LOG.isDebugEnabled()) {
0249: LOG.debug(message.key(), ioe);
0250: }
0251:
0252: throw new CmsImportExportException(message, ioe);
0253: }
0254: }
0255:
0256: /**
0257: * Constructs a new export.<p>
0258: *
0259: * @param cms the cmsObject to work with
0260: * @param exportFile the file or folder to export to
0261: * @param resourcesToExport the paths of folders and files to export
0262: * @param includeSystem if <code>true</code>, the system folder is included
0263: * @param includeUnchanged <code>true</code>, if unchanged files should be included
0264: *
0265: * @throws CmsImportExportException if something goes wrong
0266: * @throws CmsRoleViolationException if the current user has not the required role
0267: *
0268: * @deprecated use the {@link CmsExportParameters} constructor instead
0269: */
0270: public CmsExport(CmsObject cms, String exportFile,
0271: List resourcesToExport, boolean includeSystem,
0272: boolean includeUnchanged) throws CmsImportExportException,
0273: CmsRoleViolationException {
0274:
0275: this (cms, exportFile, resourcesToExport, includeSystem,
0276: includeUnchanged, null, false, 0, new CmsShellReport(
0277: cms.getRequestContext().getLocale()));
0278: }
0279:
0280: /**
0281: * Constructs a new export.<p>
0282: *
0283: * @param cms the cmsObject to work with
0284: * @param exportFile the file or folder to export to
0285: * @param resourcesToExport the paths of folders and files to export
0286: * @param includeSystem if <code>true</code>, the system folder is included
0287: * @param includeUnchanged <code>true</code>, if unchanged files should be included
0288: * @param moduleElement module informations in a Node for module export
0289: * @param exportUserdata if <code>true</code>, the user and group data will also be exported
0290: * @param contentAge export contents changed after this date/time
0291: * @param report to handle the log messages
0292: *
0293: * @throws CmsImportExportException if something goes wrong
0294: * @throws CmsRoleViolationException if the current user has not the required role
0295: *
0296: * @deprecated use the {@link CmsExportParameters} constructor instead
0297: */
0298: public CmsExport(CmsObject cms, String exportFile,
0299: List resourcesToExport, boolean includeSystem,
0300: boolean includeUnchanged, Element moduleElement,
0301: boolean exportUserdata, long contentAge, I_CmsReport report)
0302: throws CmsImportExportException, CmsRoleViolationException {
0303:
0304: this (cms, exportFile, resourcesToExport, includeSystem,
0305: includeUnchanged, moduleElement, exportUserdata,
0306: contentAge, report, true);
0307: }
0308:
0309: /**
0310: * Constructs a new export.<p>
0311: *
0312: * @param cms the cmsObject to work with
0313: * @param exportFile the file or folder to export to
0314: * @param resourcesToExport the paths of folders and files to export
0315: * @param includeSystem if <code>true</code>, the system folder is included
0316: * @param includeUnchanged <code>true</code>, if unchanged files should be included
0317: * @param moduleElement module informations in a Node for module export
0318: * @param exportUserdata if <code>true</code>, the user and group data will also be exported
0319: * @param contentAge export contents changed after this date/time
0320: * @param report to handle the log messages
0321: * @param recursive recursive flag
0322: *
0323: * @throws CmsImportExportException if something goes wrong
0324: * @throws CmsRoleViolationException if the current user has not the required role
0325: *
0326: * @deprecated use the {@link CmsExportParameters} constructor instead
0327: */
0328: public CmsExport(CmsObject cms, String exportFile,
0329: List resourcesToExport, boolean includeSystem,
0330: boolean includeUnchanged, Element moduleElement,
0331: boolean exportUserdata, long contentAge,
0332: I_CmsReport report, boolean recursive)
0333: throws CmsImportExportException, CmsRoleViolationException {
0334:
0335: this (cms, report);
0336: exportData(new CmsExportParameters(exportFile, moduleElement,
0337: true, exportUserdata, false, resourcesToExport,
0338: includeSystem, includeUnchanged, contentAge, recursive,
0339: false));
0340: }
0341:
0342: /**
0343: * Exports the given folder and all child resources.<p>
0344: *
0345: * @param folderName to complete path to the resource to export
0346: *
0347: * @throws CmsImportExportException if something goes wrong
0348: * @throws SAXException if something goes wrong processing the manifest.xml
0349: * @throws IOException if not all resources could be appended to the ZIP archive
0350: */
0351: protected void addChildResources(String folderName)
0352: throws CmsImportExportException, IOException, SAXException {
0353:
0354: try {
0355: // get all subFolders
0356: List subFolders = getCms().getSubFolders(folderName,
0357: CmsResourceFilter.IGNORE_EXPIRATION);
0358: // get all files in folder
0359: List subFiles = getCms().getFilesInFolder(folderName,
0360: CmsResourceFilter.IGNORE_EXPIRATION);
0361:
0362: // walk through all files and export them
0363: for (int i = 0; i < subFiles.size(); i++) {
0364: CmsResource file = (CmsResource) subFiles.get(i);
0365: CmsResourceState state = file.getState();
0366: long age = file.getDateLastModified() < file
0367: .getDateCreated() ? file.getDateCreated()
0368: : file.getDateLastModified();
0369:
0370: if (getCms().getRequestContext().currentProject()
0371: .isOnlineProject()
0372: || (m_parameters.isIncludeUnchangedResources())
0373: || state.isNew() || state.isChanged()) {
0374: if (!state.isDeleted()
0375: && !CmsWorkplace.isTemporaryFile(file)
0376: && (age >= m_parameters.getContentAge())) {
0377: String export = getCms().getSitePath(file);
0378: if (checkExportResource(export)) {
0379: if (isInExportableProject(file)) {
0380: exportFile(getCms()
0381: .readFile(
0382: export,
0383: CmsResourceFilter.IGNORE_EXPIRATION));
0384: }
0385: }
0386: }
0387: }
0388: // release file header memory
0389: subFiles.set(i, null);
0390: }
0391: // all files are exported, release memory
0392: subFiles = null;
0393:
0394: // walk through all subfolders and export them
0395: for (int i = 0; i < subFolders.size(); i++) {
0396: CmsResource folder = (CmsResource) subFolders.get(i);
0397: if (folder.getState() != CmsResource.STATE_DELETED) {
0398: // check if this is a system-folder and if it should be included.
0399: String export = getCms().getSitePath(folder);
0400: if (checkExportResource(export)) {
0401:
0402: long age = folder.getDateLastModified() < folder
0403: .getDateCreated() ? folder
0404: .getDateCreated() : folder
0405: .getDateLastModified();
0406: // export this folder only if age is above selected age
0407: // default for selected age (if not set by user) is <code>long 0</code> (i.e. 1970)
0408: if (age >= m_parameters.getContentAge()) {
0409: // only export folder data to manifest.xml if it has changed
0410: appendResourceToManifest(folder, false);
0411: }
0412:
0413: // export all sub-resources in this folder
0414: addChildResources(getCms().getSitePath(folder));
0415: }
0416: }
0417: // release folder memory
0418: subFolders.set(i, null);
0419: }
0420: } catch (CmsImportExportException e) {
0421:
0422: throw e;
0423: } catch (CmsException e) {
0424:
0425: CmsMessageContainer message = Messages
0426: .get()
0427: .container(
0428: Messages.ERR_IMPORTEXPORT_ERROR_ADDING_CHILD_RESOURCES_1,
0429: folderName);
0430: if (LOG.isDebugEnabled()) {
0431: LOG.debug(message.key(), e);
0432: }
0433:
0434: throw new CmsImportExportException(message, e);
0435: }
0436: }
0437:
0438: /**
0439: * Adds all files in fileNames to the manifest.xml file.<p>
0440: *
0441: * @param fileNames list of path Strings, e.g. <code>/folder/index.html</code>
0442: *
0443: * @throws CmsImportExportException if something goes wrong
0444: * @throws IOException if a file could not be exported
0445: * @throws SAXException if something goes wrong processing the manifest.xml
0446: */
0447: protected void addFiles(List fileNames)
0448: throws CmsImportExportException, IOException, SAXException {
0449:
0450: if (fileNames != null) {
0451: for (int i = 0; i < fileNames.size(); i++) {
0452: String fileName = (String) fileNames.get(i);
0453:
0454: try {
0455: CmsFile file = getCms().readFile(fileName,
0456: CmsResourceFilter.IGNORE_EXPIRATION);
0457: if (!file.getState().isDeleted()
0458: && !CmsWorkplace.isTemporaryFile(file)) {
0459: if (checkExportResource(fileName)) {
0460: if (m_parameters.isRecursive()) {
0461: addParentFolders(fileName);
0462: }
0463: if (isInExportableProject(file)) {
0464: exportFile(file);
0465: }
0466: }
0467: }
0468: } catch (CmsImportExportException e) {
0469:
0470: throw e;
0471: } catch (CmsException e) {
0472: if (e instanceof CmsVfsException) { // file not found
0473: CmsMessageContainer message = Messages
0474: .get()
0475: .container(
0476: Messages.ERR_IMPORTEXPORT_ERROR_ADDING_FILE_1,
0477: fileName);
0478: if (LOG.isDebugEnabled()) {
0479: LOG.debug(message.key(), e);
0480: }
0481:
0482: throw new CmsImportExportException(message, e);
0483: }
0484: }
0485: }
0486: }
0487: }
0488:
0489: /**
0490: * Adds the parent folders of the given resource to the config file,
0491: * starting at the top, excluding the root folder.<p>
0492: *
0493: * @param resourceName the name of a resource in the VFS
0494: *
0495: * @throws CmsImportExportException if something goes wrong
0496: * @throws SAXException if something goes wrong processing the manifest.xml
0497: */
0498: protected void addParentFolders(String resourceName)
0499: throws CmsImportExportException, SAXException {
0500:
0501: try {
0502: // this is a resource in /system/ folder and option includeSystem is not true
0503: if (!checkExportResource(resourceName)) {
0504: return;
0505: }
0506:
0507: // Initialize the "previously added folder cache"
0508: if (m_super Folders == null) {
0509: m_super Folders = new ArrayList();
0510: }
0511: List super Folders = new ArrayList();
0512:
0513: // Check, if the path is really a folder
0514: if (resourceName.lastIndexOf("/") != (resourceName.length() - 1)) {
0515: resourceName = resourceName.substring(0, resourceName
0516: .lastIndexOf("/") + 1);
0517: }
0518: while (resourceName.length() > "/".length()) {
0519: super Folders.add(resourceName);
0520: resourceName = resourceName.substring(0, resourceName
0521: .length() - 1);
0522: resourceName = resourceName.substring(0, resourceName
0523: .lastIndexOf("/") + 1);
0524: }
0525: for (int i = super Folders.size() - 1; i >= 0; i--) {
0526: String addFolder = (String) super Folders.get(i);
0527: if (!m_super Folders.contains(addFolder)) {
0528: // This super folder was NOT added previously. Add it now!
0529: CmsFolder folder = getCms().readFolder(addFolder,
0530: CmsResourceFilter.IGNORE_EXPIRATION);
0531: appendResourceToManifest(folder, false);
0532: // Remember that this folder was added
0533: m_super Folders.add(addFolder);
0534: }
0535: }
0536: } catch (CmsImportExportException e) {
0537:
0538: throw e;
0539: } catch (CmsException e) {
0540:
0541: CmsMessageContainer message = Messages
0542: .get()
0543: .container(
0544: Messages.ERR_IMPORTEXPORT_ERROR_ADDING_PARENT_FOLDERS_1,
0545: resourceName);
0546: if (LOG.isDebugEnabled()) {
0547: LOG.debug(message.key(), e);
0548: }
0549:
0550: throw new CmsImportExportException(message, e);
0551: }
0552: }
0553:
0554: /**
0555: * Adds a property node to the manifest.xml.<p>
0556: *
0557: * @param propertiesElement the parent element to append the node to
0558: * @param propertyName the name of the property
0559: * @param propertyValue the value of the property
0560: * @param shared if <code>true</code>, add a shared property attribute to the generated property node
0561: */
0562: protected void addPropertyNode(Element propertiesElement,
0563: String propertyName, String propertyValue, boolean shared) {
0564:
0565: if (propertyValue != null) {
0566: Element propertyElement = propertiesElement
0567: .addElement(CmsImportVersion7.N_PROPERTY);
0568: if (shared) {
0569: // add "type" attribute to the property node in case of a shared/resource property value
0570: propertyElement.addAttribute(CmsImportVersion7.A_TYPE,
0571: CmsImportVersion7.PROPERTY_ATTRIB_TYPE_SHARED);
0572: }
0573: propertyElement.addElement(CmsImportVersion7.N_NAME)
0574: .addText(propertyName);
0575: propertyElement.addElement(CmsImportVersion7.N_VALUE)
0576: .addCDATA(propertyValue);
0577: }
0578: }
0579:
0580: /**
0581: * Adds a relation node to the <code>manifest.xml</code>.<p>
0582: *
0583: * @param relationsElement the parent element to append the node to
0584: * @param structureId the structure id of the target relation
0585: * @param sitePath the site path of the target relation
0586: * @param relationType the type of the relation
0587: */
0588: protected void addRelationNode(Element relationsElement,
0589: String structureId, String sitePath, String relationType) {
0590:
0591: if ((structureId != null) && (sitePath != null)
0592: && (relationType != null)) {
0593: Element relationElement = relationsElement
0594: .addElement(CmsImportVersion7.N_RELATION);
0595:
0596: relationElement.addElement(CmsImportVersion7.N_ID).addText(
0597: structureId);
0598: relationElement.addElement(CmsImportVersion7.N_PATH)
0599: .addText(sitePath);
0600: relationElement.addElement(CmsImportVersion7.N_TYPE)
0601: .addText(relationType);
0602: }
0603: }
0604:
0605: /**
0606: * Writes the data for a resource (like access-rights) to the <code>manifest.xml</code> file.<p>
0607: *
0608: * @param resource the resource to get the data from
0609: * @param source flag to show if the source information in the xml file must be written
0610: *
0611: * @throws CmsImportExportException if something goes wrong
0612: * @throws SAXException if something goes wrong processing the manifest.xml
0613: */
0614: protected void appendResourceToManifest(CmsResource resource,
0615: boolean source) throws CmsImportExportException,
0616: SAXException {
0617:
0618: try {
0619: // only write <source> if resource is a file
0620: String fileName = trimResourceName(getCms().getSitePath(
0621: resource));
0622: if (fileName.startsWith("system/orgunits")) {
0623: // it is not allowed to export organizational unit resources
0624: // export the organizational units instead
0625: return;
0626: }
0627:
0628: // define the file node
0629: Element fileElement = m_resourceNode
0630: .addElement(CmsImportVersion7.N_FILE);
0631:
0632: if (resource.isFile()) {
0633: if (source) {
0634: fileElement.addElement(CmsImportVersion7.N_SOURCE)
0635: .addText(fileName);
0636: }
0637: } else {
0638: m_exportCount++;
0639: I_CmsReport report = getReport();
0640: // output something to the report for the folder
0641: report
0642: .print(
0643: org.opencms.report.Messages
0644: .get()
0645: .container(
0646: org.opencms.report.Messages.RPT_SUCCESSION_1,
0647: String
0648: .valueOf(m_exportCount)),
0649: I_CmsReport.FORMAT_NOTE);
0650: report
0651: .print(Messages.get().container(
0652: Messages.RPT_EXPORT_0),
0653: I_CmsReport.FORMAT_NOTE);
0654: report
0655: .print(org.opencms.report.Messages
0656: .get()
0657: .container(
0658: org.opencms.report.Messages.RPT_ARGUMENT_1,
0659: getCms().getSitePath(resource)));
0660: report
0661: .print(org.opencms.report.Messages
0662: .get()
0663: .container(
0664: org.opencms.report.Messages.RPT_DOTS_0));
0665: report.println(
0666: org.opencms.report.Messages.get().container(
0667: org.opencms.report.Messages.RPT_OK_0),
0668: I_CmsReport.FORMAT_OK);
0669:
0670: if (LOG.isInfoEnabled()) {
0671: LOG.info(Messages.get().getBundle().key(
0672: Messages.LOG_EXPORTING_OK_2,
0673: String.valueOf(m_exportCount),
0674: getCms().getSitePath(resource)));
0675: }
0676: }
0677:
0678: // <destination>
0679: fileElement.addElement(CmsImportVersion7.N_DESTINATION)
0680: .addText(fileName);
0681: // <type>
0682: fileElement.addElement(CmsImportVersion7.N_TYPE).addText(
0683: OpenCms.getResourceManager().getResourceType(
0684: resource.getTypeId()).getTypeName());
0685:
0686: // <uuidstructure>
0687: fileElement.addElement(CmsImportVersion7.N_UUIDSTRUCTURE)
0688: .addText(resource.getStructureId().toString());
0689: if (resource.isFile()) {
0690: // <uuidresource>
0691: fileElement
0692: .addElement(CmsImportVersion7.N_UUIDRESOURCE)
0693: .addText(resource.getResourceId().toString());
0694: }
0695:
0696: // <datelastmodified>
0697: fileElement
0698: .addElement(CmsImportVersion7.N_DATELASTMODIFIED)
0699: .addText(
0700: CmsDateUtil.getHeaderDate(resource
0701: .getDateLastModified()));
0702: // <userlastmodified>
0703: String userNameLastModified = null;
0704: try {
0705: userNameLastModified = getCms().readUser(
0706: resource.getUserLastModified()).getName();
0707: } catch (CmsException e) {
0708: userNameLastModified = OpenCms.getDefaultUsers()
0709: .getUserAdmin();
0710: }
0711: fileElement
0712: .addElement(CmsImportVersion7.N_USERLASTMODIFIED)
0713: .addText(userNameLastModified);
0714: // <datecreated>
0715: fileElement.addElement(CmsImportVersion7.N_DATECREATED)
0716: .addText(
0717: CmsDateUtil.getHeaderDate(resource
0718: .getDateCreated()));
0719: // <usercreated>
0720: String userNameCreated = null;
0721: try {
0722: userNameCreated = getCms().readUser(
0723: resource.getUserCreated()).getName();
0724: } catch (CmsException e) {
0725: userNameCreated = OpenCms.getDefaultUsers()
0726: .getUserAdmin();
0727: }
0728: fileElement.addElement(CmsImportVersion7.N_USERCREATED)
0729: .addText(userNameCreated);
0730: // <release>
0731: if (resource.getDateReleased() != CmsResource.DATE_RELEASED_DEFAULT) {
0732: fileElement
0733: .addElement(CmsImportVersion7.N_DATERELEASED)
0734: .addText(
0735: CmsDateUtil.getHeaderDate(resource
0736: .getDateReleased()));
0737: }
0738: // <expire>
0739: if (resource.getDateExpired() != CmsResource.DATE_EXPIRED_DEFAULT) {
0740: fileElement.addElement(CmsImportVersion7.N_DATEEXPIRED)
0741: .addText(
0742: CmsDateUtil.getHeaderDate(resource
0743: .getDateExpired()));
0744: }
0745: // <flags>
0746: int resFlags = resource.getFlags();
0747: resFlags &= ~CmsResource.FLAG_LABELED;
0748: fileElement.addElement(CmsImportVersion7.N_FLAGS).addText(
0749: Integer.toString(resFlags));
0750:
0751: // write the properties to the manifest
0752: Element propertiesElement = fileElement
0753: .addElement(CmsImportVersion7.N_PROPERTIES);
0754: List properties = getCms().readPropertyObjects(
0755: getCms().getSitePath(resource), false);
0756: // sort the properties for a well defined output order
0757: Collections.sort(properties);
0758: for (int i = 0, n = properties.size(); i < n; i++) {
0759: CmsProperty property = (CmsProperty) properties.get(i);
0760: if (isIgnoredProperty(property)) {
0761: continue;
0762: }
0763: addPropertyNode(propertiesElement, property.getName(),
0764: property.getStructureValue(), false);
0765: addPropertyNode(propertiesElement, property.getName(),
0766: property.getResourceValue(), true);
0767: }
0768:
0769: // Write the relations to the manifest
0770: List relations = getCms().getRelationsForResource(
0771: getCms().getSitePath(resource),
0772: CmsRelationFilter.TARGETS
0773: .filterNotDefinedInContent());
0774: CmsRelation relation = null;
0775: Element relationsElement = fileElement
0776: .addElement(CmsImportVersion7.N_RELATIONS);
0777: // iterate over the relations
0778: for (Iterator iter = relations.iterator(); iter.hasNext();) {
0779: relation = (CmsRelation) iter.next();
0780: CmsResource target = relation.getTarget(getCms(),
0781: CmsResourceFilter.ALL);
0782: String structureId = target.getStructureId().toString();
0783: String sitePath = getCms().getSitePath(target);
0784: String relationType = relation.getType().getName();
0785:
0786: addRelationNode(relationsElement, structureId,
0787: sitePath, relationType);
0788: }
0789:
0790: // append the nodes for access control entries
0791: Element acl = fileElement
0792: .addElement(CmsImportVersion7.N_ACCESSCONTROL_ENTRIES);
0793:
0794: // read the access control entries
0795: List fileAcEntries = getCms().getAccessControlEntries(
0796: getCms().getSitePath(resource), false);
0797: Iterator i = fileAcEntries.iterator();
0798:
0799: // create xml elements for each access control entry
0800: while (i.hasNext()) {
0801: CmsAccessControlEntry ace = (CmsAccessControlEntry) i
0802: .next();
0803: Element a = acl
0804: .addElement(CmsImportVersion7.N_ACCESSCONTROL_ENTRY);
0805:
0806: // now check if the principal is a group or a user
0807: int flags = ace.getFlags();
0808: String acePrincipalName = "";
0809: CmsUUID acePrincipal = ace.getPrincipal();
0810: if ((flags & CmsAccessControlEntry.ACCESS_FLAGS_ALLOTHERS) > 0) {
0811: acePrincipalName = CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_NAME;
0812: } else if ((flags & CmsAccessControlEntry.ACCESS_FLAGS_OVERWRITE_ALL) > 0) {
0813: acePrincipalName = CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_NAME;
0814: } else if ((flags & CmsAccessControlEntry.ACCESS_FLAGS_GROUP) > 0) {
0815: // the principal is a group
0816: acePrincipalName = getCms().readGroup(acePrincipal)
0817: .getPrefixedName();
0818: } else if ((flags & CmsAccessControlEntry.ACCESS_FLAGS_USER) > 0) {
0819: // the principal is a user
0820: acePrincipalName = getCms().readUser(acePrincipal)
0821: .getPrefixedName();
0822: } else {
0823: // the principal is a role
0824: acePrincipalName = CmsRole.PRINCIPAL_ROLE
0825: + "."
0826: + CmsRole.valueOfId(acePrincipal)
0827: .getRoleName();
0828: }
0829:
0830: a.addElement(
0831: CmsImportVersion7.N_ACCESSCONTROL_PRINCIPAL)
0832: .addText(acePrincipalName);
0833: a.addElement(CmsImportVersion7.N_FLAGS).addText(
0834: Integer.toString(flags));
0835:
0836: Element b = a
0837: .addElement(CmsImportVersion7.N_ACCESSCONTROL_PERMISSIONSET);
0838: b
0839: .addElement(
0840: CmsImportVersion7.N_ACCESSCONTROL_ALLOWEDPERMISSIONS)
0841: .addText(
0842: Integer.toString(ace
0843: .getAllowedPermissions()));
0844: b
0845: .addElement(
0846: CmsImportVersion7.N_ACCESSCONTROL_DENIEDPERMISSIONS)
0847: .addText(
0848: Integer.toString(ace
0849: .getDeniedPermissions()));
0850: }
0851:
0852: // write the XML
0853: digestElement(m_resourceNode, fileElement);
0854: } catch (CmsImportExportException e) {
0855:
0856: throw e;
0857: } catch (CmsException e) {
0858:
0859: CmsMessageContainer message = Messages
0860: .get()
0861: .container(
0862: Messages.ERR_IMPORTEXPORT_ERROR_APPENDING_RESOURCE_TO_MANIFEST_1,
0863: resource.getRootPath());
0864: if (LOG.isDebugEnabled()) {
0865: LOG.debug(message.key(), e);
0866: }
0867:
0868: throw new CmsImportExportException(message, e);
0869: }
0870: }
0871:
0872: /**
0873: * Returns true if the checked resource name can be exported depending on the include settings.<p>
0874: *
0875: * @param resourcename the absolute path of the resource
0876: * @return true if the checked resource name can be exported depending on the include settings
0877: */
0878: protected boolean checkExportResource(String resourcename) {
0879:
0880: return (// other folder than "/system/" will be exported
0881: !resourcename.startsWith(CmsWorkplace.VFS_PATH_SYSTEM) // OR always export "/system/"
0882: || resourcename
0883: .equalsIgnoreCase(CmsWorkplace.VFS_PATH_SYSTEM) // OR always export "/system/galleries/"
0884: || resourcename
0885: .startsWith(CmsWorkplace.VFS_PATH_GALLERIES) // OR option "include system folder" selected
0886: || (m_parameters.isIncludeSystemFolder() // AND export folder is a system folder
0887: && resourcename.startsWith(CmsWorkplace.VFS_PATH_SYSTEM)));
0888: }
0889:
0890: /**
0891: * Closes the export ZIP file and saves the XML document for the manifest.<p>
0892: *
0893: * @param exportNode the export root node
0894: *
0895: * @throws SAXException if something goes wrong processing the manifest.xml
0896: * @throws IOException if something goes wrong while closing the export file
0897: */
0898: protected void closeExportFile(Element exportNode)
0899: throws IOException, SAXException {
0900:
0901: // close the <export> Tag
0902: getSaxWriter().writeClose(exportNode);
0903:
0904: // close the XML document
0905: CmsXmlSaxWriter xmlSaxWriter = (CmsXmlSaxWriter) getSaxWriter()
0906: .getContentHandler();
0907: xmlSaxWriter.endDocument();
0908:
0909: // create zip entry for the manifest XML document
0910: ZipEntry entry = new ZipEntry(
0911: CmsImportExportManager.EXPORT_MANIFEST);
0912: getExportZipStream().putNextEntry(entry);
0913:
0914: // complex substring operation is required to ensure handling for very large export manifest files
0915: StringBuffer result = ((StringWriter) xmlSaxWriter.getWriter())
0916: .getBuffer();
0917: int steps = result.length() / SUB_LENGTH;
0918: int rest = result.length() % SUB_LENGTH;
0919: int pos = 0;
0920: for (int i = 0; i < steps; i++) {
0921: String sub = result.substring(pos, pos + SUB_LENGTH);
0922: getExportZipStream().write(
0923: sub.getBytes(OpenCms.getSystemInfo()
0924: .getDefaultEncoding()));
0925: pos += SUB_LENGTH;
0926: }
0927: if (rest > 0) {
0928: String sub = result.substring(pos, pos + rest);
0929: getExportZipStream().write(
0930: sub.getBytes(OpenCms.getSystemInfo()
0931: .getDefaultEncoding()));
0932: }
0933:
0934: // close the zip entry for the manifest XML document
0935: getExportZipStream().closeEntry();
0936:
0937: // finally close the zip stream
0938: getExportZipStream().close();
0939: }
0940:
0941: /**
0942: * Writes the output element to the XML output writer and detaches it
0943: * from it's parent element.<p>
0944: *
0945: * @param parent the parent element
0946: * @param output the output element
0947: *
0948: * @throws SAXException if something goes wrong processing the manifest.xml
0949: */
0950: protected void digestElement(Element parent, Element output)
0951: throws SAXException {
0952:
0953: m_saxWriter.write(output);
0954: parent.remove(output);
0955: }
0956:
0957: /**
0958: * Exports all resources and possible sub-folders form the provided list of resources.
0959: *
0960: * @param parent the parent node to add the resources to
0961: * @param resourcesToExport the list of resources to export
0962: *
0963: * @throws CmsImportExportException if something goes wrong
0964: * @throws SAXException if something goes wrong processing the manifest.xml
0965: * @throws IOException if not all resources could be appended to the ZIP archive
0966: */
0967: protected void exportAllResources(Element parent,
0968: List resourcesToExport) throws CmsImportExportException,
0969: IOException, SAXException {
0970:
0971: // export all the resources
0972: String resourceNodeName = getResourceNodeName();
0973: m_resourceNode = parent.addElement(resourceNodeName);
0974: getSaxWriter().writeOpen(m_resourceNode);
0975:
0976: if (m_parameters.isRecursive()) {
0977: // remove the possible redundancies in the list of resources
0978: resourcesToExport = CmsFileUtil
0979: .removeRedundancies(resourcesToExport);
0980: }
0981:
0982: // distinguish folder and file names
0983: List folderNames = new ArrayList();
0984: List fileNames = new ArrayList();
0985: Iterator it = resourcesToExport.iterator();
0986: while (it.hasNext()) {
0987: String resource = (String) it.next();
0988: if (CmsResource.isFolder(resource)) {
0989: folderNames.add(resource);
0990: } else {
0991: fileNames.add(resource);
0992: }
0993: }
0994:
0995: m_exportedResources = new HashSet();
0996:
0997: // export the folders
0998: for (int i = 0; i < folderNames.size(); i++) {
0999: String path = (String) folderNames.get(i);
1000: if (m_parameters.isRecursive()) {
1001: // first add super folders to the xml-config file
1002: addParentFolders(path);
1003: addChildResources(path);
1004: } else {
1005: CmsFolder folder;
1006: try {
1007: folder = getCms().readFolder(path,
1008: CmsResourceFilter.IGNORE_EXPIRATION);
1009: } catch (CmsException e) {
1010: CmsMessageContainer message = Messages
1011: .get()
1012: .container(
1013: Messages.ERR_IMPORTEXPORT_ERROR_ADDING_PARENT_FOLDERS_1,
1014: path);
1015: if (LOG.isDebugEnabled()) {
1016: LOG.debug(message.key(), e);
1017: }
1018: throw new CmsImportExportException(message, e);
1019: }
1020: CmsResourceState state = folder.getState();
1021: long age = folder.getDateLastModified() < folder
1022: .getDateCreated() ? folder.getDateCreated()
1023: : folder.getDateLastModified();
1024:
1025: if (getCms().getRequestContext().currentProject()
1026: .isOnlineProject()
1027: || (m_parameters.isIncludeUnchangedResources())
1028: || state.isNew() || state.isChanged()) {
1029: if (!state.isDeleted()
1030: && (age >= m_parameters.getContentAge())) {
1031: // check if this is a system-folder and if it should be included.
1032: String export = getCms().getSitePath(folder);
1033: if (checkExportResource(export)) {
1034: appendResourceToManifest(folder, false);
1035: }
1036: }
1037: }
1038: }
1039: }
1040: // export the files
1041: addFiles(fileNames);
1042:
1043: // write the XML
1044: getSaxWriter().writeClose(m_resourceNode);
1045: parent.remove(m_resourceNode);
1046: m_resourceNode = null;
1047: }
1048:
1049: /**
1050: * Exports one single file with all its data and content.<p>
1051: *
1052: * @param file the file to be exported
1053: *
1054: * @throws CmsImportExportException if something goes wrong
1055: * @throws SAXException if something goes wrong processing the manifest.xml
1056: * @throws IOException if the ZIP entry for the file could be appended to the ZIP archive
1057: */
1058: protected void exportFile(CmsFile file)
1059: throws CmsImportExportException, SAXException, IOException {
1060:
1061: String source = trimResourceName(getCms().getSitePath(file));
1062: I_CmsReport report = getReport();
1063: m_exportCount++;
1064: report
1065: .print(org.opencms.report.Messages.get().container(
1066: org.opencms.report.Messages.RPT_SUCCESSION_1,
1067: String.valueOf(m_exportCount)),
1068: I_CmsReport.FORMAT_NOTE);
1069: report.print(Messages.get().container(Messages.RPT_EXPORT_0),
1070: I_CmsReport.FORMAT_NOTE);
1071: report.print(org.opencms.report.Messages.get().container(
1072: org.opencms.report.Messages.RPT_ARGUMENT_1,
1073: getCms().getSitePath(file)));
1074: report.print(org.opencms.report.Messages.get().container(
1075: org.opencms.report.Messages.RPT_DOTS_0));
1076:
1077: // store content in zip-file
1078: // check if the content of this resource was not already exported
1079: if (!m_exportedResources.contains(file.getResourceId())) {
1080: ZipEntry entry = new ZipEntry(source);
1081: // save the time of the last modification in the zip
1082: entry.setTime(file.getDateLastModified());
1083: getExportZipStream().putNextEntry(entry);
1084: getExportZipStream().write(file.getContents());
1085: getExportZipStream().closeEntry();
1086: // add the resource id to the storage to mark that this resource was already exported
1087: m_exportedResources.add(file.getResourceId());
1088: // create the manifest-entries
1089: appendResourceToManifest(file, true);
1090: } else {
1091: // only create the manifest-entries
1092: appendResourceToManifest(file, false);
1093: }
1094:
1095: if (LOG.isInfoEnabled()) {
1096: LOG.info(Messages.get().getBundle().key(
1097: Messages.LOG_EXPORTING_OK_2,
1098: String.valueOf(m_exportCount), source));
1099: }
1100: report.println(org.opencms.report.Messages.get().container(
1101: org.opencms.report.Messages.RPT_OK_0),
1102: I_CmsReport.FORMAT_OK);
1103: }
1104:
1105: /**
1106: * Exports one single group with all it's data.<p>
1107: *
1108: * @param parent the parent node to add the groups to
1109: * @param group the group to be exported
1110: *
1111: * @throws CmsImportExportException if something goes wrong
1112: * @throws SAXException if something goes wrong processing the manifest.xml
1113: */
1114: protected void exportGroup(Element parent, CmsGroup group)
1115: throws CmsImportExportException, SAXException {
1116:
1117: try {
1118: String parentgroup;
1119: if ((group.getParentId() == null)
1120: || group.getParentId().isNullUUID()) {
1121: parentgroup = "";
1122: } else {
1123: parentgroup = getCms().getParent(group.getName())
1124: .getName();
1125: }
1126:
1127: Element e = parent.addElement(CmsImportVersion7.N_GROUP);
1128: e.addElement(CmsImportVersion7.N_NAME).addText(
1129: group.getSimpleName());
1130: e.addElement(CmsImportVersion7.N_DESCRIPTION).addCDATA(
1131: group.getDescription());
1132: e.addElement(CmsImportVersion7.N_FLAGS).addText(
1133: Integer.toString(group.getFlags()));
1134: e.addElement(CmsImportVersion7.N_PARENTGROUP).addText(
1135: parentgroup);
1136:
1137: // write the XML
1138: digestElement(parent, e);
1139: } catch (CmsException e) {
1140: CmsMessageContainer message = org.opencms.db.Messages
1141: .get()
1142: .container(
1143: org.opencms.db.Messages.ERR_GET_PARENT_GROUP_1,
1144: group.getName());
1145: if (LOG.isDebugEnabled()) {
1146: LOG.debug(message.key(), e);
1147: }
1148:
1149: throw new CmsImportExportException(message, e);
1150: }
1151: }
1152:
1153: /**
1154: * Exports all groups of the given organizational unit.<p>
1155: *
1156: * @param parent the parent node to add the groups to
1157: * @param orgunit the organizational unit to write the groups for
1158: *
1159: * @throws CmsImportExportException if something goes wrong
1160: * @throws SAXException if something goes wrong processing the manifest.xml
1161: */
1162: protected void exportGroups(Element parent,
1163: CmsOrganizationalUnit orgunit)
1164: throws CmsImportExportException, SAXException {
1165:
1166: try {
1167: I_CmsReport report = getReport();
1168: List allGroups = OpenCms.getOrgUnitManager().getGroups(
1169: getCms(), orgunit.getName(), false);
1170: for (int i = 0, l = allGroups.size(); i < l; i++) {
1171: CmsGroup group = (CmsGroup) allGroups.get(i);
1172: report
1173: .print(
1174: org.opencms.report.Messages
1175: .get()
1176: .container(
1177: org.opencms.report.Messages.RPT_SUCCESSION_2,
1178: String.valueOf(i + 1),
1179: String.valueOf(l)),
1180: I_CmsReport.FORMAT_NOTE);
1181: report.print(Messages.get().container(
1182: Messages.RPT_EXPORT_GROUP_0),
1183: I_CmsReport.FORMAT_NOTE);
1184: report
1185: .print(org.opencms.report.Messages
1186: .get()
1187: .container(
1188: org.opencms.report.Messages.RPT_ARGUMENT_1,
1189: group.getName()));
1190: report
1191: .print(org.opencms.report.Messages
1192: .get()
1193: .container(
1194: org.opencms.report.Messages.RPT_DOTS_0));
1195: exportGroup(parent, group);
1196: report.println(
1197: org.opencms.report.Messages.get().container(
1198: org.opencms.report.Messages.RPT_OK_0),
1199: I_CmsReport.FORMAT_OK);
1200: }
1201: } catch (CmsImportExportException e) {
1202: throw e;
1203: } catch (CmsException e) {
1204: if (LOG.isDebugEnabled()) {
1205: LOG.debug(e.getLocalizedMessage(), e);
1206: }
1207: throw new CmsImportExportException(e.getMessageContainer(),
1208: e);
1209: }
1210: }
1211:
1212: /**
1213: * Exports one single organizational unit with all it's data.<p>
1214: *
1215: * @param parent the parent node to add the groups to
1216: * @param orgunit the group to be exported
1217: *
1218: * @throws SAXException if something goes wrong processing the manifest.xml
1219: * @throws CmsException if something goes wrong reading the data to export
1220: */
1221: protected void exportOrgUnit(Element parent,
1222: CmsOrganizationalUnit orgunit) throws SAXException,
1223: CmsException {
1224:
1225: Element orgunitElement = parent
1226: .addElement(CmsImportVersion7.N_ORGUNIT);
1227: getSaxWriter().writeOpen(orgunitElement);
1228:
1229: Element name = orgunitElement.addElement(
1230: CmsImportVersion7.N_NAME).addText(orgunit.getName());
1231: digestElement(orgunitElement, name);
1232:
1233: Element description = orgunitElement.addElement(
1234: CmsImportVersion7.N_DESCRIPTION).addCDATA(
1235: orgunit.getDescription());
1236: digestElement(orgunitElement, description);
1237:
1238: Element flags = orgunitElement.addElement(
1239: CmsImportVersion7.N_FLAGS).addText(
1240: Integer.toString(orgunit.getFlags()));
1241: digestElement(orgunitElement, flags);
1242:
1243: Element resources = orgunitElement
1244: .addElement(CmsImportVersion7.N_RESOURCES);
1245: Iterator it = OpenCms.getOrgUnitManager()
1246: .getResourcesForOrganizationalUnit(getCms(),
1247: orgunit.getName()).iterator();
1248: while (it.hasNext()) {
1249: CmsResource resource = (CmsResource) it.next();
1250: resources.addElement(CmsImportVersion7.N_RESOURCE).addText(
1251: resource.getRootPath());
1252: }
1253: digestElement(orgunitElement, resources);
1254: getReport().println(
1255: org.opencms.report.Messages.get().container(
1256: org.opencms.report.Messages.RPT_OK_0),
1257: I_CmsReport.FORMAT_OK);
1258:
1259: Element groupsElement = parent
1260: .addElement(CmsImportVersion7.N_GROUPS);
1261: getSaxWriter().writeOpen(groupsElement);
1262: exportGroups(groupsElement, orgunit);
1263: getSaxWriter().writeClose(groupsElement);
1264:
1265: Element usersElement = parent
1266: .addElement(CmsImportVersion7.N_USERS);
1267: getSaxWriter().writeOpen(usersElement);
1268: exportUsers(usersElement, orgunit);
1269: getSaxWriter().writeClose(usersElement);
1270:
1271: getSaxWriter().writeClose(orgunitElement);
1272: }
1273:
1274: /**
1275: * Exports all organizational units with all data.<p>
1276: *
1277: * @param parent the parent node to add the organizational units to
1278: *
1279: * @throws CmsImportExportException if something goes wrong
1280: * @throws SAXException if something goes wrong processing the manifest.xml
1281: */
1282: protected void exportOrgUnits(Element parent)
1283: throws CmsImportExportException, SAXException {
1284:
1285: try {
1286: Element orgunitsElement = parent
1287: .addElement(CmsImportVersion7.N_ORGUNITS);
1288: getSaxWriter().writeOpen(orgunitsElement);
1289:
1290: I_CmsReport report = getReport();
1291: List allOUs = new ArrayList();
1292: allOUs.add(OpenCms.getOrgUnitManager()
1293: .readOrganizationalUnit(getCms(), ""));
1294: allOUs.addAll(OpenCms.getOrgUnitManager()
1295: .getOrganizationalUnits(getCms(), "", true));
1296: for (int i = 0; i < allOUs.size(); i++) {
1297: CmsOrganizationalUnit ou = (CmsOrganizationalUnit) allOUs
1298: .get(i);
1299: report
1300: .print(
1301: org.opencms.report.Messages
1302: .get()
1303: .container(
1304: org.opencms.report.Messages.RPT_SUCCESSION_2,
1305: String.valueOf(i + 1),
1306: String.valueOf(allOUs
1307: .size())),
1308: I_CmsReport.FORMAT_NOTE);
1309: report.print(Messages.get().container(
1310: Messages.RPT_EXPORT_ORGUNIT_0),
1311: I_CmsReport.FORMAT_NOTE);
1312: report
1313: .print(org.opencms.report.Messages
1314: .get()
1315: .container(
1316: org.opencms.report.Messages.RPT_ARGUMENT_1,
1317: ou.getName()));
1318: report
1319: .print(org.opencms.report.Messages
1320: .get()
1321: .container(
1322: org.opencms.report.Messages.RPT_DOTS_0));
1323:
1324: exportOrgUnit(orgunitsElement, ou);
1325: }
1326: getSaxWriter().writeClose(orgunitsElement);
1327: } catch (CmsImportExportException e) {
1328: throw e;
1329: } catch (CmsException e) {
1330: if (LOG.isDebugEnabled()) {
1331: LOG.debug(e.getLocalizedMessage(), e);
1332: }
1333: throw new CmsImportExportException(e.getMessageContainer(),
1334: e);
1335: }
1336: }
1337:
1338: /**
1339: * Exports one single project with all it's data.<p>
1340: *
1341: * @param parent the parent node to add the project to
1342: * @param project the project to be exported
1343: *
1344: * @throws CmsImportExportException if something goes wrong
1345: * @throws SAXException if something goes wrong processing the manifest.xml
1346: */
1347: protected void exportProject(Element parent, CmsProject project)
1348: throws CmsImportExportException, SAXException {
1349:
1350: String users;
1351: try {
1352: users = getCms().readGroup(project.getGroupId()).getName();
1353: } catch (CmsException e) {
1354: CmsMessageContainer message = org.opencms.db.Messages
1355: .get()
1356: .container(
1357: org.opencms.db.Messages.ERR_READ_GROUP_FOR_ID_1,
1358: project.getGroupId());
1359: if (LOG.isDebugEnabled()) {
1360: LOG.debug(message.key(), e);
1361: }
1362:
1363: throw new CmsImportExportException(message, e);
1364: }
1365: String managers;
1366: try {
1367: managers = getCms().readGroup(project.getManagerGroupId())
1368: .getName();
1369: } catch (CmsException e) {
1370: CmsMessageContainer message = org.opencms.db.Messages
1371: .get()
1372: .container(
1373: org.opencms.db.Messages.ERR_READ_GROUP_FOR_ID_1,
1374: project.getManagerGroupId());
1375: if (LOG.isDebugEnabled()) {
1376: LOG.debug(message.key(), e);
1377: }
1378:
1379: throw new CmsImportExportException(message, e);
1380: }
1381:
1382: Element e = parent.addElement(CmsImportVersion7.N_PROJECT);
1383: e.addElement(CmsImportVersion7.N_NAME).addText(
1384: project.getSimpleName());
1385: e.addElement(CmsImportVersion7.N_DESCRIPTION).addCDATA(
1386: project.getDescription());
1387: e.addElement(CmsImportVersion7.N_USERSGROUP).addText(users);
1388: e.addElement(CmsImportVersion7.N_MANAGERSGROUP).addText(
1389: managers);
1390:
1391: Element resources = e.addElement(CmsImportVersion7.N_RESOURCES);
1392: try {
1393: Iterator it = getCms().readProjectResources(project)
1394: .iterator();
1395: while (it.hasNext()) {
1396: String resName = (String) it.next();
1397: resources.addElement(CmsImportVersion7.N_RESOURCE)
1398: .addText(resName);
1399: }
1400: } catch (CmsException exc) {
1401: CmsMessageContainer message = org.opencms.db.Messages
1402: .get()
1403: .container(
1404: org.opencms.db.Messages.ERR_READ_PROJECT_RESOURCES_2,
1405: project.getName(), project.getUuid());
1406: if (LOG.isDebugEnabled()) {
1407: LOG.debug(message.key(), exc);
1408: }
1409:
1410: throw new CmsImportExportException(message, exc);
1411: }
1412: // write the XML
1413: digestElement(parent, e);
1414: }
1415:
1416: /**
1417: * Exports all projects with all data.<p>
1418: *
1419: * @param parent the parent node to add the projects to
1420: *
1421: * @throws CmsImportExportException if something goes wrong
1422: * @throws SAXException if something goes wrong processing the manifest.xml
1423: */
1424: protected void exportProjects(Element parent)
1425: throws CmsImportExportException, SAXException {
1426:
1427: try {
1428: I_CmsReport report = getReport();
1429: List allProjects = getCms().getAllManageableProjects();
1430: for (int i = 0; i < allProjects.size(); i++) {
1431: CmsProject project = (CmsProject) allProjects.get(i);
1432: report
1433: .print(
1434: org.opencms.report.Messages
1435: .get()
1436: .container(
1437: org.opencms.report.Messages.RPT_SUCCESSION_2,
1438: String.valueOf(i + 1),
1439: String
1440: .valueOf(allProjects
1441: .size())),
1442: I_CmsReport.FORMAT_NOTE);
1443: report.print(Messages.get().container(
1444: Messages.RPT_EXPORT_PROJECT_0),
1445: I_CmsReport.FORMAT_NOTE);
1446: report
1447: .print(org.opencms.report.Messages
1448: .get()
1449: .container(
1450: org.opencms.report.Messages.RPT_ARGUMENT_1,
1451: project.getName()));
1452: report
1453: .print(org.opencms.report.Messages
1454: .get()
1455: .container(
1456: org.opencms.report.Messages.RPT_DOTS_0));
1457:
1458: exportProject(parent, project);
1459:
1460: report.println(
1461: org.opencms.report.Messages.get().container(
1462: org.opencms.report.Messages.RPT_OK_0),
1463: I_CmsReport.FORMAT_OK);
1464: }
1465: } catch (CmsImportExportException e) {
1466: throw e;
1467: } catch (CmsException e) {
1468: if (LOG.isDebugEnabled()) {
1469: LOG.debug(e.getLocalizedMessage(), e);
1470: }
1471: throw new CmsImportExportException(e.getMessageContainer(),
1472: e);
1473: }
1474: }
1475:
1476: /**
1477: * Exports one single user with all its data.<p>
1478: *
1479: * @param parent the parent node to add the users to
1480: * @param user the user to be exported
1481: *
1482: * @throws CmsImportExportException if something goes wrong
1483: * @throws SAXException if something goes wrong processing the manifest.xml
1484: */
1485: protected void exportUser(Element parent, CmsUser user)
1486: throws CmsImportExportException, SAXException {
1487:
1488: try {
1489: // add user node to the manifest.xml
1490: Element e = parent.addElement(CmsImportVersion7.N_USER);
1491: e.addElement(CmsImportVersion7.N_NAME).addText(
1492: user.getSimpleName());
1493: // encode the password, using a base 64 decoder
1494: String passwd = new String(Base64.encodeBase64(user
1495: .getPassword().getBytes()));
1496: e.addElement(CmsImportVersion7.N_PASSWORD).addCDATA(passwd);
1497: e.addElement(CmsImportVersion7.N_FIRSTNAME).addText(
1498: user.getFirstname());
1499: e.addElement(CmsImportVersion7.N_LASTNAME).addText(
1500: user.getLastname());
1501: e.addElement(CmsImportVersion7.N_EMAIL).addText(
1502: user.getEmail());
1503: e.addElement(CmsImportVersion7.N_FLAGS).addText(
1504: Integer.toString(user.getFlags()));
1505: e.addElement(CmsImportVersion7.N_DATECREATED).addText(
1506: Long.toString(user.getDateCreated()));
1507:
1508: Element userInfoNode = e
1509: .addElement(CmsImportVersion7.N_USERINFO);
1510: List keys = new ArrayList(user.getAdditionalInfo().keySet());
1511: Collections.sort(keys);
1512: Iterator itInfoKeys = keys.iterator();
1513: while (itInfoKeys.hasNext()) {
1514: String key = (String) itInfoKeys.next();
1515: if (key == null) {
1516: continue;
1517: }
1518: Object value = user.getAdditionalInfo(key);
1519: if (value == null) {
1520: continue;
1521: }
1522: Element entryNode = userInfoNode
1523: .addElement(CmsImportVersion7.N_USERINFO_ENTRY);
1524: entryNode.addAttribute(CmsImportVersion7.A_NAME, key);
1525: entryNode.addAttribute(CmsImportVersion7.A_TYPE, value
1526: .getClass().getName());
1527: try {
1528: // serialize the user info and write it into a file
1529: entryNode.addCDATA(CmsDataTypeUtil
1530: .dataExport(value));
1531: } catch (IOException ioe) {
1532: getReport().println(ioe);
1533: if (LOG.isErrorEnabled()) {
1534: LOG
1535: .error(
1536: Messages
1537: .get()
1538: .getBundle()
1539: .key(
1540: Messages.ERR_IMPORTEXPORT_ERROR_EXPORTING_USER_1,
1541: user.getName()),
1542: ioe);
1543: }
1544: }
1545: }
1546:
1547: // append node for roles of user
1548: Element userRoles = e
1549: .addElement(CmsImportVersion7.N_USERROLES);
1550: List roles = OpenCms.getRoleManager().getRolesOfUser(
1551: getCms(), user.getName(), "", true, true, true);
1552: for (int i = 0; i < roles.size(); i++) {
1553: String roleName = ((CmsRole) roles.get(i)).getFqn();
1554: userRoles.addElement(CmsImportVersion7.N_USERROLE)
1555: .addText(roleName);
1556: }
1557: // append the node for groups of user
1558: Element userGroups = e
1559: .addElement(CmsImportVersion7.N_USERGROUPS);
1560: List groups = getCms().getGroupsOfUser(user.getName(),
1561: true, true);
1562: for (int i = 0; i < groups.size(); i++) {
1563: String groupName = ((CmsGroup) groups.get(i)).getName();
1564: userGroups.addElement(CmsImportVersion7.N_USERGROUP)
1565: .addText(groupName);
1566: }
1567: // write the XML
1568: digestElement(parent, e);
1569: } catch (CmsException e) {
1570: if (LOG.isDebugEnabled()) {
1571: LOG.debug(e.getLocalizedMessage(), e);
1572: }
1573: throw new CmsImportExportException(e.getMessageContainer(),
1574: e);
1575: }
1576: }
1577:
1578: /**
1579: * Exports all users of the given organizational unit.<p>
1580: *
1581: * @param parent the parent node to add the users to
1582: * @param orgunit the organizational unit to write the groups for
1583: *
1584: * @throws CmsImportExportException if something goes wrong
1585: * @throws SAXException if something goes wrong processing the manifest.xml
1586: */
1587: protected void exportUsers(Element parent,
1588: CmsOrganizationalUnit orgunit)
1589: throws CmsImportExportException, SAXException {
1590:
1591: try {
1592: I_CmsReport report = getReport();
1593: List allUsers = OpenCms.getOrgUnitManager().getUsers(
1594: getCms(), orgunit.getName(), false);
1595: for (int i = 0, l = allUsers.size(); i < l; i++) {
1596: CmsUser user = (CmsUser) allUsers.get(i);
1597: report
1598: .print(
1599: org.opencms.report.Messages
1600: .get()
1601: .container(
1602: org.opencms.report.Messages.RPT_SUCCESSION_2,
1603: String.valueOf(i + 1),
1604: String.valueOf(l)),
1605: I_CmsReport.FORMAT_NOTE);
1606: report.print(Messages.get().container(
1607: Messages.RPT_EXPORT_USER_0),
1608: I_CmsReport.FORMAT_NOTE);
1609: report
1610: .print(org.opencms.report.Messages
1611: .get()
1612: .container(
1613: org.opencms.report.Messages.RPT_ARGUMENT_1,
1614: user.getName()));
1615: report
1616: .print(org.opencms.report.Messages
1617: .get()
1618: .container(
1619: org.opencms.report.Messages.RPT_DOTS_0));
1620: exportUser(parent, user);
1621: report.println(
1622: org.opencms.report.Messages.get().container(
1623: org.opencms.report.Messages.RPT_OK_0),
1624: I_CmsReport.FORMAT_OK);
1625: }
1626: } catch (CmsImportExportException e) {
1627: throw e;
1628: } catch (CmsException e) {
1629: if (LOG.isDebugEnabled()) {
1630: LOG.debug(e.getLocalizedMessage(), e);
1631: }
1632: throw new CmsImportExportException(e.getMessageContainer(),
1633: e);
1634: }
1635: }
1636:
1637: /**
1638: * Returns the OpenCms context object this export was initialized with.<p>
1639: *
1640: * @return the OpenCms context object this export was initialized with
1641: */
1642: protected CmsObject getCms() {
1643:
1644: return m_cms;
1645: }
1646:
1647: /**
1648: * Returns the name of the export file.<p>
1649: *
1650: * @return the name of the export file
1651: */
1652: protected String getExportFileName() {
1653:
1654: return m_parameters.getPath();
1655: }
1656:
1657: /**
1658: * Returns the name of the main export node.<p>
1659: *
1660: * @return the name of the main export node
1661: */
1662: protected String getExportNodeName() {
1663:
1664: return CmsImportExportManager.N_EXPORT;
1665: }
1666:
1667: /**
1668: * Returns the zip output stream to write to.<p>
1669: *
1670: * @return the zip output stream to write to
1671: */
1672: protected ZipOutputStream getExportZipStream() {
1673:
1674: return m_exportZipStream;
1675: }
1676:
1677: /**
1678: * Returns the report to write progress messages to.<p>
1679: *
1680: * @return the report to write progress messages to
1681: */
1682: protected I_CmsReport getReport() {
1683:
1684: return m_report;
1685: }
1686:
1687: /**
1688: * Returns the name for the main resource node.<p>
1689: *
1690: * @return the name for the main resource node
1691: */
1692: protected String getResourceNodeName() {
1693:
1694: return "files";
1695: }
1696:
1697: /**
1698: * Returns the SAX based xml writer to write the XML output to.<p>
1699: *
1700: * @return the SAX based xml writer to write the XML output to
1701: */
1702: protected SAXWriter getSaxWriter() {
1703:
1704: return m_saxWriter;
1705: }
1706:
1707: /**
1708: * Checks if a property should be written to the export or not.<p>
1709: *
1710: * @param property the property to check
1711: *
1712: * @return if true, the property is to be ignored, otherwise it should be exported
1713: */
1714: protected boolean isIgnoredProperty(CmsProperty property) {
1715:
1716: if (property == null) {
1717: return true;
1718: }
1719: // default implementation is to export all properties not null
1720: return false;
1721: }
1722:
1723: /**
1724: * Checks if a resource is belongs to the correct project for exporting.<p>
1725: *
1726: * @param res the resource to check
1727: *
1728: * @return <code>true</code>, if the resource can be exported, false otherwise
1729: */
1730: protected boolean isInExportableProject(CmsResource res) {
1731:
1732: boolean retValue = true;
1733: // the "only modified in current project flag" is checked
1734: if (m_parameters.isInProject()) {
1735: // resource state is new or changed
1736: if ((res.getState() == CmsResource.STATE_CHANGED)
1737: || (res.getState() == CmsResource.STATE_NEW)) {
1738: // the resource belongs not to the current project, so it must not be exported
1739: if (!res.getProjectLastModified().equals(
1740: getCms().getRequestContext().currentProject()
1741: .getUuid())) {
1742: retValue = false;
1743: }
1744: } else {
1745: // state is unchanged, so do not export it
1746: retValue = false;
1747: }
1748: }
1749: return retValue;
1750: }
1751:
1752: /**
1753: * Opens the export ZIP file and initializes the internal XML document for the manifest.<p>
1754: *
1755: * @return the node in the XML document where all files are appended to
1756: *
1757: * @throws SAXException if something goes wrong processing the manifest.xml
1758: * @throws IOException if something goes wrong while closing the export file
1759: */
1760: protected Element openExportFile() throws IOException, SAXException {
1761:
1762: // create the export-zipstream
1763: setExportZipStream(new ZipOutputStream(new FileOutputStream(
1764: getExportFileName())));
1765: // generate the SAX XML writer
1766: CmsXmlSaxWriter saxHandler = new CmsXmlSaxWriter(
1767: new StringWriter(4096), OpenCms.getSystemInfo()
1768: .getDefaultEncoding());
1769: saxHandler.setEscapeXml(true);
1770: saxHandler.setEscapeUnknownChars(true);
1771: // initialize the dom4j writer object as member variable
1772: setSaxWriter(new SAXWriter(saxHandler, saxHandler));
1773: // the XML document to write the XMl to
1774: Document doc = DocumentHelper.createDocument();
1775: // start the document
1776: saxHandler.startDocument();
1777:
1778: // set the doctype if needed
1779: if (m_parameters.isXmlValidation()) {
1780: saxHandler.startDTD(getExportNodeName(), null,
1781: CmsConfigurationManager.DEFAULT_DTD_PREFIX
1782: + CmsImportVersion7.DTD_FILENAME);
1783: saxHandler.endDTD();
1784: }
1785:
1786: // the node in the XML document where the file entries are appended to
1787: String exportNodeName = getExportNodeName();
1788: // add main export node to XML document
1789: Element exportNode = doc.addElement(exportNodeName);
1790: getSaxWriter().writeOpen(exportNode);
1791:
1792: // add the info element. it contains all infos for this export
1793: Element info = exportNode
1794: .addElement(CmsImportExportManager.N_INFO);
1795: info.addElement(CmsImportExportManager.N_CREATOR).addText(
1796: getCms().getRequestContext().currentUser().getName());
1797: info.addElement(CmsImportExportManager.N_OC_VERSION).addText(
1798: OpenCms.getSystemInfo().getVersionNumber());
1799: info.addElement(CmsImportExportManager.N_DATE).addText(
1800: CmsDateUtil.getHeaderDate(System.currentTimeMillis()));
1801: info.addElement(CmsImportExportManager.N_INFO_PROJECT)
1802: .addText(
1803: getCms().getRequestContext().currentProject()
1804: .getName());
1805: info.addElement(CmsImportExportManager.N_VERSION).addText(
1806: CmsImportExportManager.EXPORT_VERSION);
1807:
1808: // write the XML
1809: digestElement(exportNode, info);
1810:
1811: return exportNode;
1812: }
1813:
1814: /**
1815: * Sets the zip output stream to write to.<p>
1816: *
1817: * @param exportZipStream the zip output stream to write to
1818: */
1819: protected void setExportZipStream(ZipOutputStream exportZipStream) {
1820:
1821: m_exportZipStream = exportZipStream;
1822: }
1823:
1824: /**
1825: * Sets the SAX based xml writer to write the XML output to.<p>
1826: *
1827: * @param saxWriter the SAX based xml writer to write the XML output to
1828: */
1829: protected void setSaxWriter(SAXWriter saxWriter) {
1830:
1831: m_saxWriter = saxWriter;
1832: }
1833:
1834: /**
1835: * Cuts leading and trailing '/' from the given resource name.<p>
1836: *
1837: * @param resourceName the absolute path of a resource
1838: *
1839: * @return the trimmed resource name
1840: */
1841: protected String trimResourceName(String resourceName) {
1842:
1843: if (resourceName.startsWith("/")) {
1844: resourceName = resourceName.substring(1);
1845: }
1846: if (resourceName.endsWith("/")) {
1847: resourceName = resourceName.substring(0, resourceName
1848: .length() - 1);
1849: }
1850: return resourceName;
1851: }
1852: }
|