View Javadoc

1   /**
2    * This file Copyright (c) 2003-2010 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.importexport;
35  
36  import info.magnolia.cms.beans.config.ContentRepository;
37  import info.magnolia.cms.core.Path;
38  import info.magnolia.cms.core.SystemProperty;
39  import org.apache.commons.io.FileUtils;
40  import org.apache.commons.io.filefilter.FileFilterUtils;
41  import org.apache.commons.io.filefilter.IOFileFilter;
42  import org.apache.commons.lang.StringUtils;
43  import org.slf4j.Logger;
44  import org.slf4j.LoggerFactory;
45  
46  import java.io.File;
47  import java.io.IOException;
48  import java.util.Collection;
49  import java.util.Iterator;
50  import java.util.Set;
51  import java.util.SortedSet;
52  import java.util.TreeSet;
53  
54  
55  /**
56   * Bootstrapper: loads content from xml when a magnolia is started with an uninitialized repository.
57   *
58   * @author Fabrizio Giustina
59   * @version $Revision: 32667 $ ($Author: gjoseph $)
60   */
61  public final class Bootstrapper {
62      private static final Logger log = LoggerFactory.getLogger(Bootstrapper.class);
63  
64      /**
65       * Used to process an additional filtering for the bootstrap files
66       *
67       * @author philipp
68       */
69      public interface BootstrapFilter {
70  
71          boolean accept(String filename);
72      }
73  
74      /**
75       * don't instantiate
76       */
77      private Bootstrapper() {
78          // unused
79      }
80  
81      /**
82       * Repositories appears to be empty and the <code>"magnolia.bootstrap.dir</code> directory is configured in
83       * web.xml. Loops over all the repositories and try to load any xml file found in a subdirectory with the same name
84       * of the repository. For example the <code>config</code> repository will be initialized using all the
85       * <code>*.xml</code> files found in <code>"magnolia.bootstrap.dir</code><strong>/config</strong> directory.
86       *
87       * @param bootdirs bootstrap dir
88       */
89      public static void bootstrapRepositories(String[] bootdirs, BootstrapFilter filter) {
90          log.info("Trying to initialize repositories from: \n    {}", StringUtils.join(bootdirs, "\n    "));
91  
92          Iterator repositoryNames = ContentRepository.getAllRepositoryNames();
93          while (repositoryNames.hasNext()) {
94              String repositoryName = (String) repositoryNames.next();
95  
96              if (!bootstrapRepository(bootdirs, repositoryName, filter)) {
97                  // exeption was already logged
98                  break;
99              }
100 
101             log.info("Repository [{}] has been initialized.", repositoryName); //$NON-NLS-1$
102         }
103     }
104 
105     /**
106      * Bootstrap a specific repository.
107      */
108     public static boolean bootstrapRepository(String[] bootdirs, String repositoryName, BootstrapFilter filter) {
109         Set xmlfileset = getBootstrapFiles(bootdirs, repositoryName, filter);
110 
111         if (xmlfileset.isEmpty()) {
112             log.debug("No bootstrap files found for repository [{}], skipping...", repositoryName); //$NON-NLS-1$
113             return true;
114         }
115 
116         log.info("Trying to import content from {} files into repository [{}]", Integer.toString(xmlfileset.size()), repositoryName);
117 
118         final File[] files = (File[]) xmlfileset.toArray(new File[xmlfileset.size()]);
119         return bootstrapFiles(repositoryName, files);
120     }
121 
122     /**
123      * Bootstrap the array of files
124      */
125     private static boolean bootstrapFiles(String repositoryName, File[] files) {
126         try {
127             for (int k = 0; k < files.length; k++) {
128                 File xmlFile = files[k];
129                 log.debug("Importing {}", xmlFile);
130                 DataTransporter.executeBootstrapImport(xmlFile, repositoryName);
131             }
132         }
133         catch (IOException ioe) {
134             log.error(ioe.getMessage(), ioe);
135         }
136         catch (OutOfMemoryError e) {
137             int maxMem = (int) (Runtime.getRuntime().maxMemory() / 1024 / 1024);
138             int needed = Math.max(256, maxMem + 128);
139             log.error("Unable to complete bootstrapping: out of memory.\n" //$NON-NLS-1$
140                     + "{} MB were not enough, try to increase the amount of memory available by adding the -Xmx{}m parameter to the server startup script.\n" //$NON-NLS-1$
141                     + "You will need to completely remove the Magnolia webapp before trying again", //$NON-NLS-1$
142                     Integer.toString(maxMem), Integer.toString(needed));
143             return false;
144         }
145         return true;
146     }
147 
148     /**
149      * Get the files to bootstrap. The method garantees that only one file is imported if it occures twice in the
150      * bootstrap dir. The set is returned sorted, so that the execution fo the import will import the upper most nodes
151      * first. This is done using the filelength.
152      *
153      * @return the sorted set
154      */
155     private static SortedSet getBootstrapFiles(String[] bootdirs, final String repositoryName, final BootstrapFilter filter) {
156         SortedSet xmlfileset = new TreeSet(new BootstrapFilesComparator());
157 
158         for (int j = 0; j < bootdirs.length; j++) {
159             String bootdir = bootdirs[j];
160             File xmldir = new File(bootdir);
161             if (!xmldir.exists() || !xmldir.isDirectory()) {
162                 continue;
163             }
164 
165             Collection files = FileUtils.listFiles(xmldir, new IOFileFilter(){
166                 public boolean accept(File file) {
167                     return accept(file.getParentFile(), file.getName());
168                 }
169                 public boolean accept(File dir, String name) {
170                     return name.startsWith(repositoryName + ".")
171                         && filter.accept(name)
172                         && (name.endsWith(DataTransporter.XML) || name.endsWith(DataTransporter.ZIP) || name
173                             .endsWith(DataTransporter.GZ) || name.endsWith(DataTransporter.PROPERTIES));
174                 }
175             }, FileFilterUtils.trueFileFilter());
176 
177             xmlfileset.addAll(files);
178         }
179 
180         return xmlfileset;
181     }
182 
183     /**
184      * Return the standard bootstrap dirs defined in the magnolia.properies file
185      * @return Array of directory names
186      */
187     public static String[] getBootstrapDirs() {
188         String bootdirProperty = SystemProperty.getProperty(SystemProperty.MAGNOLIA_BOOTSTRAP_ROOTDIR);
189 
190         if (StringUtils.isEmpty(bootdirProperty)) {
191             return new String[0];
192         }
193 
194         String[] bootDirs = StringUtils.split(bootdirProperty);
195 
196         // converts to absolute paths
197         for (int j = 0; j < bootDirs.length; j++) {
198             bootDirs[j] = Path.getAbsoluteFileSystemPath(bootDirs[j]);
199         }
200         return bootDirs;
201     }
202 
203 }