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.db; 029 030import org.opencms.file.CmsFile; 031import org.opencms.file.CmsObject; 032import org.opencms.file.CmsProperty; 033import org.opencms.file.CmsPropertyDefinition; 034import org.opencms.file.CmsResource; 035import org.opencms.file.CmsResourceFilter; 036import org.opencms.file.CmsVfsException; 037import org.opencms.file.types.CmsResourceTypeFolder; 038import org.opencms.file.types.CmsResourceTypePlain; 039import org.opencms.main.CmsException; 040import org.opencms.main.OpenCms; 041import org.opencms.security.CmsSecurityException; 042import org.opencms.util.CmsFileUtil; 043 044import java.io.ByteArrayInputStream; 045import java.io.File; 046import java.io.FileInputStream; 047import java.io.IOException; 048import java.util.ArrayList; 049import java.util.List; 050import java.util.StringTokenizer; 051import java.util.zip.ZipEntry; 052import java.util.zip.ZipInputStream; 053 054/** 055 * Allows to import resources from the filesystem or a ZIP file into the OpenCms VFS.<p> 056 * 057 * @since 6.0.0 058 */ 059public class CmsImportFolder { 060 061 /** The OpenCms context object that provides the permissions. */ 062 private CmsObject m_cms; 063 064 /** The names of resources that have been created or replaced during the import. */ 065 private List<CmsResource> m_importedResources = new ArrayList<CmsResource>(); 066 067 /** The name of the import folder to load resources from. */ 068 private String m_importFolderName; 069 070 /** The import path in the OpenCms VFS. */ 071 private String m_importPath; 072 073 /** The resource (folder or ZIP file) to import from in the real file system. */ 074 private File m_importResource; 075 076 /** Will be true if the import resource is a valid ZIP file. */ 077 private boolean m_validZipFile; 078 079 /** The import resource ZIP stream to load resources from. */ 080 private ZipInputStream m_zipStreamIn; 081 082 /** 083 * Default Constructor.<p> 084 */ 085 public CmsImportFolder() { 086 087 // noop 088 } 089 090 /** 091 * Constructor for a new CmsImportFolder that will read from a ZIP file.<p> 092 * 093 * @param content the zip file to import 094 * @param importPath the path to the OpenCms VFS to import to 095 * @param cms a OpenCms context to provide the permissions 096 * @param noSubFolder if <code>true</code> no sub folders will be created, if <code>false</code> the content of the 097 * zip file is created 1:1 inclusive sub folders 098 * 099 * @throws CmsException if something goes wrong 100 */ 101 public CmsImportFolder(byte[] content, String importPath, CmsObject cms, boolean noSubFolder) 102 throws CmsException { 103 104 importZip(content, importPath, cms, noSubFolder); 105 } 106 107 /** 108 * Constructor for a new CmsImportFolder that will read from the real file system.<p> 109 * 110 * @param importFolderName the folder to import 111 * @param importPath the path to the OpenCms VFS to import to 112 * @param cms a OpenCms context to provide the permissions 113 * @throws CmsException if something goes wrong 114 */ 115 public CmsImportFolder(String importFolderName, String importPath, CmsObject cms) 116 throws CmsException { 117 118 importFolder(importFolderName, importPath, cms); 119 } 120 121 /** 122 * Returns the list of imported resources.<p> 123 * 124 * @return the list of imported resources 125 */ 126 public List<CmsResource> getImportedResources() { 127 128 return m_importedResources; 129 } 130 131 /** 132 * Import that will read from the real file system.<p> 133 * 134 * @param importFolderName the folder to import 135 * @param importPath the path to the OpenCms VFS to import to 136 * @param cms a OpenCms context to provide the permissions 137 * @throws CmsException if something goes wrong 138 */ 139 public void importFolder(String importFolderName, String importPath, CmsObject cms) throws CmsException { 140 141 try { 142 m_importedResources = new ArrayList<CmsResource>(); 143 m_importFolderName = importFolderName; 144 m_importPath = importPath; 145 m_cms = cms; 146 // open the import resource 147 getImportResource(); 148 // first lock the destination path 149 m_cms.lockResource(m_importPath); 150 // import the resources 151 if (m_zipStreamIn == null) { 152 importResources(m_importResource, m_importPath); 153 } else { 154 importZipResource(m_zipStreamIn, m_importPath, false); 155 } 156 // all is done, unlock the resources 157 m_cms.unlockResource(m_importPath); 158 } catch (Exception e) { 159 throw new CmsVfsException( 160 Messages.get().container(Messages.ERR_IMPORT_FOLDER_2, importFolderName, importPath), 161 e); 162 } 163 164 } 165 166 /** 167 * Import that will read from a ZIP file.<p> 168 * 169 * @param content the zip file to import 170 * @param importPath the path to the OpenCms VFS to import to 171 * @param cms a OpenCms context to provide the permissions 172 * @param noSubFolder if <code>true</code> no sub folders will be created, if <code>false</code> the content of the 173 * zip file is created 1:1 inclusive sub folders 174 * 175 * @throws CmsException if something goes wrong 176 */ 177 public void importZip(byte[] content, String importPath, CmsObject cms, boolean noSubFolder) throws CmsException { 178 179 m_importPath = importPath; 180 m_cms = cms; 181 try { 182 // open the import resource 183 m_zipStreamIn = new ZipInputStream(new ByteArrayInputStream(content)); 184 m_cms.readFolder(importPath, CmsResourceFilter.IGNORE_EXPIRATION); 185 // import the resources 186 importZipResource(m_zipStreamIn, m_importPath, noSubFolder); 187 } catch (Exception e) { 188 throw new CmsVfsException(Messages.get().container(Messages.ERR_IMPORT_FOLDER_1, importPath), e); 189 } 190 191 } 192 193 /** 194 * Returns true if a valid ZIP file was imported.<p> 195 * 196 * @return true if a valid ZIP file was imported 197 */ 198 public boolean isValidZipFile() { 199 200 return m_validZipFile; 201 } 202 203 /** 204 * Stores the import resource in an Object member variable.<p> 205 * @throws CmsVfsException if the file to import is no valid zipfile 206 */ 207 private void getImportResource() throws CmsVfsException { 208 209 // get the import resource 210 m_importResource = new File(m_importFolderName); 211 // check if this is a folder or a ZIP file 212 if (m_importResource.isFile()) { 213 try { 214 m_zipStreamIn = new ZipInputStream(new FileInputStream(m_importResource)); 215 } catch (IOException e) { 216 // if file but no ZIP file throw an exception 217 throw new CmsVfsException( 218 Messages.get().container(Messages.ERR_NO_ZIPFILE_1, m_importResource.getName()), 219 e); 220 } 221 } 222 } 223 224 /** 225 * Imports the resources from the folder in the real file system to the OpenCms VFS.<p> 226 * 227 * @param folder the folder to import from 228 * @param importPath the OpenCms VFS import path to import to 229 * @throws Exception if something goes wrong during file IO 230 */ 231 private void importResources(File folder, String importPath) throws Exception { 232 233 String[] diskFiles = folder.list(); 234 File currentFile; 235 236 for (int i = 0; i < diskFiles.length; i++) { 237 currentFile = new File(folder, diskFiles[i]); 238 239 if (currentFile.isDirectory()) { 240 // create directory in cms 241 m_importedResources.add( 242 m_cms.createResource(importPath + currentFile.getName(), CmsResourceTypeFolder.RESOURCE_TYPE_ID)); 243 importResources(currentFile, importPath + currentFile.getName() + "/"); 244 } else { 245 // import file into cms 246 int type = OpenCms.getResourceManager().getDefaultTypeForName(currentFile.getName()).getTypeId(); 247 byte[] content = CmsFileUtil.readFile(currentFile); 248 // create the file 249 try { 250 m_importedResources.add( 251 m_cms.createResource(importPath + currentFile.getName(), type, content, null)); 252 } catch (CmsSecurityException e) { 253 // in case of not enough permissions, try to create a plain text file 254 int plainId = OpenCms.getResourceManager().getResourceType( 255 CmsResourceTypePlain.getStaticTypeName()).getTypeId(); 256 m_importedResources.add( 257 m_cms.createResource(importPath + currentFile.getName(), plainId, content, null)); 258 } 259 content = null; 260 } 261 } 262 } 263 264 /** 265 * Imports the resources from a ZIP file in the real file system to the OpenCms VFS.<p> 266 * 267 * @param zipStreamIn the input Stream 268 * @param importPath the path in the vfs 269 * @param noSubFolder if <code>true</code> no sub folders will be created, if <code>false</code> the content of the 270 * zip file is created 1:1 inclusive sub folders 271 * 272 * @throws Exception if something goes wrong during file IO 273 */ 274 private void importZipResource(ZipInputStream zipStreamIn, String importPath, boolean noSubFolder) 275 throws Exception { 276 277 // HACK: this method looks very crude, it should be re-written sometime... 278 279 boolean isFolder = false; 280 int j, r, stop, size; 281 int entries = 0; 282 byte[] buffer = null; 283 boolean resourceExists; 284 285 while (true) { 286 // handle the single entries ... 287 j = 0; 288 stop = 0; 289 // open the entry ... 290 ZipEntry entry = zipStreamIn.getNextEntry(); 291 if (entry == null) { 292 break; 293 } 294 entries++; // count number of entries in zip 295 String actImportPath = importPath; 296 String title = CmsResource.getName(entry.getName()); 297 String filename = m_cms.getRequestContext().getFileTranslator().translateResource(entry.getName()); 298 // separate path in directories an file name ... 299 StringTokenizer st = new StringTokenizer(filename, "/\\"); 300 int count = st.countTokens(); 301 String[] path = new String[count]; 302 303 if (filename.endsWith("\\") || filename.endsWith("/")) { 304 isFolder = true; // last entry is a folder 305 } else { 306 isFolder = false; // last entry is a file 307 } 308 while (st.hasMoreTokens()) { 309 // store the files and folder names in array ... 310 path[j] = st.nextToken(); 311 j++; 312 } 313 stop = isFolder ? path.length : (path.length - 1); 314 315 if (noSubFolder) { 316 stop = 0; 317 } 318 // now write the folders ... 319 for (r = 0; r < stop; r++) { 320 try { 321 CmsResource createdFolder = m_cms.createResource( 322 actImportPath + path[r], 323 CmsResourceTypeFolder.RESOURCE_TYPE_ID); 324 m_importedResources.add(createdFolder); 325 } catch (CmsException e) { 326 // of course some folders did already exist! 327 } 328 actImportPath += path[r]; 329 actImportPath += "/"; 330 } 331 if (!isFolder) { 332 // import file into cms 333 int type = OpenCms.getResourceManager().getDefaultTypeForName(path[path.length - 1]).getTypeId(); 334 size = new Long(entry.getSize()).intValue(); 335 if (size == -1) { 336 buffer = CmsFileUtil.readFully(zipStreamIn, false); 337 } else { 338 buffer = CmsFileUtil.readFully(zipStreamIn, size, false); 339 } 340 filename = actImportPath + path[path.length - 1]; 341 342 try { 343 m_cms.lockResource(filename); 344 m_cms.readResource(filename); 345 resourceExists = true; 346 } catch (CmsException e) { 347 resourceExists = false; 348 } 349 350 int plainId = OpenCms.getResourceManager().getResourceType( 351 CmsResourceTypePlain.getStaticTypeName()).getTypeId(); 352 if (resourceExists) { 353 CmsResource res = m_cms.readResource(filename, CmsResourceFilter.ALL); 354 CmsFile file = m_cms.readFile(res); 355 byte[] contents = file.getContents(); 356 try { 357 m_cms.replaceResource(filename, res.getTypeId(), buffer, new ArrayList<CmsProperty>(0)); 358 m_importedResources.add(res); 359 } catch (CmsSecurityException e) { 360 // in case of not enough permissions, try to create a plain text file 361 m_cms.replaceResource(filename, plainId, buffer, new ArrayList<CmsProperty>(0)); 362 m_importedResources.add(res); 363 } catch (CmsDbSqlException sqlExc) { 364 // SQL error, probably the file is too large for the database settings, restore content 365 file.setContents(contents); 366 m_cms.writeFile(file); 367 throw sqlExc; 368 } 369 } else { 370 String newResName = actImportPath + path[path.length - 1]; 371 if (title.lastIndexOf('.') != -1) { 372 title = title.substring(0, title.lastIndexOf('.')); 373 } 374 List<CmsProperty> properties = new ArrayList<CmsProperty>(1); 375 CmsProperty titleProp = new CmsProperty(); 376 titleProp.setName(CmsPropertyDefinition.PROPERTY_TITLE); 377 if (OpenCms.getWorkplaceManager().isDefaultPropertiesOnStructure()) { 378 titleProp.setStructureValue(title); 379 } else { 380 titleProp.setResourceValue(title); 381 } 382 properties.add(titleProp); 383 try { 384 m_importedResources.add(m_cms.createResource(newResName, type, buffer, properties)); 385 } catch (CmsSecurityException e) { 386 // in case of not enough permissions, try to create a plain text file 387 m_importedResources.add(m_cms.createResource(newResName, plainId, buffer, properties)); 388 } catch (CmsDbSqlException sqlExc) { 389 // SQL error, probably the file is too large for the database settings, delete file 390 m_cms.lockResource(newResName); 391 m_cms.deleteResource(newResName, CmsResource.DELETE_PRESERVE_SIBLINGS); 392 throw sqlExc; 393 } 394 } 395 } 396 397 // close the entry ... 398 zipStreamIn.closeEntry(); 399 } 400 zipStreamIn.close(); 401 if (entries > 0) { 402 // at least one entry, got a valid zip file ... 403 m_validZipFile = true; 404 } 405 } 406}