/**
* This file Copyright (c) 2003-2012 Magnolia International
* Ltd. (http://www.magnolia-cms.com). All rights reserved.
*
*
* This file is dual-licensed under both the Magnolia
* Network Agreement and the GNU General Public License.
* You may elect to use one or the other of these licenses.
*
* This file is distributed in the hope that it will be
* useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
* Redistribution, except as permitted by whichever of the GPL
* or MNA you select, is prohibited.
*
* 1. For the GPL license (GPL), you can redistribute and/or
* modify this file under the terms of the GNU General
* Public License, Version 3, as published by the Free Software
* Foundation. You should have received a copy of the GNU
* General Public License, Version 3 along with this program;
* if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* 2. For the Magnolia Network Agreement (MNA), this file
* and the accompanying materials are made available under the
* terms of the MNA which accompanies this distribution, and
* is available at http://www.magnolia-cms.com/mna.html
*
* Any modifications to this file must keep this entire header
* intact.
*
*/
package info.magnolia.importexport;
import info.magnolia.cms.beans.config.ContentRepository;
import info.magnolia.cms.core.Path;
import info.magnolia.cms.core.SystemProperty;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Bootstrapper: loads content from xml when a magnolia is started with an uninitialized repository.
*
* @author Fabrizio Giustina
* @version $Revision$ ($Author$)
*/
public final class Bootstrapper {
private static final Logger log = LoggerFactory.getLogger(Bootstrapper.class);
/**
* Filter used to provide an additional filtering for the bootstrap files.
*
* @author philipp
*/
public interface BootstrapFilter {
boolean accept(String filename);
}
private Bootstrapper() {
// unused
}
/**
* Repositories appears to be empty and the <code>"magnolia.bootstrap.dir</code> directory is configured in
* web.xml. Loops over all the repositories and try to load any xml file found in a subdirectory with the same name
* of the repository. For example the <code>config</code> repository will be initialized using all the
* <code>*.xml</code> files found in <code>"magnolia.bootstrap.dir</code><strong>/config</strong> directory.
*
* @param bootdirs bootstrap dir
*/
public static void bootstrapRepositories(String[] bootdirs, BootstrapFilter filter) {
log.info("Trying to initialize repositories from: \n {}", StringUtils.join(bootdirs, "\n "));
Iterator repositoryNames = ContentRepository.getAllRepositoryNames();
while (repositoryNames.hasNext()) {
String repositoryName = (String) repositoryNames.next();
if (!bootstrapRepository(bootdirs, repositoryName, filter)) {
// exeption was already logged
break;
}
log.info("Repository [{}] has been initialized.", repositoryName);
}
}
/**
* Bootstrap a specific repository.
*/
public static boolean bootstrapRepository(String[] bootdirs, String repositoryName, BootstrapFilter filter) {
Set<File> xmlfileset = getBootstrapFiles(bootdirs, repositoryName, filter);
if (xmlfileset.isEmpty()) {
log.debug("No bootstrap files found for repository [{}], skipping...", repositoryName);
return true;
}
log.info("Trying to import content from {} files into repository [{}]", Integer.toString(xmlfileset.size()), repositoryName);
final File[] files = xmlfileset.toArray(new File[xmlfileset.size()]);
return bootstrapFiles(repositoryName, files);
}
/**
* Bootstrap the array of files.
*/
private static boolean bootstrapFiles(String repositoryName, File[] files) {
try {
for (int k = 0; k < files.length; k++) {
File xmlFile = files[k];
log.debug("Importing {}", xmlFile);
DataTransporter.executeBootstrapImport(xmlFile, repositoryName);
}
}
catch (IOException ioe) {
log.error(ioe.getMessage(), ioe);
}
catch (OutOfMemoryError e) {
int maxMem = (int) (Runtime.getRuntime().maxMemory() / 1024 / 1024);
int needed = Math.max(256, maxMem + 128);
log.error("Unable to complete bootstrapping: out of memory.\n"
+ "{} MB were not enough, try to increase the amount of memory available by adding the -Xmx{}m parameter to the server startup script.\n"
+ "You will need to completely remove the Magnolia webapp before trying again",
Integer.toString(maxMem), Integer.toString(needed));
return false;
}
return true;
}
/**
* Get the files to bootstrap. The method garantees that only one file is imported if it occures twice in the
* bootstrap dir. The set is returned sorted, so that the execution fo the import will import the upper most nodes
* first. This is done using the filelength.
*
* @return the sorted set
*/
private static SortedSet<File> getBootstrapFiles(String[] bootdirs, final String repositoryName, final BootstrapFilter filter) {
SortedSet<File> xmlfileset = new TreeSet<File>(new BootstrapFilesComparator());
for (int j = 0; j < bootdirs.length; j++) {
String bootdir = bootdirs[j];
File xmldir = new File(bootdir);
if (!xmldir.exists() || !xmldir.isDirectory()) {
continue;
}
@SuppressWarnings("unchecked")
Collection<File> files = FileUtils.listFiles(xmldir, new IOFileFilter() {
@Override
public boolean accept(File file) {
return accept(file.getParentFile(), file.getName());
}
@Override
public boolean accept(File dir, String name) {
return name.startsWith(repositoryName + ".")
&& filter.accept(name)
&& (name.endsWith(DataTransporter.XML) || name.endsWith(DataTransporter.ZIP) || name
.endsWith(DataTransporter.GZ) || name.endsWith(DataTransporter.PROPERTIES));
}
}, FileFilterUtils.trueFileFilter());
xmlfileset.addAll(files);
}
return xmlfileset;
}
/**
* Return the standard bootstrap dirs defined in the <code>magnolia.properties</code> file.
* @return Array of directory names
*/
public static String[] getBootstrapDirs() {
String bootdirProperty = SystemProperty.getProperty(SystemProperty.MAGNOLIA_BOOTSTRAP_ROOTDIR);
if (StringUtils.isEmpty(bootdirProperty)) {
return new String[0];
}
String[] bootDirs = StringUtils.split(bootdirProperty);
// converts to absolute paths
for (int j = 0; j < bootDirs.length; j++) {
bootDirs[j] = Path.getAbsoluteFileSystemPath(bootDirs[j]);
}
return bootDirs;
}
}