View Javadoc
1   /**
2    * This file Copyright (c) 2012-2014 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;
35  
36  import java.util.ArrayList;
37  import java.util.HashSet;
38  import java.util.Iterator;
39  import java.util.List;
40  import java.util.Set;
41  import javax.inject.Inject;
42  import javax.inject.Singleton;
43  import javax.jcr.Node;
44  import javax.jcr.RepositoryException;
45  
46  import org.apache.commons.lang.StringUtils;
47  import org.apache.commons.lang.exception.ExceptionUtils;
48  import org.slf4j.Logger;
49  import org.slf4j.LoggerFactory;
50  
51  import info.magnolia.cms.core.Content;
52  import info.magnolia.cms.core.ItemType;
53  import info.magnolia.cms.util.ContentUtil;
54  import info.magnolia.cms.util.ExtendingContentWrapper;
55  import info.magnolia.cms.util.ModuleConfigurationObservingManager;
56  import info.magnolia.cms.util.NodeDataUtil;
57  import info.magnolia.cms.util.SystemContentWrapper;
58  import info.magnolia.module.ModuleRegistry;
59  import info.magnolia.module.admininterface.dialogs.ConfiguredDialog;
60  import info.magnolia.objectfactory.Classes;
61  
62  /**
63   * Observes dialogs configured in modules and registers them with {@link DialogHandlerManager} when they're changed.
64   *
65   * @version $Id$
66   */
67  @Singleton
68  public class ConfiguredDialogHandlerManager extends ModuleConfigurationObservingManager {
69  
70      protected final Logger log = LoggerFactory.getLogger(getClass());
71  
72      private static final String CLASS = "class";
73      private static final String ND_NAME = "name";
74  
75      private Set<String> registeredIds = new HashSet<String>();
76      private final DialogHandlerManager dialogHandlerManager;
77  
78      @Inject
79      public ConfiguredDialogHandlerManager(ModuleRegistry moduleRegistry, DialogHandlerManager dialogHandlerManager) {
80          super("dialogs", moduleRegistry);
81          this.dialogHandlerManager = dialogHandlerManager;
82      }
83  
84      @Override
85      protected void reload(List<Node> nodes) throws RepositoryException {
86  
87          final List<DialogHandlerProvider> providers = new ArrayList<DialogHandlerProvider>();
88  
89          for (Node node2 : nodes) {
90  
91              Content node = ContentUtil.asContent(node2);
92  
93              final List<Content> dialogNodes = new ArrayList<Content>();
94              try {
95                  collectDialogNodes(node, dialogNodes);
96              } catch (RepositoryException e) {
97                  log.error("Can't collect dialog nodes for [" + node.getHandle() + "]: " + ExceptionUtils.getMessage(e), e);
98                  throw new IllegalStateException("Can't collect dialog nodes for [" + node.getHandle() + "]: " + ExceptionUtils.getMessage(e));
99              }
100 
101             for (Iterator<Content> iter = dialogNodes.iterator(); iter.hasNext(); ) {
102                 Content dialogNode = new ExtendingContentWrapper(new SystemContentWrapper(iter.next()));
103                 try {
104                     if (dialogNode.getItemType().equals(ItemType.CONTENT) && dialogNode.hasNodeData("label")) {
105                         log.warn("Dialog definitions should be of type contentNode but [" + dialogNode.getHandle() + "] is of type content.");
106                     }
107                 } catch (RepositoryException e) {
108                     log.error("Can't check for node type of the dialog node [" + dialogNode.getHandle() + "]: " + ExceptionUtils.getMessage(e), e);
109                     throw new IllegalStateException("Can't check for node type of the dialog node ["
110                             + dialogNode.getHandle()
111                             + "]: "
112                             + ExceptionUtils.getMessage(e));
113                 }
114 
115                 String dialogId;
116                 try {
117                     dialogId = getDialogId(dialogNode);
118                 } catch (RepositoryException e) {
119                     log.warn("Can't establish id for dialog [" + dialogNode.getHandle() + "]: " + ExceptionUtils.getMessage(e), e);
120                     continue;
121                 }
122 
123                 String name = dialogNode.getNodeData(ND_NAME).getString();
124                 if (StringUtils.isEmpty(name)) {
125                     name = dialogNode.getName();
126                 }
127 
128                 // dialog class is not mandatory
129                 String className = NodeDataUtil.getString(dialogNode, CLASS);
130                 Class<? extends DialogMVCHandler> dialogClass;
131                 try {
132                     if (StringUtils.isNotEmpty(className)) {
133                         dialogClass = Classes.getClassFactory().forName(className);
134                     } else {
135                         dialogClass = ConfiguredDialog.class;
136                     }
137                 } catch (ClassNotFoundException e) {
138                     log.warn("Can't find dialog handler class " + className, e);
139                     continue;
140                 }
141 
142                 providers.add(new ConfiguredDialogHandlerProvider(name, dialogNode, dialogClass));
143                 providers.add(new ConfiguredDialogHandlerProvider(dialogId, dialogNode, dialogClass));
144             }
145         }
146 
147         this.registeredIds = dialogHandlerManager.unregisterAndRegister(registeredIds, providers);
148     }
149 
150     protected String getDialogId(Content node) throws RepositoryException {
151         Content moduleNode = node.getAncestor(2);
152         Content dialogsNode = node.getAncestor(3);
153         return moduleNode.getName() + ":" + StringUtils.removeStart(node.getHandle(), dialogsNode.getHandle() + "/");
154     }
155 
156     protected void collectDialogNodes(Content current, List<Content> dialogNodes) throws RepositoryException {
157         if (isDialogNode(current)) {
158             dialogNodes.add(current);
159             return;
160         }
161         for (Content child : ContentUtil.getAllChildren(current)) {
162             collectDialogNodes(child, dialogNodes);
163         }
164     }
165 
166     protected boolean isDialogNode(Content node) throws RepositoryException {
167         if (isDialogControlNode(node)) {
168             return false;
169         }
170 
171         // if leaf
172         if (ContentUtil.getAllChildren(node).isEmpty()) {
173             return true;
174         }
175 
176         // if has node datas
177         if (!node.getNodeDataCollection().isEmpty()) {
178             return true;
179         }
180 
181         // if one subnode is a control
182         for (Content child : node.getChildren(ItemType.CONTENTNODE)) {
183             if (isDialogControlNode(child)) {
184                 return true;
185             }
186         }
187         return false;
188     }
189 
190     protected boolean isDialogControlNode(Content node) throws RepositoryException {
191         return node.hasNodeData("controlType") || node.hasNodeData("reference");
192     }
193 }