001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.importexport; 029 030import org.opencms.configuration.CmsParameterConfiguration; 031import org.opencms.file.CmsFile; 032import org.opencms.file.CmsFolder; 033import org.opencms.file.CmsObject; 034import org.opencms.file.CmsProperty; 035import org.opencms.file.CmsPropertyDefinition; 036import org.opencms.file.CmsResource; 037import org.opencms.file.CmsResourceFilter; 038import org.opencms.file.types.CmsResourceTypeFolder; 039import org.opencms.file.types.CmsResourceTypePlain; 040import org.opencms.file.types.CmsResourceTypeXmlPage; 041import org.opencms.file.types.I_CmsResourceType; 042import org.opencms.i18n.CmsMessageContainer; 043import org.opencms.lock.CmsLockException; 044import org.opencms.main.CmsException; 045import org.opencms.main.CmsLog; 046import org.opencms.main.OpenCms; 047import org.opencms.report.I_CmsReport; 048import org.opencms.security.CmsAccessControlEntry; 049import org.opencms.security.CmsRole; 050import org.opencms.security.I_CmsPasswordHandler; 051import org.opencms.util.CmsStringUtil; 052import org.opencms.util.CmsUUID; 053import org.opencms.xml.CmsXmlException; 054import org.opencms.xml.CmsXmlUtils; 055import org.opencms.xml.page.CmsXmlPage; 056 057import java.io.File; 058import java.io.IOException; 059import java.util.ArrayList; 060import java.util.Collections; 061import java.util.HashMap; 062import java.util.Iterator; 063import java.util.List; 064import java.util.Map; 065import java.util.Map.Entry; 066import java.util.StringTokenizer; 067import java.util.zip.ZipFile; 068 069import org.apache.commons.logging.Log; 070 071import org.dom4j.Document; 072import org.dom4j.Element; 073import org.dom4j.Node; 074 075/** 076 * Implementation of the OpenCms Import Interface ({@link org.opencms.importexport.I_CmsImport}) for 077 * the import version 2.<p> 078 * 079 * This import format was used in OpenCms 5.0.0 - 5.1.2.<p> 080 * 081 * @since 6.0.0 082 * 083 * @see org.opencms.importexport.A_CmsImport 084 * 085 * @deprecated this import class is no longer in use and should only be used to import old export files 086 */ 087@Deprecated 088public class CmsImportVersion2 extends A_CmsImport { 089 090 /** Parameter for content body folder. */ 091 public static final String VFS_PATH_BODIES = "/system/bodies/"; 092 093 /** The runtime property name for old webapp names. */ 094 private static final String COMPATIBILITY_WEBAPPNAMES = "compatibility.support.webAppNames"; 095 096 /** The version number of this import implementation. */ 097 private static final int IMPORT_VERSION = 2; 098 099 /** The log object for this class. */ 100 private static final Log LOG = CmsLog.getLog(CmsImportVersion2.class); 101 102 /** Web application names for conversion support. */ 103 protected List<String> m_webAppNames; 104 105 /** Old webapp URL for import conversion. */ 106 protected String m_webappUrl; 107 108 /** folder storage for page file and body conversion. */ 109 private List<String> m_folderStorage; 110 111 /** page file storage for page file and body co.version. */ 112 private List<String> m_pageStorage; 113 114 /** 115 * Translates directory Strings from OpenCms 4.x structure to new 5.0 structure.<p> 116 * 117 * @param content the filecontent 118 * @param rules the translation rules 119 * @return String the manipulated file content 120 */ 121 public static String setDirectories(String content, String[] rules) { 122 123 // get translation rules 124 for (int i = 0; i < rules.length; i++) { 125 String actRule = rules[i]; 126 // cut String "/default/vfs/" from rule 127 actRule = CmsStringUtil.substitute(actRule, "/default/vfs", ""); 128 // divide rule into search and replace parts and delete regular expressions 129 StringTokenizer ruleT = new StringTokenizer(actRule, "#"); 130 ruleT.nextToken(); 131 String search = ruleT.nextToken(); 132 int pos = search.lastIndexOf("(.*)"); 133 if (pos >= 0) { 134 search = search.substring(0, pos); 135 } 136 String replace = ruleT.nextToken(); 137 if (pos >= 0) { 138 replace = replace.substring(0, replace.lastIndexOf("$1")); 139 } 140 // scan content for paths if the replace String is not present 141 if ((content.indexOf(replace) == -1) && (content.indexOf(search) != -1)) { 142 // ensure subdirectories of the same name are not replaced 143 search = "([}>\"'\\[]\\s*)" + search; 144 replace = "$1" + replace; 145 content = CmsStringUtil.substitutePerl(content, search, replace, "g"); 146 } 147 } 148 return content; 149 } 150 151 /** 152 * @see org.opencms.importexport.I_CmsImport#getVersion() 153 * @return the version number of this import implementation 154 */ 155 public int getVersion() { 156 157 return CmsImportVersion2.IMPORT_VERSION; 158 } 159 160 /** 161 * @see org.opencms.importexport.I_CmsImport#importData(CmsObject, I_CmsReport, CmsImportParameters) 162 */ 163 public void importData(CmsObject cms, I_CmsReport report, CmsImportParameters params) 164 throws CmsImportExportException, CmsXmlException { 165 166 // initialize the import 167 initialize(); 168 m_cms = cms; 169 m_importPath = params.getDestinationPath(); 170 m_report = report; 171 172 m_folderStorage = new ArrayList<String>(); 173 m_pageStorage = new ArrayList<String>(); 174 m_linkStorage = new HashMap<String, String>(); 175 m_linkPropertyStorage = new HashMap<String, List<CmsProperty>>(); 176 177 if (OpenCms.getRunLevel() >= OpenCms.RUNLEVEL_3_SHELL_ACCESS) { 178 OpenCms.getMemoryMonitor().register(this.getClass().getName() + ".m_folderStorage", m_folderStorage); 179 OpenCms.getMemoryMonitor().register(this.getClass().getName() + ".m_pageStorage", m_pageStorage); 180 OpenCms.getMemoryMonitor().register(this.getClass().getName() + ".m_linkStorage", m_linkStorage); 181 OpenCms.getMemoryMonitor().register( 182 this.getClass().getName() + ".m_linkPropertyStorage", 183 m_linkPropertyStorage); 184 } 185 186 CmsImportHelper helper = new CmsImportHelper(params); 187 try { 188 helper.openFile(); 189 m_importResource = helper.getFolder(); 190 m_importZip = helper.getZipFile(); 191 m_docXml = CmsXmlUtils.unmarshalHelper(helper.getFileBytes(CmsImportExportManager.EXPORT_MANIFEST), null); 192 // first import the user information 193 if (OpenCms.getRoleManager().hasRole(m_cms, CmsRole.ACCOUNT_MANAGER)) { 194 importGroups(); 195 importUsers(); 196 } 197 // now import the VFS resources 198 importAllResources(); 199 convertPointerToSiblings(); 200 } catch (IOException e) { 201 CmsMessageContainer msg = Messages.get().container( 202 Messages.ERR_IMPORTEXPORT_ERROR_READING_FILE_1, 203 CmsImportExportManager.EXPORT_MANIFEST); 204 if (LOG.isErrorEnabled()) { 205 LOG.error(msg.key(), e); 206 } 207 throw new CmsImportExportException(msg, e); 208 } finally { 209 helper.closeFile(); 210 cleanUp(); 211 } 212 } 213 214 /** 215 * @see org.opencms.importexport.I_CmsImport#importResources(org.opencms.file.CmsObject, java.lang.String, org.opencms.report.I_CmsReport, java.io.File, java.util.zip.ZipFile, org.dom4j.Document) 216 * 217 * @deprecated use {@link #importData(CmsObject, I_CmsReport, CmsImportParameters)} instead 218 */ 219 @Deprecated 220 public void importResources( 221 CmsObject cms, 222 String importPath, 223 I_CmsReport report, 224 File importResource, 225 ZipFile importZip, 226 Document docXml) 227 throws CmsImportExportException { 228 229 CmsImportParameters params = new CmsImportParameters( 230 importResource != null ? importResource.getAbsolutePath() : importZip.getName(), 231 importPath, 232 true); 233 234 try { 235 importData(cms, report, params); 236 } catch (CmsXmlException e) { 237 throw new CmsImportExportException(e.getMessageContainer(), e); 238 } 239 } 240 241 /** 242 * Cleans up member variables after the import is finished.<p> 243 * 244 * This is required since there is only one instance for 245 * each import version that is kept in memory and reused.<p> 246 */ 247 @Override 248 protected void cleanUp() { 249 250 m_pageStorage = null; 251 m_folderStorage = null; 252 m_webAppNames = null; 253 m_webappUrl = null; 254 super.cleanUp(); 255 } 256 257 /** 258 * Performs all required pre-import steps.<p> 259 * 260 * The content is *NOT* changed in the implementation of this class.<p> 261 * 262 * @param source the source path of the resource 263 * @param destination the destination path of the resource 264 * @param content the content of the resource 265 * @param resType the type of the resource 266 * @return the (prepared) content of the resource 267 */ 268 protected byte[] convertContent(String source, String destination, byte[] content, String resType) { 269 270 // if the import is older than version 3, some additional conversions must be made 271 if (getVersion() < 3) { 272 if ("page".equals(resType)) { 273 // if the imported resource is a page, store its path inside the VFS for later 274 // integration with its body 275 m_pageStorage.add(destination); 276 } else if ("folder".equals(resType)) { 277 // check if the imported resource is a folder. Folders created in the /system/bodies/ folder 278 if (destination.startsWith(VFS_PATH_BODIES.substring(1))) { 279 // must be removed since we do not use body files anymore. 280 m_folderStorage.add(destination); 281 } 282 } 283 } 284 285 return content; 286 } 287 288 /** 289 * Gets the encoding from the <?XML ...> tag if present.<p> 290 * 291 * @param content the file content 292 * @return String the found encoding 293 */ 294 protected String getEncoding(String content) { 295 296 String encoding = content; 297 int index = encoding.toLowerCase().indexOf("encoding=\""); 298 // encoding attribute found, get the value 299 if (index != -1) { 300 encoding = encoding.substring(index + 10); 301 index = encoding.indexOf("\""); 302 if (index != -1) { 303 encoding = encoding.substring(0, index); 304 return encoding.toUpperCase(); 305 } 306 } 307 // no encoding attribute found 308 return ""; 309 } 310 311 /** 312 * @see org.opencms.importexport.A_CmsImport#importUser(String, String, String, String, String, String, long, Map, List) 313 */ 314 @Override 315 protected void importUser( 316 String name, 317 String flags, 318 String password, 319 String firstname, 320 String lastname, 321 String email, 322 long dateCreated, 323 Map<String, Object> userInfo, 324 List<String> userGroups) 325 throws CmsImportExportException { 326 327 boolean convert = false; 328 329 CmsParameterConfiguration config = OpenCms.getPasswordHandler().getConfiguration(); 330 if ((config != null) && config.containsKey(I_CmsPasswordHandler.CONVERT_DIGEST_ENCODING)) { 331 convert = config.getBoolean(I_CmsPasswordHandler.CONVERT_DIGEST_ENCODING, false); 332 } 333 334 if (convert) { 335 password = convertDigestEncoding(password); 336 } 337 338 super.importUser(name, flags, password, firstname, lastname, email, dateCreated, userInfo, userGroups); 339 } 340 341 /** 342 * Initializes all member variables before the import is started.<p> 343 * 344 * This is required since there is only one instance for 345 * each import version that is kept in memory and reused.<p> 346 */ 347 @Override 348 protected void initialize() { 349 350 m_convertToXmlPage = true; 351 m_webAppNames = new ArrayList<String>(); 352 super.initialize(); 353 } 354 355 /** 356 * Sets the right encoding and returns the result.<p> 357 * 358 * @param content the filecontent 359 * @param encoding the encoding to use 360 * @return modified content 361 */ 362 protected String setEncoding(String content, String encoding) { 363 364 if (content.toLowerCase().indexOf("<?xml") == -1) { 365 return content; 366 } else { 367 // XML information present, replace encoding 368 // set the encoding only if it does not exist 369 String xmlTag = content.substring(0, content.indexOf(">") + 1); 370 if (xmlTag.toLowerCase().indexOf("encoding") == -1) { 371 content = content.substring(content.indexOf(">") + 1); 372 content = "<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>" + content; 373 } 374 } 375 return content; 376 } 377 378 /** 379 * Returns the compatibility web app names.<p> 380 * 381 * @return the compatibility web app names 382 */ 383 private List<String> getCompatibilityWebAppNames() { 384 385 List<String> webAppNamesOri = new ArrayList<String>(); 386 387 String configuredWebAppNames = (String)OpenCms.getRuntimeProperty(COMPATIBILITY_WEBAPPNAMES); 388 if ((configuredWebAppNames != null) && (configuredWebAppNames.length() != 0)) { 389 // split the comma separated list of web app names 390 StringTokenizer tokenizer = new StringTokenizer(configuredWebAppNames, ",;"); 391 while (tokenizer.hasMoreTokens()) { 392 webAppNamesOri.add(tokenizer.nextToken()); 393 } 394 } 395 396 List<String> webAppNames = new ArrayList<String>(); 397 for (int i = 0; i < webAppNamesOri.size(); i++) { 398 // remove possible white space 399 String name = webAppNamesOri.get(i).trim(); 400 if (CmsStringUtil.isNotEmpty(name)) { 401 webAppNames.add(name); 402 if (LOG.isInfoEnabled()) { 403 LOG.info( 404 Messages.get().getBundle().key( 405 Messages.INIT_IMPORTEXPORT_OLD_CONTEXT_PATH_2, 406 Integer.toString((i + 1)), 407 name)); 408 } 409 } 410 } 411 412 String key = (webAppNames.size() > 0) 413 ? Messages.INIT_IMPORTEXPORT_OLD_CONTEXT_SUPPORT_ENABLED_0 414 : Messages.INIT_IMPORTEXPORT_OLD_CONTEXT_SUPPORT_DISABLED_0; 415 if (LOG.isInfoEnabled()) { 416 LOG.info(Messages.get().getBundle().key(key)); 417 } 418 419 // add current context to webapp names list 420 if (!webAppNames.contains(OpenCms.getSystemInfo().getOpenCmsContext())) { 421 webAppNames.add(OpenCms.getSystemInfo().getOpenCmsContext()); 422 } 423 424 return webAppNames; 425 } 426 427 /** 428 * Imports the resources and writes them to the cms.<p> 429 * 430 * @throws CmsImportExportException if something goes wrong 431 */ 432 private void importAllResources() throws CmsImportExportException { 433 434 List<Node> fileNodes = null; 435 List<Node> acentryNodes = null; 436 Element currentElement = null, currentEntry = null; 437 String source = null, destination = null, resourceTypeName = null, timestamp = null, uuid = null, 438 uuidresource = null; 439 long lastmodified = 0; 440 int resourceTypeId = CmsResourceTypePlain.getStaticTypeId(); 441 List<CmsProperty> properties = null; 442 boolean old_overwriteCollidingResources = false; 443 try { 444 m_webAppNames = getCompatibilityWebAppNames(); 445 } catch (Exception e) { 446 if (LOG.isDebugEnabled()) { 447 LOG.debug( 448 Messages.get().getBundle().key( 449 Messages.LOG_IMPORTEXPORT_ERROR_GETTING_WEBAPP_COMPATIBILITY_NAMES_0), 450 e); 451 } 452 m_report.println(e); 453 } 454 if (m_webAppNames == null) { 455 m_webAppNames = Collections.EMPTY_LIST; 456 } 457 458 // get the old webapp url from the OpenCms properties 459 m_webappUrl = OpenCms.getImportExportManager().getOldWebAppUrl(); 460 if (m_webappUrl == null) { 461 // use a default value 462 m_webappUrl = "http://localhost:8080/opencms/opencms"; 463 } 464 // cut last "/" from webappUrl if present 465 if (m_webappUrl.endsWith("/")) { 466 m_webappUrl = m_webappUrl.substring(0, m_webappUrl.lastIndexOf("/")); 467 } 468 469 // get list of unwanted properties 470 List<String> deleteProperties = OpenCms.getImportExportManager().getIgnoredProperties(); 471 472 // get list of immutable resources 473 List<String> immutableResources = OpenCms.getImportExportManager().getImmutableResources(); 474 if (immutableResources == null) { 475 immutableResources = Collections.EMPTY_LIST; 476 } 477 if (LOG.isDebugEnabled()) { 478 LOG.debug( 479 Messages.get().getBundle().key( 480 Messages.LOG_IMPORTEXPORT_IMMUTABLE_RESOURCES_SIZE_1, 481 Integer.toString(immutableResources.size()))); 482 } 483 484 // save the value of the boolean flag whether colliding resources should be overwritten 485 old_overwriteCollidingResources = OpenCms.getImportExportManager().overwriteCollidingResources(); 486 487 // force v1 and v2 imports to overwrite colliding resources, because they dont have resource 488 // UUIDs in their manifest anyway 489 OpenCms.getImportExportManager().setOverwriteCollidingResources(true); 490 491 try { 492 // get all file-nodes 493 fileNodes = m_docXml.selectNodes("//" + A_CmsImport.N_FILE); 494 int importSize = fileNodes.size(); 495 496 // walk through all files in manifest 497 for (int i = 0; i < importSize; i++) { 498 499 m_report.print( 500 org.opencms.report.Messages.get().container( 501 org.opencms.report.Messages.RPT_SUCCESSION_2, 502 String.valueOf(i + 1), 503 String.valueOf(importSize)), 504 I_CmsReport.FORMAT_NOTE); 505 currentElement = (Element)fileNodes.get(i); 506 507 // get all information for a file-import 508 source = getChildElementTextValue(currentElement, A_CmsImport.N_SOURCE); 509 destination = getChildElementTextValue(currentElement, A_CmsImport.N_DESTINATION); 510 511 resourceTypeName = getChildElementTextValue(currentElement, A_CmsImport.N_TYPE); 512 if (RESOURCE_TYPE_NEWPAGE_NAME.equals(resourceTypeName)) { 513 resourceTypeId = RESOURCE_TYPE_NEWPAGE_ID; 514 } else if (RESOURCE_TYPE_LEGACY_PAGE_NAME.equals(resourceTypeName)) { 515 // resource with a "legacy" resource type are imported using the "plain" resource 516 // type because you cannot import a resource without having the resource type object 517 resourceTypeId = CmsResourceTypePlain.getStaticTypeId(); 518 } else if (RESOURCE_TYPE_LINK_NAME.equals(resourceTypeName)) { 519 // set resource type of legacy "link" which is converted later 520 resourceTypeId = RESOURCE_TYPE_LINK_ID; 521 } else { 522 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(resourceTypeName); 523 resourceTypeId = type.getTypeId(); 524 } 525 526 uuid = getChildElementTextValue(currentElement, A_CmsImport.N_UUIDSTRUCTURE); 527 uuidresource = getChildElementTextValue(currentElement, A_CmsImport.N_UUIDRESOURCE); 528 529 timestamp = getChildElementTextValue(currentElement, A_CmsImport.N_LASTMODIFIED); 530 if (timestamp != null) { 531 lastmodified = Long.parseLong(timestamp); 532 } else { 533 lastmodified = System.currentTimeMillis(); 534 } 535 536 // if the type is "script" set it to plain 537 if ("script".equals(resourceTypeName)) { 538 resourceTypeName = CmsResourceTypePlain.getStaticTypeName(); 539 } 540 541 if (LOG.isDebugEnabled()) { 542 LOG.debug( 543 Messages.get().getBundle().key( 544 Messages.LOG_IMPORTEXPORT_ORIGINAL_RESOURCE_NAME_1, 545 destination)); 546 } 547 548 String translatedName = m_cms.getRequestContext().addSiteRoot(m_importPath + destination); 549 if (CmsResourceTypeFolder.RESOURCE_TYPE_NAME.equals(resourceTypeName)) { 550 // ensure folders end with a "/" 551 if (!CmsResource.isFolder(translatedName)) { 552 translatedName += "/"; 553 } 554 } 555 556 if (LOG.isDebugEnabled()) { 557 LOG.debug( 558 Messages.get().getBundle().key( 559 Messages.LOG_IMPORTEXPORT_TRANSLATED_RESOURCE_NAME_1, 560 translatedName)); 561 } 562 563 boolean resourceNotImmutable = checkImmutable(translatedName, immutableResources); 564 translatedName = m_cms.getRequestContext().removeSiteRoot(translatedName); 565 if (resourceNotImmutable) { 566 567 // print out the information to the report 568 m_report.print(Messages.get().container(Messages.RPT_IMPORTING_0), I_CmsReport.FORMAT_NOTE); 569 m_report.print( 570 org.opencms.report.Messages.get().container( 571 org.opencms.report.Messages.RPT_ARGUMENT_1, 572 translatedName)); 573 m_report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0)); 574 575 // get all properties 576 properties = readPropertiesFromManifest(currentElement, deleteProperties); 577 578 // import the specified file 579 CmsResource res = importResource( 580 source, 581 destination, 582 uuid, 583 uuidresource, 584 resourceTypeId, 585 resourceTypeName, 586 lastmodified, 587 properties); 588 589 if (res != null) { 590 591 List<CmsAccessControlEntry> aceList = new ArrayList<CmsAccessControlEntry>(); 592 // write all imported access control entries for this file 593 acentryNodes = currentElement.selectNodes("*/" + A_CmsImport.N_ACCESSCONTROL_ENTRY); 594 // collect all access control entries 595 for (int j = 0; j < acentryNodes.size(); j++) { 596 currentEntry = (Element)acentryNodes.get(j); 597 // get the data of the access control entry 598 String id = getChildElementTextValue(currentEntry, A_CmsImport.N_ID); 599 String acflags = getChildElementTextValue(currentEntry, A_CmsImport.N_FLAGS); 600 String allowed = getChildElementTextValue( 601 currentEntry, 602 A_CmsImport.N_ACCESSCONTROL_ALLOWEDPERMISSIONS); 603 String denied = getChildElementTextValue( 604 currentEntry, 605 A_CmsImport.N_ACCESSCONTROL_DENIEDPERMISSIONS); 606 607 // add the entry to the list 608 aceList.add(getImportAccessControlEntry(res, id, allowed, denied, acflags)); 609 } 610 importAccessControlEntries(res, aceList); 611 if (LOG.isInfoEnabled()) { 612 LOG.info( 613 Messages.get().getBundle().key( 614 Messages.LOG_IMPORTING_4, 615 new Object[] { 616 String.valueOf(i + 1), 617 String.valueOf(importSize), 618 translatedName, 619 destination})); 620 } 621 622 } else { 623 // resource import failed, since no CmsResource was created 624 m_report.print(Messages.get().container(Messages.RPT_SKIPPING_0), I_CmsReport.FORMAT_OK); 625 m_report.println( 626 org.opencms.report.Messages.get().container( 627 org.opencms.report.Messages.RPT_ARGUMENT_1, 628 translatedName)); 629 if (LOG.isInfoEnabled()) { 630 LOG.info( 631 Messages.get().getBundle().key( 632 Messages.LOG_SKIPPING_3, 633 String.valueOf(i + 1), 634 String.valueOf(importSize), 635 translatedName)); 636 } 637 } 638 } else { 639 // skip the file import, just print out the information to the report 640 m_report.print(Messages.get().container(Messages.RPT_SKIPPING_0), I_CmsReport.FORMAT_NOTE); 641 m_report.println( 642 org.opencms.report.Messages.get().container( 643 org.opencms.report.Messages.RPT_ARGUMENT_1, 644 translatedName)); 645 646 if (LOG.isInfoEnabled()) { 647 LOG.info( 648 Messages.get().getBundle().key( 649 Messages.LOG_SKIPPING_3, 650 String.valueOf(i + 1), 651 String.valueOf(importSize), 652 translatedName)); 653 } 654 } 655 } 656 657 // now merge the body and page control files. this only has to be done if the import 658 // version is below version 3 659 if ((getVersion() < 3) && m_convertToXmlPage) { 660 mergePageFiles(); 661 removeFolders(); 662 } 663 } catch (Exception e) { 664 m_report.println(e); 665 m_report.addError(e); 666 667 CmsMessageContainer message = Messages.get().container( 668 Messages.ERR_IMPORTEXPORT_ERROR_IMPORTING_RESOURCES_0); 669 if (LOG.isDebugEnabled()) { 670 LOG.debug(message.key(), e); 671 } 672 673 throw new CmsImportExportException(message, e); 674 } finally { 675 // set the flag to overwrite colliding resources back to its original value 676 OpenCms.getImportExportManager().setOverwriteCollidingResources(old_overwriteCollidingResources); 677 } 678 } 679 680 /** 681 * Imports a resource (file or folder) into the cms.<p> 682 * 683 * @param source the path to the source-file 684 * @param destination the path to the destination-file in the cms 685 * @param uuid the structure uuid of the resource 686 * @param uuidresource the resource uuid of the resource 687 * @param resourceTypeId the ID of the file's resource type 688 * @param resourceTypeName the name of the file's resource type 689 * @param lastmodified the timestamp of the file 690 * @param properties a list with properties for this resource 691 * 692 * @return imported resource 693 */ 694 private CmsResource importResource( 695 String source, 696 String destination, 697 String uuid, 698 String uuidresource, 699 int resourceTypeId, 700 String resourceTypeName, 701 long lastmodified, 702 List<CmsProperty> properties) { 703 704 byte[] content = null; 705 CmsResource res = null; 706 String targetName = null; 707 708 try { 709 // get the file content 710 if (source != null) { 711 content = getFileBytes(source); 712 } 713 714 content = convertContent(source, destination, content, resourceTypeName); 715 716 // get all required information to create a CmsResource 717 int size = 0; 718 if (content != null) { 719 size = content.length; 720 } 721 // get the required UUIDs 722 CmsUUID curUser = m_cms.getRequestContext().getCurrentUser().getId(); 723 CmsUUID newUuidstructure = new CmsUUID(); 724 CmsUUID newUuidresource = new CmsUUID(); 725 if (uuid != null) { 726 newUuidstructure = new CmsUUID(uuid); 727 } 728 if (uuidresource != null) { 729 newUuidresource = new CmsUUID(uuidresource); 730 } 731 732 // extract the name of the resource form the destination 733 targetName = destination; 734 if (targetName.endsWith("/")) { 735 targetName = targetName.substring(0, targetName.length() - 1); 736 } 737 738 boolean isFolder = false; 739 try { 740 isFolder = CmsFolder.isFolderType(resourceTypeId); 741 } catch (Throwable t) { 742 // the specified resource type ID might be of an unknown resource type. 743 // as another option, check the content length and resource type name 744 // to determine if the resource is a folder or not. 745 isFolder = ((size == 0) && CmsResourceTypeFolder.RESOURCE_TYPE_NAME.equalsIgnoreCase(resourceTypeName)); 746 } 747 748 // create a new CmsResource 749 CmsResource resource = new CmsResource( 750 newUuidstructure, 751 newUuidresource, 752 targetName, 753 resourceTypeId, 754 isFolder, 755 0, 756 m_cms.getRequestContext().getCurrentProject().getUuid(), 757 CmsResource.STATE_NEW, 758 lastmodified, 759 curUser, 760 lastmodified, 761 curUser, 762 CmsResource.DATE_RELEASED_DEFAULT, 763 CmsResource.DATE_EXPIRED_DEFAULT, 764 1, 765 size, 766 System.currentTimeMillis(), 767 0); 768 769 if (RESOURCE_TYPE_LINK_ID == resourceTypeId) { 770 // store links for later conversion 771 m_report.print(Messages.get().container(Messages.RPT_STORING_LINK_0), I_CmsReport.FORMAT_NOTE); 772 m_linkStorage.put(m_importPath + destination, new String(content)); 773 m_linkPropertyStorage.put(m_importPath + destination, properties); 774 res = resource; 775 } else { 776 // import this resource in the VFS 777 String resName = m_importPath + destination; 778 res = m_cms.importResource(resName, resource, content, properties); 779 try { 780 m_cms.unlockResource(resName); 781 } catch (CmsLockException e) { 782 if (LOG.isDebugEnabled()) { 783 LOG.debug( 784 Messages.get().getBundle().key( 785 Messages.LOG_IMPORTEXPORT_UNABLE_TO_UNLOCK_RESOURCE_1, 786 resName), 787 e); 788 } 789 } 790 } 791 792 m_report.println(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0)); 793 794 } catch (CmsException exc) { 795 CmsMessageContainer message = Messages.get().container( 796 Messages.ERR_IMPORTEXPORT_ERROR_IMPORTING_RESOURCE_1, 797 targetName); 798 if (LOG.isDebugEnabled()) { 799 LOG.debug(message.key(), exc); 800 } 801 // an error while importing the file 802 m_report.println(exc); 803 try { 804 // Sleep some time after an error so that the report output has a chance to keep up 805 Thread.sleep(1000); 806 } catch (Exception e) { 807 // ignore 808 } 809 } 810 return res; 811 } 812 813 /** 814 * Merges a single page.<p> 815 * 816 * @param resourcename the resource name of the page 817 * @throws CmsImportExportException if something goes wrong 818 * @throws CmsXmlException if the page file could not be unmarshalled 819 */ 820 private void mergePageFile(String resourcename) throws CmsXmlException, CmsImportExportException { 821 822 try { 823 824 if (LOG.isDebugEnabled()) { 825 LOG.debug(Messages.get().getBundle().key(Messages.LOG_IMPORTEXPORT_START_MERGING_1, resourcename)); 826 } 827 828 // in OpenCms versions <5 node names have not been case sensitive. thus, nodes are read both in upper 829 // and lower case letters, or have to be tested for equality ignoring upper/lower case... 830 831 // get the header file 832 CmsFile pagefile = m_cms.readFile(resourcename, CmsResourceFilter.ALL); 833 Document contentXml = CmsXmlUtils.unmarshalHelper(pagefile.getContents(), null); 834 835 // get the <masterTemplate> node to check the content. this node contains the name of the template file. 836 String masterTemplateNodeName = "//masterTemplate"; 837 Node masterTemplateNode = contentXml.selectSingleNode(masterTemplateNodeName); 838 if (masterTemplateNode == null) { 839 masterTemplateNode = contentXml.selectSingleNode(masterTemplateNodeName.toLowerCase()); 840 } 841 if (masterTemplateNode == null) { 842 masterTemplateNode = contentXml.selectSingleNode(masterTemplateNodeName.toUpperCase()); 843 } 844 845 // there is only one <masterTemplate> allowed 846 String mastertemplate = null; 847 if (masterTemplateNode != null) { 848 // get the name of the mastertemplate 849 mastertemplate = masterTemplateNode.getText().trim(); 850 } 851 852 // get the <ELEMENTDEF> nodes to check the content. 853 // this node contains the information for the body element. 854 String elementDefNodeName = "//ELEMENTDEF"; 855 Node bodyNode = contentXml.selectSingleNode(elementDefNodeName); 856 if (bodyNode == null) { 857 bodyNode = contentXml.selectSingleNode(elementDefNodeName.toLowerCase()); 858 } 859 860 // there is only one <ELEMENTDEF> allowed 861 if (bodyNode != null) { 862 863 String bodyclass = null; 864 String bodyname = null; 865 Map<String, String> bodyparams = null; 866 867 List<Element> nodes = ((Element)bodyNode).elements(); 868 for (int i = 0, n = nodes.size(); i < n; i++) { 869 870 Node node = nodes.get(i); 871 872 if ("CLASS".equalsIgnoreCase(node.getName())) { 873 bodyclass = node.getText().trim(); 874 } else if ("TEMPLATE".equalsIgnoreCase(node.getName())) { 875 bodyname = node.getText().trim(); 876 if (!bodyname.startsWith("/")) { 877 bodyname = CmsResource.getFolderPath(resourcename) + bodyname; 878 } 879 } else if ("PARAMETER".equalsIgnoreCase(node.getName())) { 880 Element paramElement = (Element)node; 881 if (bodyparams == null) { 882 bodyparams = new HashMap<String, String>(); 883 } 884 bodyparams.put((paramElement.attribute("name")).getText(), paramElement.getTextTrim()); 885 } 886 } 887 888 if ((mastertemplate == null) || (bodyname == null)) { 889 890 CmsMessageContainer message = Messages.get().container( 891 Messages.ERR_IMPORTEXPORT_ERROR_CANNOT_MERGE_PAGE_FILE_3, 892 resourcename, 893 mastertemplate, 894 bodyname); 895 if (LOG.isDebugEnabled()) { 896 LOG.debug(message.key()); 897 } 898 899 throw new CmsImportExportException(message); 900 } 901 902 // lock the resource, so that it can be manipulated 903 m_cms.lockResource(resourcename); 904 905 // get all properties 906 List<CmsProperty> properties = m_cms.readPropertyObjects(resourcename, false); 907 908 // now get the content of the bodyfile and insert it into the control file 909 CmsFile bodyfile = m_cms.readFile(bodyname, CmsResourceFilter.IGNORE_EXPIRATION); 910 911 //get the encoding 912 String encoding = CmsProperty.get( 913 CmsPropertyDefinition.PROPERTY_CONTENT_ENCODING, 914 properties).getValue(); 915 if (encoding == null) { 916 encoding = OpenCms.getSystemInfo().getDefaultEncoding(); 917 } 918 919 if (m_convertToXmlPage) { 920 if (LOG.isDebugEnabled()) { 921 LOG.debug(Messages.get().getBundle().key(Messages.LOG_IMPORTEXPORT_START_CONVERTING_TO_XML_0)); 922 } 923 924 CmsXmlPage xmlPage = CmsXmlPageConverter.convertToXmlPage( 925 m_cms, 926 bodyfile.getContents(), 927 getLocale(resourcename, properties), 928 encoding); 929 930 if (LOG.isDebugEnabled()) { 931 LOG.debug(Messages.get().getBundle().key(Messages.LOG_IMPORTEXPORT_END_CONVERTING_TO_XML_0)); 932 } 933 934 if (xmlPage != null) { 935 pagefile.setContents(xmlPage.marshal()); 936 937 // set the type to xml page 938 pagefile.setType(CmsResourceTypeXmlPage.getStaticTypeId()); 939 } 940 } 941 942 // add the template and other required properties 943 CmsProperty newProperty = new CmsProperty( 944 CmsPropertyDefinition.PROPERTY_TEMPLATE, 945 mastertemplate, 946 null); 947 // property lists must not contain equal properties 948 properties.remove(newProperty); 949 properties.add(newProperty); 950 951 // if set, add the bodyclass as property 952 if (CmsStringUtil.isNotEmpty(bodyclass)) { 953 newProperty = new CmsProperty(CmsPropertyDefinition.PROPERTY_TEMPLATE, mastertemplate, null); 954 newProperty.setAutoCreatePropertyDefinition(true); 955 properties.remove(newProperty); 956 properties.add(newProperty); 957 } 958 // if set, add bodyparams as properties 959 if (bodyparams != null) { 960 for (Iterator<Entry<String, String>> p = bodyparams.entrySet().iterator(); p.hasNext();) { 961 Entry<String, String> entry = p.next(); 962 String key = entry.getKey(); 963 String value = entry.getValue(); 964 newProperty = new CmsProperty(key, value, null); 965 newProperty.setAutoCreatePropertyDefinition(true); 966 properties.remove(newProperty); 967 properties.add(newProperty); 968 } 969 } 970 971 if (LOG.isDebugEnabled()) { 972 LOG.debug(Messages.get().getBundle().key(Messages.LOG_IMPORTEXPORT_START_IMPORTING_XML_PAGE_0)); 973 } 974 975 // now import the resource 976 m_cms.importResource(resourcename, pagefile, pagefile.getContents(), properties); 977 978 // finally delete the old body file, it is not needed anymore 979 m_cms.lockResource(bodyname); 980 m_cms.deleteResource(bodyname, CmsResource.DELETE_PRESERVE_SIBLINGS); 981 982 if (LOG.isDebugEnabled()) { 983 LOG.debug(Messages.get().getBundle().key(Messages.LOG_IMPORTEXPORT_END_IMPORTING_XML_PAGE_0)); 984 } 985 986 m_report.println( 987 org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0), 988 I_CmsReport.FORMAT_OK); 989 990 } else { 991 992 // there are more than one template nodes in this control file 993 // convert the resource into a plain text file 994 // lock the resource, so that it can be manipulated 995 m_cms.lockResource(resourcename); 996 // set the type to plain 997 pagefile.setType(CmsResourceTypePlain.getStaticTypeId()); 998 // write all changes 999 m_cms.writeFile(pagefile); 1000 // done, unlock the resource 1001 m_cms.unlockResource(resourcename); 1002 1003 if (LOG.isDebugEnabled()) { 1004 LOG.debug( 1005 Messages.get().getBundle().key( 1006 Messages.LOG_IMPORTEXPORT_CANNOT_CONVERT_XML_STRUCTURE_1, 1007 resourcename)); 1008 } 1009 1010 m_report.println(Messages.get().container(Messages.RPT_NOT_CONVERTED_0), I_CmsReport.FORMAT_OK); 1011 1012 } 1013 1014 if (LOG.isDebugEnabled()) { 1015 LOG.debug(Messages.get().getBundle().key(Messages.LOG_IMPORTEXPORT_END_MERGING_1, resourcename)); 1016 } 1017 } catch (CmsXmlException e) { 1018 1019 throw e; 1020 } catch (CmsException e) { 1021 1022 m_report.println(e); 1023 1024 CmsMessageContainer message = Messages.get().container( 1025 Messages.ERR_IMPORTEXPORT_ERROR_MERGING_PAGE_FILE_1, 1026 resourcename); 1027 if (LOG.isDebugEnabled()) { 1028 LOG.debug(message.key(), e); 1029 } 1030 1031 throw new CmsImportExportException(message, e); 1032 } 1033 1034 } 1035 1036 /** 1037 * Merges the page control files and their corresponding bodies into a single files.<p> 1038 * 1039 * @throws CmsImportExportException if something goes wrong 1040 * @throws CmsXmlException if the page file could not be unmarshalled 1041 */ 1042 private void mergePageFiles() throws CmsXmlException, CmsImportExportException { 1043 1044 try { 1045 // check if the template property exists. If not, create it. 1046 try { 1047 m_cms.readPropertyDefinition(CmsPropertyDefinition.PROPERTY_TEMPLATE); 1048 } catch (CmsException e) { 1049 // the template propertydefintion does not exist. So create it. 1050 m_cms.createPropertyDefinition(CmsPropertyDefinition.PROPERTY_TEMPLATE); 1051 } 1052 1053 // copy all propertydefinitions of the old page to the new page 1054 List<CmsPropertyDefinition> definitions = m_cms.readAllPropertyDefinitions(); 1055 1056 Iterator<CmsPropertyDefinition> j = definitions.iterator(); 1057 while (j.hasNext()) { 1058 CmsPropertyDefinition definition = j.next(); 1059 // check if this propertydef already exits 1060 try { 1061 m_cms.readPropertyDefinition(definition.getName()); 1062 } catch (Exception e) { 1063 m_cms.createPropertyDefinition(definition.getName()); 1064 } 1065 } 1066 } catch (CmsException e) { 1067 1068 CmsMessageContainer message = Messages.get().container( 1069 Messages.ERR_IMPORTEXPORT_ERROR_COPYING_PROPERTY_DEFINITIONS_0); 1070 if (LOG.isDebugEnabled()) { 1071 LOG.debug(message.key(), e); 1072 } 1073 1074 throw new CmsImportExportException(message); 1075 } 1076 1077 // iterate through the list of all page controlfiles found during the import process 1078 int size = m_pageStorage.size(); 1079 m_report.println(Messages.get().container(Messages.RPT_MERGE_START_0), I_CmsReport.FORMAT_HEADLINE); 1080 Iterator<String> i = m_pageStorage.iterator(); 1081 int counter = 1; 1082 while (i.hasNext()) { 1083 String resname = i.next(); 1084 // adjust the resourcename if nescessary 1085 if (!resname.startsWith("/")) { 1086 resname = "/" + resname; 1087 } 1088 1089 m_report.print( 1090 org.opencms.report.Messages.get().container( 1091 org.opencms.report.Messages.RPT_SUCCESSION_2, 1092 String.valueOf(counter), 1093 String.valueOf(size)), 1094 I_CmsReport.FORMAT_NOTE); 1095 m_report.print(Messages.get().container(Messages.RPT_MERGE_0), I_CmsReport.FORMAT_NOTE); 1096 m_report.print( 1097 org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_ARGUMENT_1, resname)); 1098 1099 mergePageFile(resname); 1100 if (LOG.isInfoEnabled()) { 1101 LOG.info( 1102 Messages.get().getBundle().key( 1103 Messages.LOG_MERGING_3, 1104 String.valueOf(counter), 1105 String.valueOf(size), 1106 resname)); 1107 } 1108 1109 counter++; 1110 1111 } 1112 // free mem 1113 m_pageStorage.clear(); 1114 1115 } 1116 1117 /** 1118 * Deletes the folder structure which has been creating while importing the body files..<p> 1119 * 1120 * @throws CmsImportExportException if something goes wrong 1121 */ 1122 private void removeFolders() throws CmsImportExportException { 1123 1124 try { 1125 1126 int size = m_folderStorage.size(); 1127 1128 m_report.println(Messages.get().container(Messages.RPT_DELFOLDER_START_0), I_CmsReport.FORMAT_HEADLINE); 1129 // iterate though all collected folders. Iteration must start at the end of the list, 1130 // as folders habe to be deleted in the reverse order. 1131 int counter = 1; 1132 for (int j = (size - 1); j >= 0; j--) { 1133 String resname = m_folderStorage.get(j); 1134 resname = (resname.startsWith("/") ? "" : "/") + resname + (resname.endsWith("/") ? "" : "/"); 1135 // now check if the folder is really empty. Only delete empty folders 1136 List<CmsResource> files = m_cms.getFilesInFolder(resname, CmsResourceFilter.IGNORE_EXPIRATION); 1137 1138 if (files.size() == 0) { 1139 List<CmsResource> folders = m_cms.getSubFolders(resname, CmsResourceFilter.IGNORE_EXPIRATION); 1140 if (folders.size() == 0) { 1141 m_report.print( 1142 org.opencms.report.Messages.get().container( 1143 org.opencms.report.Messages.RPT_SUCCESSION_2, 1144 String.valueOf(counter), 1145 String.valueOf(size)), 1146 I_CmsReport.FORMAT_NOTE); 1147 m_report.print(Messages.get().container(Messages.RPT_DELFOLDER_0), I_CmsReport.FORMAT_NOTE); 1148 m_report.print( 1149 org.opencms.report.Messages.get().container( 1150 org.opencms.report.Messages.RPT_ARGUMENT_1, 1151 resname), 1152 I_CmsReport.FORMAT_DEFAULT); 1153 m_cms.lockResource(resname); 1154 m_cms.deleteResource(resname, CmsResource.DELETE_PRESERVE_SIBLINGS); 1155 m_report.println( 1156 org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0), 1157 I_CmsReport.FORMAT_OK); 1158 counter++; 1159 } 1160 } 1161 } 1162 } catch (CmsException e) { 1163 1164 CmsMessageContainer message = Messages.get().container( 1165 Messages.ERR_IMPORTEXPORT_ERROR_REMOVING_FOLDERS_OF_IMPORTED_BODY_FILES_0); 1166 if (LOG.isDebugEnabled()) { 1167 LOG.debug(message.key(), e); 1168 } 1169 1170 throw new CmsImportExportException(message, e); 1171 } 1172 } 1173}