View Javadoc

1   /*
2    * Copyright (c) 2006-2007 Creative Sphere Limited.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *
10   *   Creative Sphere - initial API and implementation
11   *
12   */
13  package org.abstracthorizon.danube.beanconsole;
14  
15  import org.abstracthorizon.danube.connection.Connection;
16  import org.abstracthorizon.danube.http.HTTPConnection;
17  import org.abstracthorizon.danube.mvc.Controller;
18  import org.abstracthorizon.danube.mvc.ModelAndView;
19  
20  import java.beans.BeanInfo;
21  import java.beans.IntrospectionException;
22  import java.beans.Introspector;
23  import java.beans.MethodDescriptor;
24  import java.beans.PropertyDescriptor;
25  import java.beans.PropertyEditor;
26  import java.beans.PropertyEditorManager;
27  import java.lang.reflect.Method;
28  import java.util.Collection;
29  import java.util.HashMap;
30  import java.util.Map;
31  
32  import org.springframework.context.ApplicationContext;
33  import org.springframework.context.ApplicationContextAware;
34  import org.springframework.context.ConfigurableApplicationContext;
35  
36  /**
37   * Controller that processes request, select the object and prepares data for the view
38   *
39   * @author Daniel Sendula
40   */
41  public class DisplayController implements Controller, ApplicationContextAware {
42  
43      /**
44       * Root object
45       */
46      protected Object root;
47  
48      /** Application context this controller is running under */
49      protected ApplicationContext rootContext;
50  
51      /** Component path this controller is to be working from */
52      protected String componentPath;
53  
54      /**
55       * If path defined as a pattern to a specific page (index.html for instance)
56       * then it needs to be stripped of component resource path before it is used
57       */
58      protected String pageName;
59  
60      /**
61       * Method that handles a request. It returns following entries in model's map:
62       * <ul>
63       *   <li>connection - httpConnection passed into this controller</li>
64       *   <li>uri - URI this page is called from. It always ends with &quot;/&quot;</li>
65       *   <li>name - name of the bean (last element of the path or Root Bean)</li>
66       *   <li>type - string representation of the type of the selected object</li>
67       *   <li>path - full path to the bean. Path elements are separated with &quot;.&quot; and if
68       *              element has dot in it then it is enclosed in &quot;&lt;&quot; and &quot;&gt;&quot; simbols</li>
69       *   <li>resourcePath - full path to the bean but always starting with &quot;/&quot; and never ending
70       *              with it. If root then empty string. It is used for creating URIs.</li>
71       *   <li>topUri and backUri - uris to previous bean and top - root bean. </li>
72       *   <li>current - reference to the object referenced with the path</li>
73       *   <li>propertiesError - if error occured setting properties</li>
74       *   <li>beans - list of {@link BeanDef} objects - if object is of {@link ConfigurableApplicationContext} type.</li>
75       *   <li>map - list of {@link BeanDef} objects - if object is of {@link Map} type.</li>
76       *   <li>collection - list of {@link BeanDef} objects - if object is of {@link Collection} type.</li>
77       *   <li>properties - list of {@link BeanDef} objects - object accessible properties.</li>
78       *   <li>methods - list of {@link MethodDescriptor} object - methods that are not used for properties' access.</li>
79       * </ul>
80       * <p>
81       *   For the way navigation is done check {@link BeanHelper#navigate(Object, String)} method documentation.
82       * </p>
83       */
84      public ModelAndView handleRequest(Connection connection) {
85          HTTPConnection httpConnection = (HTTPConnection)connection.adapt(HTTPConnection.class);
86  
87          Map<String, Object> model = new HashMap<String, Object>();
88  
89          model.put("connection", connection);
90  
91  
92          String resourcePath = BeanHelper.createResourcePath(httpConnection.getComponentResourcePath());
93  
94          if ((pageName != null) && resourcePath.endsWith(pageName)) {
95              resourcePath = resourcePath.substring(0, resourcePath.length() - pageName.length() - 1);
96          }
97  
98          model.put("uri", httpConnection.getContextPath() + componentPath + resourcePath + "/");
99  
100         Object current = getRootObject();
101         if (resourcePath.length() > 0) {
102             int i = resourcePath.lastIndexOf('/');
103             if (i > 0) {
104                 String backUri = httpConnection.getContextPath() + componentPath + resourcePath.substring(0, i);
105                 model.put("backUri", backUri);
106             } else {
107                 model.put("backUri", httpConnection.getContextPath() + componentPath);
108             }
109             model.put("topUri", httpConnection.getContextPath() + componentPath);
110             current = BeanHelper.navigate(current, resourcePath);
111         }
112 
113         model.put("name", BeanHelper.createName(resourcePath));
114         model.put("path", BeanHelper.createPath(resourcePath));
115         model.put("type", BeanHelper.toTypeString(current));
116         model.put("resourcePath", resourcePath);
117         model.put("current", current);
118 
119         if ("true".equals(httpConnection.getRequestParameters().getOnly("-update"))) {
120             updateProperties(current, httpConnection, model);
121         }
122 
123         BeanHelper.prepare(current, model);
124 
125         String accept = httpConnection.getRequestHeaders().getOnly("Accept");
126         String view = null;
127         if (accept != null) {
128             if (accept.indexOf("text/html") >= 0) {
129                 view = "html/display";
130             } else if (accept.indexOf("text/xml") >= 0) {
131                 view = "xml/display";
132             }
133         }
134         if (view == null) {
135             view = "text/display";
136         }
137 
138         ModelAndView modelAndView = new ModelAndView(view, model);
139         return modelAndView;
140     }
141 
142 
143     /**
144      * Sets properties of the selected bean.
145      *
146      * @param current selected bean
147      * @param httpConnection http connection
148      * @param model model
149      */
150     protected void updateProperties(Object current, HTTPConnection httpConnection, Map<String, Object> model) {
151         boolean hasError = false;
152         StringBuilder errorString = null;
153         try {
154             BeanInfo beanInfo = Introspector.getBeanInfo(current.getClass());
155 
156             PropertyDescriptor[] props = beanInfo.getPropertyDescriptors();
157             for (PropertyDescriptor prop : props) {
158                 String param = prop.getName();
159                 Method writeMethod = prop.getWriteMethod();
160                 if (writeMethod != null) {
161                     PropertyEditor writePropertyEditor = PropertyEditorManager.findEditor(writeMethod.getParameterTypes()[0]);
162                     if (writePropertyEditor != null) {
163                         String value = (String)httpConnection.getRequestParameters().getOnly(param);
164                         if (value != null) {
165                             String oldValue = BeanHelper.toString(prop);
166                             if (oldValue != value) {
167                                 try {
168                                     writePropertyEditor.setAsText(value);
169                                     writeMethod.invoke(current, new Object[]{writePropertyEditor.getValue()});
170                                 } catch (Exception e) {
171                                     if (!hasError) {
172                                         hasError = true;
173                                         errorString = new StringBuilder();
174                                     } else {
175                                         errorString.append("\n");
176                                     }
177                                     errorString.append(BeanHelper.stackTrace(e));
178                                 }
179                             } else {
180                                  //logger.debug("Skipped storing new value for " + param + " since they are same");
181                             }
182                         } else {
183                             //
184                         }
185                     }
186                 }
187             }
188         } catch (IntrospectionException e) {
189             if (errorString == null) {
190                 errorString = new StringBuilder();
191             }
192             if (!hasError) {
193                 hasError = true;
194                 errorString = new StringBuilder();
195             } else {
196                 errorString.append("\n");
197             }
198             errorString.append(BeanHelper.stackTrace(e));
199         }
200         if (hasError) {
201             model.put("propertiesError", errorString.toString());
202         }
203 
204     }
205 
206     /**
207      * Sets root application context in case root is not set.
208      * @param context application context
209      */
210     public void setApplicationContext(ApplicationContext context) {
211         while (context.getParent() != null) {
212             context = context.getParent();
213         }
214         this.rootContext = context;
215     }
216 
217     /**
218      * Returns root object. If not set then rootContext is used instead.
219      * @return root object
220      */
221     public Object getRootObject() {
222         if (root == null) {
223             root = rootContext;
224         }
225         return root;
226     }
227 
228     /**
229      * Sets root object.
230      * @param root root object.
231      */
232     public void setRootObject(Object root) {
233         this.root = root;
234     }
235 
236     /**
237      * Returns component path
238      * @return component path
239      */
240     public String getComponentPath() {
241         return componentPath;
242     }
243 
244     /**
245      * Sets component path
246      * @param componentPath component path
247      */
248     public void setComponentPath(String componentPath) {
249         this.componentPath = componentPath;
250     }
251 
252     /**
253      * Returns page name
254      * @return page name
255      */
256     public String getPageName() {
257         return pageName;
258     }
259 
260     /**
261      * Sets page name
262      * @param pageName page name
263      */
264     public void setPageName(String pageName) {
265         this.pageName = pageName;
266     }
267 
268 }