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