View Javadoc
1   /**
2    * This file Copyright (c) 2003-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 info.magnolia.cms.beans.config.ObservedManager;
37  import info.magnolia.cms.core.Content;
38  import info.magnolia.cms.util.ContentUtil;
39  import info.magnolia.cms.util.SystemContentWrapper;
40  import info.magnolia.cms.util.NodeDataUtil;
41  import info.magnolia.content2bean.Content2BeanException;
42  import info.magnolia.content2bean.Content2BeanUtil;
43  import info.magnolia.content2bean.TransformationState;
44  import info.magnolia.content2bean.impl.Content2BeanTransformerImpl;
45  import info.magnolia.objectfactory.ComponentProvider;
46  import info.magnolia.objectfactory.Components;
47  
48  import java.lang.reflect.Constructor;
49  import java.util.HashMap;
50  import java.util.Iterator;
51  import java.util.Map;
52  
53  import javax.inject.Singleton;
54  import javax.servlet.http.HttpServletRequest;
55  import javax.servlet.http.HttpServletResponse;
56  
57  import org.apache.commons.beanutils.BeanUtils;
58  import org.apache.commons.beanutils.ConstructorUtils;
59  
60  
61  /**
62   * Manages the page handlers. A page is a very simple dialog without any configuration.
63   * @author philipp
64   */
65  @Singleton
66  public class PageHandlerManager extends ObservedManager {
67  
68      /**
69       * The handlers
70       */
71      private final Map dialogPageHandlers = new HashMap();
72  
73      /**
74       * Find a handler by name
75       * @param name
76       * @param request
77       * @param response
78       * @return an instance of the handlers
79       */
80      public PageMVCHandler getPageHandler(String name, HttpServletRequest request, HttpServletResponse response) {
81  
82          PageDefinition pageDefinition = (PageDefinition) dialogPageHandlers.get(name);
83  
84          if (pageDefinition == null) {
85              log.warn("Page definition not found: \"{}\"", name);
86              return null;
87          }
88          return pageDefinition.newInstance(name, request, response);
89      }
90  
91      /**
92       * register the pages from the config
93       * @param defNode
94       */
95      @Override
96      protected void onRegister(Content defNode) {
97          // read the dialog configuration
98  
99          for (Iterator iter = ContentUtil.getAllChildren(defNode).iterator(); iter.hasNext();) {
100             Content pageNode = (Content) iter.next();
101 
102             PageDefinition pd = new RepositoryPageDefinition(new SystemContentWrapper(pageNode));
103             registerPageDefinition(pd);
104         }
105 
106     }
107 
108     public void registerPageDefinition(PageDefinition pageDefinition) {
109         dialogPageHandlers.put(pageDefinition.getName(), pageDefinition);
110     }
111 
112     /**
113      * @deprecated
114      */
115     public void registerPageDefinition(String name, PageDefinition pageDefinition) {
116         dialogPageHandlers.put(name, pageDefinition);
117     }
118 
119     /**
120      * @return Returns the instance.
121      */
122     public static PageHandlerManager getInstance() {
123         return Components.getSingleton(PageHandlerManager.class);
124     }
125 
126     @Override
127     protected void onClear() {
128         this.dialogPageHandlers.clear();
129     }
130 
131     public static interface PageDefinition {
132 
133         public String getName();
134 
135         public PageMVCHandler newInstance(String name, HttpServletRequest request, HttpServletResponse response);
136     }
137 
138     /**
139      * This class is used if you want to register a page that is not stored in the repository.
140      * @author philipp
141      * @version $Id$
142      */
143     public static class BasePageDefinition implements PageDefinition {
144         private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BasePageDefinition.class);
145 
146         private Map defaultProperties = new HashMap();
147 
148         private Class handlerClass;
149 
150         private String name;
151 
152         public BasePageDefinition(String name, Class handlerClass) {
153             this.name = name;
154             this.handlerClass = handlerClass;
155         }
156 
157         public Map getDefaultProperties() {
158             return this.defaultProperties;
159         }
160 
161         public void setDefaultProperties(Map defaultProperties) {
162             this.defaultProperties = defaultProperties;
163         }
164 
165         public Class getHandlerClass() {
166             return this.handlerClass;
167         }
168 
169         public void setHandlerClass(Class handlerClass) {
170             this.handlerClass = handlerClass;
171         }
172 
173         @Override
174         public String getName() {
175             return this.name;
176         }
177 
178         public void setName(String name) {
179             this.name = name;
180         }
181 
182         @Override
183         public PageMVCHandler newInstance(String name, HttpServletRequest request, HttpServletResponse response) {
184 
185             try {
186                 Constructor constructor = getHandlerClass().getConstructor(
187                     new Class[]{String.class, HttpServletRequest.class, HttpServletResponse.class});
188                 PageMVCHandler page = (PageMVCHandler) constructor.newInstance(new Object[]{name, request, response});
189                 BeanUtils.populate(page, getDefaultProperties());
190                 return page;
191             }
192             catch (Exception e) {
193                 log.error("Can't instantiate page [" + name + "]", e);
194                 throw new InvalidDialogPageHandlerException(name, e);
195             }
196 
197         }
198     }
199 
200     public static class RepositoryPageDefinition implements PageDefinition {
201 
202         private Content node;
203 
204         public RepositoryPageDefinition(Content node) {
205             this.node = node;
206         }
207 
208         @Override
209         public String getName() {
210             return NodeDataUtil.getString(this.node, "name", this.node.getName());
211         }
212 
213         @Override
214         public PageMVCHandler newInstance(String name, final HttpServletRequest request,
215             final HttpServletResponse response) {
216             try {
217                 return (PageMVCHandler) Content2BeanUtil.toBean(node, true, new Content2BeanTransformerImpl() {
218 
219                     @Override
220                     public Object newBeanInstance(TransformationState state, Map properties, ComponentProvider componentProvider)
221                         throws Content2BeanException {
222                         if (state.getLevel() == 1) {
223                             try {
224                                 // TODO - with ioc and a request-scope container, this can go away \o/
225                                 return ConstructorUtils.invokeConstructor(
226                                     state.getCurrentType().getType(),
227                                     new Object[]{getName(), request, response});
228                             }
229                             catch (Exception e) {
230                                 throw new Content2BeanException("no proper constructor found", e);
231                             }
232                         }
233 
234                         return super.newBeanInstance(state, properties, componentProvider);
235                     }
236                 });
237             }
238             catch (Content2BeanException e) {
239                 throw new InvalidDialogPageHandlerException(this.getName(), e);
240             }
241         }
242     }
243 
244 }