View Javadoc

1   /**
2    * This file Copyright (c) 2003-2011 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.module.admininterface.pages;
35  
36  import info.magnolia.cms.beans.config.ContentRepository;
37  import info.magnolia.cms.core.Content;
38  import info.magnolia.cms.core.HierarchyManager;
39  import info.magnolia.cms.core.ItemType;
40  import info.magnolia.cms.core.Path;
41  import info.magnolia.cms.i18n.MessagesManager;
42  import info.magnolia.cms.security.AccessDeniedException;
43  import info.magnolia.cms.util.AlertUtil;
44  import info.magnolia.cms.util.ContentUtil;
45  import info.magnolia.cms.util.NodeDataUtil;
46  import info.magnolia.context.MgnlContext;
47  import info.magnolia.importexport.DataTransporter;
48  import info.magnolia.module.ModuleRegistry;
49  import info.magnolia.module.admininterface.TemplatedMVCHandler;
50  import info.magnolia.module.files.BasicFileExtractor;
51  import info.magnolia.module.files.FileExtractor;
52  import info.magnolia.module.files.ModuleFileExtractorTransformer;
53  import info.magnolia.repository.RepositoryConstants;
54  
55  import java.io.File;
56  import java.io.FileNotFoundException;
57  import java.io.FileOutputStream;
58  import java.io.IOException;
59  import java.util.HashSet;
60  import java.util.Iterator;
61  import java.util.Set;
62  
63  import javax.jcr.PathNotFoundException;
64  import javax.jcr.RepositoryException;
65  import javax.jcr.Session;
66  import javax.servlet.http.HttpServletRequest;
67  import javax.servlet.http.HttpServletResponse;
68  
69  import org.apache.commons.io.IOUtils;
70  import org.apache.commons.lang.StringUtils;
71  import org.slf4j.Logger;
72  import org.slf4j.LoggerFactory;
73  
74  
75  /**
76   * Utilities that can be used during development.
77   * @author Fabrizio Giustina
78   * @version $Revision: 50687 $ ($Author: dlipp $)
79   */
80  public class DevelopmentUtilsPage extends TemplatedMVCHandler {
81  
82      private boolean templates;
83  
84      private boolean paragraphs;
85  
86      private boolean dialogs;
87  
88      private boolean pages;
89  
90      private boolean website;
91  
92      private boolean users;
93  
94      private boolean groups;
95  
96      private boolean roles;
97  
98      private boolean virtualURIs;
99  
100     private String rootdir;
101 
102     private String parentpath;
103 
104     private String repository;
105 
106     private String module;
107 
108     /**
109      * Logger.
110      */
111     public static Logger log = LoggerFactory.getLogger(DevelopmentUtilsPage.class);
112 
113     /**
114      * @param name
115      * @param request
116      * @param response
117      */
118     public DevelopmentUtilsPage(String name, HttpServletRequest request, HttpServletResponse response) {
119         super(name, request, response);
120 
121         rootdir = StringUtils.defaultIfEmpty(NodeDataUtil.getString(
122             RepositoryConstants.CONFIG,
123             "/modules/adminInterface/config/developmentUtils/exportpath"), "WEB-INF/bootstrap/common");
124         module = StringUtils.defaultIfEmpty(NodeDataUtil.getString(
125             RepositoryConstants.CONFIG,
126             "/modules/adminInterface/config/developmentUtils/module"), "templating");
127     }
128 
129     /**
130      * Getter for <code>templates</code>.
131      * @return Returns the templates.
132      */
133     public boolean isTemplates() {
134         return this.templates;
135     }
136 
137     /**
138      * Getter for <code>paragraphs</code>.
139      * @return Returns the paragraphs.
140      */
141     public boolean isParagraphs() {
142         return this.paragraphs;
143     }
144 
145     /**
146      * Getter for <code>dialogs</code>.
147      * @return Returns the dialogs.
148      */
149     public boolean isDialogs() {
150         return this.dialogs;
151     }
152 
153     /**
154      * Getter for <code>pages</code>.
155      * @return Returns the pages.
156      */
157     public boolean isPages() {
158         return this.pages;
159     }
160 
161     /**
162      * Setter for <code>pages</code>.
163      * @param pages The pages to set.
164      */
165     public void setPages(boolean pages) {
166         this.pages = pages;
167     }
168 
169     /**
170      * Getter for <code>website</code>.
171      * @return Returns the website.
172      */
173     public boolean isWebsite() {
174         return this.website;
175     }
176 
177     /**
178      * Getter for <code>users</code>.
179      * @return Returns the users.
180      */
181     public boolean isUsers() {
182         return this.users;
183     }
184 
185     /**
186      * Getter for <code>groups</code>.
187      * @return Returns the groups.
188      */
189     public boolean isGroups() {
190         return this.groups;
191     }
192 
193     /**
194      * Getter for <code>roles</code>.
195      * @return Returns the roles.
196      */
197     public boolean isRoles() {
198         return this.roles;
199     }
200 
201     /**
202      * Getter for <code>rootdir</code>.
203      * @return Returns the rootdir.
204      */
205     public String getRootdir() {
206         return this.rootdir;
207     }
208 
209     /**
210      * Getter for <code>parentpath</code>.
211      * @return Returns the parentpath.
212      */
213     public String getParentpath() {
214         return this.parentpath;
215     }
216 
217     /**
218      * Getter for <code>repository</code>.
219      * @return Returns the repository.
220      */
221     public String getRepository() {
222         return this.repository;
223     }
224 
225     /**
226      * Setter for <code>dialogs</code>.
227      * @param dialogs The dialogs to set.
228      */
229     public void setDialogs(boolean dialogs) {
230         this.dialogs = dialogs;
231     }
232 
233     /**
234      * Setter for <code>paragraphs</code>.
235      * @param paragraphs The paragraphs to set.
236      */
237     public void setParagraphs(boolean paragraphs) {
238         this.paragraphs = paragraphs;
239     }
240 
241     /**
242      * Setter for <code>templates</code>.
243      * @param templates The templates to set.
244      */
245     public void setTemplates(boolean templates) {
246         this.templates = templates;
247     }
248 
249     /**
250      * Setter for <code>rootdir</code>.
251      * @param rootdir The rootdir to set.
252      */
253     public void setRootdir(String rootdir) {
254         this.rootdir = rootdir;
255     }
256 
257     /**
258      * Setter for <code>website</code>.
259      * @param website The website to set.
260      */
261     public void setWebsite(boolean website) {
262         this.website = website;
263     }
264 
265     /**
266      * Setter for <code>parentpath</code>.
267      * @param parentpath The parentpath to set.
268      */
269     public void setParentpath(String parentpath) {
270         this.parentpath = parentpath;
271     }
272 
273     /**
274      * Setter for <code>groups</code>.
275      * @param groups The groups to set.
276      */
277     public void setGroups(boolean groups) {
278         this.groups = groups;
279     }
280 
281     /**
282      * Setter for <code>roles</code>.
283      * @param roles The roles to set.
284      */
285     public void setRoles(boolean roles) {
286         this.roles = roles;
287     }
288 
289     /**
290      * Setter for <code>users</code>.
291      * @param users The users to set.
292      */
293     public void setUsers(boolean users) {
294         this.users = users;
295     }
296 
297     /**
298      * Getter for <code>module</code>.
299      * @return Returns the module.
300      */
301     public String getModule() {
302         return this.module;
303     }
304 
305     /**
306      * Setter for <code>module</code>.
307      * @param module The module to set.
308      */
309     public void setModule(String module) {
310         this.module = module;
311     }
312 
313     /**
314      * Setter for <code>repository</code>.
315      * @param repository The repository to set.
316      */
317     public void setRepository(String repository) {
318         this.repository = repository;
319     }
320 
321     /**
322      * Getter for <code>virtualURIs</code>.
323      * @return Returns the virtualURIs.
324      */
325     public boolean isVirtualURIs() {
326         return this.virtualURIs;
327     }
328 
329     /**
330      * Setter for <code>virtualURIs</code>.
331      * @param virtualURIs The virtualURIs to set.
332      */
333     public void setVirtualURIs(boolean virtualURIs) {
334         this.virtualURIs = virtualURIs;
335     }
336 
337     public Iterator getRepositories() {
338         return ContentRepository.getAllRepositoryNames();
339     }
340 
341     public Set getModules() {
342         return ModuleRegistry.Factory.getInstance().getModuleNames();
343     }
344 
345     // ---- operations ----
346     public String extractModuleFiles() {
347         final FileExtractor extractor = new BasicFileExtractor();
348         try {
349             extractor.extractFiles(new ModuleFileExtractorTransformer(module));
350             AlertUtil.setMessage("Files extracted");
351         }
352         catch (IOException e) {
353             AlertUtil.setMessage("Could not extract files for module " + module + ": " + e.getMessage(), e);
354         }
355 
356         return this.show();
357     }
358 
359     public String reloadI18nMessages() {
360         try {
361             MessagesManager.getInstance().reload();
362             AlertUtil.setMessage("Messages reloaded.");
363         }
364         catch (Exception e) {
365             e.printStackTrace();
366             AlertUtil.setMessage("Can't reload: " + e.getMessage(), e);
367         }
368 
369         return this.show();
370     }
371 
372     public String backup() {
373         HierarchyManager hm = MgnlContext.getHierarchyManager(RepositoryConstants.CONFIG);
374         Session session = hm.getWorkspace().getSession();
375 
376         try {
377             Content moduleroot = hm.getContent("/modules/" + module);
378             if (templates) {
379                 exportChildren(RepositoryConstants.CONFIG, session, moduleroot, "templates", new ItemType[]{
380                     ItemType.CONTENT,
381                     ItemType.CONTENTNODE}, false);
382             }
383             if (paragraphs) {
384                 exportChildren(RepositoryConstants.CONFIG, session, moduleroot, "paragraphs", new ItemType[]{
385                     ItemType.CONTENT,
386                     ItemType.CONTENTNODE}, false);
387             }
388             if (pages) {
389                 exportChildren(RepositoryConstants.CONFIG, session, moduleroot, "pages", new ItemType[]{
390                     ItemType.CONTENT,
391                     ItemType.CONTENTNODE}, false);
392             }
393             if (dialogs) {
394                 exportChildren(RepositoryConstants.CONFIG, session, moduleroot, "dialogs", new ItemType[]{
395                     ItemType.CONTENT,
396                     ItemType.CONTENTNODE}, true);
397             }
398             if (virtualURIs) {
399                 exportChildren(
400                     RepositoryConstants.CONFIG,
401                     session,
402                     moduleroot,
403                     "virtualURIMapping",
404                     new ItemType[]{ItemType.CONTENTNODE},
405                     true);
406             }
407             AlertUtil.setMessage("Backup done to "
408                 + new File(Path.getAbsoluteFileSystemPath(rootdir)).getCanonicalPath());
409         }
410         catch (Exception e) {
411             log.error(e.getMessage(), e);
412             AlertUtil.setMessage("Error while processing module " + module, e);
413         }
414 
415         if (website) {
416             extractWorkspaceRoots(RepositoryConstants.WEBSITE);
417         }
418 
419         if (users) {
420             backupChildren(RepositoryConstants.USERS, "/admin");
421         }
422 
423         if (groups) {
424             extractWorkspaceRoots(RepositoryConstants.USER_GROUPS);
425         }
426 
427         if (roles) {
428             extractWorkspaceRoots(RepositoryConstants.USER_ROLES);
429         }
430 
431         return this.show();
432     }
433 
434     /**
435      * @param repositoryName
436      */
437     private void extractWorkspaceRoots(String repositoryName) {
438         try {
439             HierarchyManager hm = MgnlContext.getHierarchyManager(repositoryName);
440             Content wesiteRoot = hm.getRoot();
441 
442             Iterator children = wesiteRoot.getChildren(ContentUtil.MAGNOLIA_FILTER).iterator();
443             while (children.hasNext()) {
444                 Content exported = (Content) children.next();
445                 exportNode(repositoryName, hm.getWorkspace().getSession(), exported);
446             }
447         }
448         catch (Exception e) {
449             log.error(e.getMessage(), e);
450             AlertUtil.setMessage("Error while processing " + repositoryName + " repository", e);
451         }
452     }
453 
454     public String backupChildren() {
455         backupChildren(this.repository, this.parentpath);
456 
457         String path = Path.getAbsoluteFileSystemPath(rootdir);
458 
459         try {
460             path = new File(path).getCanonicalPath();
461         }
462         catch (IOException e) {
463             // should never happen
464         }
465 
466         AlertUtil.setMessage("Backup done to " + path);
467 
468         return this.show();
469     }
470 
471     private void backupChildren(String repository, String parentpath) {
472         HierarchyManager hm = MgnlContext.getHierarchyManager(repository);
473 
474         Content parentNode = null;
475         try {
476             parentNode = hm.getContent(parentpath);
477         }
478         catch (RepositoryException e) {
479             // ignore
480             return;
481         }
482         try {
483             Iterator children = parentNode.getChildren(ContentUtil.ALL_NODES_EXCEPT_JCR_CONTENT_FILTER).iterator();
484             while (children.hasNext()) {
485                 Content exported = (Content) children.next();
486                 exportNode(repository, hm.getWorkspace().getSession(), exported);
487             }
488 
489         }
490         catch (Exception e) {
491             log.error(e.getMessage(), e);
492             AlertUtil.setMessage("Error while processing actions", e);
493         }
494 
495     }
496 
497     /**
498      * @param session
499      * @param moduleroot
500      * @param exportContentContainingContentNodes
501      * @throws PathNotFoundException
502      * @throws RepositoryException
503      * @throws AccessDeniedException
504      * @throws FileNotFoundException
505      * @throws IOException
506      */
507     private void exportChildren(String repository, Session session, Content moduleroot, String path,
508         ItemType[] itemTypes, boolean exportContentContainingContentNodes) throws PathNotFoundException,
509         RepositoryException, AccessDeniedException, FileNotFoundException, IOException {
510         Content templateRoot = null;
511         try {
512             templateRoot = moduleroot.getContent(path);
513         }
514         catch (PathNotFoundException e) {
515             // ignore
516             return;
517         }
518 
519         // we need to track exported paths, or it will export any single control for dialogs
520         Set alreadyExported = new HashSet();
521 
522         Iterator children = ContentUtil.collectAllChildren(templateRoot, itemTypes).iterator();
523         while (children.hasNext()) {
524             Content exported = (Content) children.next();
525             if (!exported.getNodeDataCollection().isEmpty() // ignore "directories"
526                 || (exportContentContainingContentNodes && exported.hasChildren(ItemType.CONTENTNODE.getSystemName()))) {
527 
528                 String current = exported.getHandle();
529                 boolean dontexport = false;
530 
531                 for (Iterator iterator = alreadyExported.iterator(); iterator.hasNext();) {
532                     String already = (String) iterator.next();
533                     if (current.startsWith(already)) {
534                         dontexport = true;
535                         break;
536                     }
537                 }
538 
539                 if (!dontexport) {
540                     alreadyExported.add(exported.getHandle() + "/");
541                     exportNode(repository, session, exported);
542                 }
543             }
544         }
545     }
546 
547     /**
548      * @param session
549      * @param exported
550      * @throws FileNotFoundException
551      * @throws IOException
552      */
553     private void exportNode(String repository, Session session, Content exported) throws FileNotFoundException,
554         IOException {
555         String handle = exported.getHandle();
556         String xmlName = repository + StringUtils.replace(handle, "/", ".") + ".xml";
557         xmlName = DataTransporter.encodePath(xmlName, ".", "UTF-8");
558         // create necessary parent directories
559         File folder = new File(Path.getAbsoluteFileSystemPath(rootdir));
560         folder.mkdirs();
561         File xmlFile = new File(folder.getAbsoluteFile(), xmlName);
562         FileOutputStream fos = new FileOutputStream(xmlFile);
563 
564         try {
565             DataTransporter.executeExport(fos, false, true, session, handle, repository, DataTransporter.XML);
566         }
567         finally {
568             IOUtils.closeQuietly(fos);
569         }
570     }
571 }