View Javadoc

1   /*
2    * Copyright 2007 The International Moth Class Association (IMCA)
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sf.imca.web;
17  
18  import java.io.IOException;
19  import java.io.PrintWriter;
20  import java.lang.reflect.InvocationTargetException;
21  import java.lang.reflect.Method;
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.Enumeration;
25  import java.util.Hashtable;
26  import java.util.Iterator;
27  import java.util.List;
28  
29  import javax.servlet.http.HttpServlet;
30  import javax.servlet.http.HttpServletRequest;
31  import javax.servlet.http.HttpServletResponse;
32  
33  import net.sf.imca.services.EditDataService;
34  import net.sf.imca.services.ReflectionUtil;
35  import net.sf.imca.web.backingbeans.Utils;
36  
37  /**
38   * This is an old school style Servlet that allows simple access to the data 
39   * for administration.  It dynamically generates a form for entity classes.
40   *
41   * @author dougculnane
42   */
43  public class DataAdminServlet extends HttpServlet {
44  
45      /**
46       * Generated serialVersionUID.
47       */
48      private static final long serialVersionUID = -5496814088701502977L;
49  
50      /**
51       * Location where the model entities are.
52       */
53      private static final String ENTITY_PACKAGE_NAME = "net.sf.imca.model.entities";
54  
55      /**
56       * Servlet implementation of HTTP post.
57       */
58      public void doPost(HttpServletRequest req, HttpServletResponse res) {
59          doHttp(req, res);
60      }
61  
62      /**
63       * Servlet implementation of HTTP get.
64       */
65      public void doGet(HttpServletRequest req, HttpServletResponse res) {
66          doHttp(req, res);
67      }
68  
69      /**
70       * Handle HTTP request.
71       */   
72      @SuppressWarnings("unchecked")
73      public void doHttp(HttpServletRequest req, HttpServletResponse res) {
74          
75          res.setContentType("text/html");
76          
77          // Security
78          try {
79              if (!Utils.getWebUser().getPerson().getEntity().getSystemAdmin()) {
80                  return;
81              }
82          } catch (NullPointerException npe) {
83              return;
84          }
85          
86          String entityName =  req.getParameter("entity");
87          String command =  req.getParameter("command");
88          String id =  req.getParameter("Id");
89          String goToId =  req.getParameter("goToId");
90          String search =  req.getParameter("search");
91          
92          try {
93              res.getWriter().write(getPageHeader());
94              doEntitySwitcherForm(res.getWriter(), entityName);
95              res.getWriter().write("<h2>" + entityName + "</h2>\n" +
96              		"<form " +
97              		"action=\"/imca/faces/dataAdmin.jsp\" method=\"post\">\n" +
98              		"<input type=\"hidden\" name=\"entity\" value=\"" 
99                      + entityName + "\" />\n");
100 
101             EditDataService service = new EditDataService();
102             Object entity = req.getSession().getAttribute("dataAdmin_entity");
103             if (entityName != null) {
104                 if (entity == null) {
105                     entity = ReflectionUtil.getObject(getEntityClassName(entityName));
106                     req.getSession().setAttribute("dataAdmin_entity", entity);
107                 } else  {
108                     if (!entity.getClass().getName().equals(getEntityClassName(entityName))) {
109                         entity = ReflectionUtil.getObject(getEntityClassName(entityName));
110                         req.getSession().setAttribute("dataAdmin_entity", entity);
111                     }
112                 }
113             }
114 
115             // Handle go to Parameter
116             if (goToId != null) {
117                 id = goToId;
118                 long goToIdInt = new Long(goToId).intValue();
119                 entity = service.findEntity(entity.getClass(), goToIdInt);
120             }
121             if (entity != null) {
122                 ReflectionUtil.setEntityValuesFromParameterMap(
123                         entity, buildRequestHashtable(req));
124             }
125 
126             // Handle command.
127             List results = null;
128             if (command != null) {
129                 if ("Save".equals(command)) {
130                     entity = service.saveEntity(entity, id);
131                 } else  if ("New".equals(command)) {
132                     id = null;
133                     entity = ReflectionUtil.getObject(
134                             getEntityClassName(entityName));
135                 } else  if ("Delete".equals(command)) {
136                     service.deleteEntity(entity, id);
137                     id = null;
138                     entity = ReflectionUtil.getObject(
139                             getEntityClassName(entityName));
140                 } else  if ("Search".equals(command)) {
141                     results = service.search(entityName, search);
142                 }
143             }
144 
145             // Build Page
146             if (entity != null) {
147                 doEntityForm(res.getWriter(), entity);
148                 res.getWriter().write("<input type=\"hidden\" name=\"Id\" value=\"" + id + "\" />");
149                 doCommandButtons(res.getWriter());
150                 doSearchTable(res.getWriter(), results, search);
151             }
152             
153             res.getWriter().write(getPageFooter());
154         } catch (Exception e) {
155             try {
156                 res.getWriter().write("<pre>\n");
157                 e.printStackTrace(res.getWriter());
158                 res.getWriter().write("</pre>\n");
159             } catch (IOException e1) {
160                 e1.printStackTrace();
161             }
162         }
163     }
164     
165     @SuppressWarnings("unchecked")
166     private Hashtable<String, String> buildRequestHashtable(
167             HttpServletRequest req) {
168 
169         Hashtable<String, String> values = new   Hashtable<String, String>();
170         Enumeration<String> keys = req.getParameterNames();
171         while (keys.hasMoreElements()) {
172             String key = keys.nextElement();
173             values.put(key, req.getParameter(key));
174         }
175         return values;
176     }
177 
178     private void  doEntityForm(PrintWriter writer, Object entity) 
179             throws IllegalArgumentException, IllegalAccessException, 
180             InvocationTargetException, SecurityException, NoSuchMethodException {
181         
182         Method[] methods = entity.getClass().getMethods();
183         entity.getClass().getMethods().toString();
184     
185         writer.write("<table>\n<tr>\n"); 
186         for (int i=0; i < methods.length; i++) {
187             if (!("getClass".equals(methods[i].getName())) &&
188                     methods[i].getName().startsWith("get")) {
189                 doFormRow(writer, entity,  methods[i]);
190             }
191         }
192         writer.write("</table>\n");
193     }
194 
195     @SuppressWarnings("unchecked")
196     private void  doFormRow(PrintWriter writer, Object entity, Method method) 
197             throws IllegalArgumentException, IllegalAccessException, 
198             InvocationTargetException, SecurityException, NoSuchMethodException{
199 
200         String className = method.getReturnType().getName();
201 
202         if (processClass(className)) {
203             writer.write("<tr>\n<td>\n");  
204             writer.write(extractLabel(method));
205             writer.write("</td>\n<td>\n" +
206             		"<input type=\"text\" name=\"" + 
207                     method.getName().substring(3) + "\" value=\"");
208 
209             if (method.invoke(entity, ReflectionUtil.NO_PARAMS) != null) {
210                 if ( className.endsWith(ReflectionUtil.ENTITY)) {
211                     writer.write(ReflectionUtil.getEntityId(method.invoke(entity, ReflectionUtil.NO_PARAMS)));
212                 } else if ("java.util.Collection".equals(className)){
213                     Collection collection = (Collection)method.invoke(entity, ReflectionUtil.NO_PARAMS);
214                     writer.write(extractCollectionValues(collection));
215                 } else {
216                     writer.write(method.invoke(entity, ReflectionUtil.NO_PARAMS).toString());
217                 }
218             }
219             writer.write("\"");
220             
221             if ("getId".equals(method.getName())) {
222                 writer.write(" readonly=\"true\""); 
223             }
224             writer.write(" />");
225 
226             if ( className.endsWith(ReflectionUtil.ENTITY)) {
227                 if (method.invoke(entity, ReflectionUtil.NO_PARAMS) != null) {
228                     writer.write("<a href=\"?entity=" + 
229                             extractEntityName(className) +
230                             "&goToId=");
231                     writer.write(ReflectionUtil.getEntityId(method.invoke(entity, ReflectionUtil.NO_PARAMS)));
232                     writer.write("\">");
233                     writer.write(method.invoke(entity, ReflectionUtil.NO_PARAMS).toString());
234                     writer.write("</a>");
235                 }
236             }
237             writer.write("</td>\n</tr>\n"); 
238         }
239     }
240 
241     /**
242      * Should the servlet process the class.  Does the servlet understand how
243      * to peocess the class?
244      *
245      * @param className
246      * @return true if the servlet can handle this class.
247      */
248     private boolean processClass(String className) {
249         return "java.lang.String".equals(className)
250         || "boolean".equals(className)
251         || "int".equals(className)
252         || "double".equals(className)
253         || className.endsWith(ReflectionUtil.ENTITY)
254         || "java.util.Collection".equals(className);
255     }
256 
257     /**
258      * extract the human readable label for the method name.
259      *
260      * @param method
261      * @return
262      */
263     private String extractLabel(Method method) {
264         return method.getName().substring(3);
265     }
266 
267     /**
268      * From the collection build a display value.
269      *
270      * @param collection
271      * @return
272      * @throws SecurityException
273      * @throws IllegalArgumentException
274      * @throws NoSuchMethodException
275      * @throws IllegalAccessException
276      * @throws InvocationTargetException
277      */
278     @SuppressWarnings("unchecked")
279     private String extractCollectionValues(Collection collection) 
280             throws SecurityException, IllegalArgumentException, 
281             NoSuchMethodException, IllegalAccessException, 
282             InvocationTargetException {
283 
284         Iterator iter = collection.iterator();
285         StringBuffer buf = new StringBuffer();
286         while (iter.hasNext()){
287             if (buf.length() > 0) {
288                 buf.append(",");
289             }
290             buf.append(ReflectionUtil.getEntityId(iter.next()));
291         }
292         return buf.toString();
293     }
294 
295     /**
296      * Write out the command buttons.
297      * @param writer
298      */
299     private void doCommandButtons(PrintWriter writer){
300         writer.write(
301                 "<input type=\"submit\" name=\"command\" value=\"New\" />" +
302         		"<input type=\"submit\" name=\"command\" value=\"Save\" />" +
303         		"<input type=\"submit\" name=\"command\" value=\"Delete\" />");
304     }
305 
306     /**
307      * Wrtie out the search table results.
308      *
309      * @param writer
310      * @param results
311      * @param search
312      * @throws IllegalArgumentException
313      * @throws IllegalAccessException
314      * @throws InvocationTargetException
315      * @throws SecurityException
316      * @throws NoSuchMethodException
317      */
318     @SuppressWarnings("unchecked")
319     private void  doSearchTable(PrintWriter writer, List results, String search) 
320             throws IllegalArgumentException, IllegalAccessException, 
321             InvocationTargetException, SecurityException, 
322             NoSuchMethodException {
323 
324         writer.write("<h2>Search</h2>\n");
325         if(search == null ) {
326             search = "";
327         }
328         writer.write("<input type=\"text\" name=\"search\" value=\"" +
329                 search + "\" />"); 
330         writer.write("<input type=\"submit\" name=\"command\" value=\"Search\" />");
331         if (results != null) {
332             writer.write("<table>");
333             for (int i=0; i < results.size(); i++) {
334                 doTableRow(writer, results.get(i));
335             }
336             writer.write("</table>");
337         }
338     }
339     
340     private void doTableRow(PrintWriter writer, Object entity) 
341             throws IllegalArgumentException, IllegalAccessException, 
342             InvocationTargetException, SecurityException, 
343             NoSuchMethodException {
344 
345         Method[] methods = entity.getClass().getMethods();
346         entity.getClass().getMethods().toString();
347 
348         String entityName = extractEntityName(entity.getClass());
349         writer.write("<tr>\n<th><a href=\"?entity=" + entityName +
350                 "&goToId=" +
351                 ReflectionUtil.getEntityId(entity)
352                 + "\" />" + entity.toString() + "</a></th>");  
353         for (int i=0; i < methods.length; i++) {
354             if (!("getClass".equals(methods[i].getName())) &&
355                     methods[i].getName().startsWith("get")) {
356                 
357                 String className = methods[i].getReturnType().getName();
358                
359                 if ("java.lang.String".equals(className)
360                         || "double".equals(className)
361                         || "int".equals(className)) {
362                     writer.write("<td>");
363                     writer.write(methods[i].invoke(entity, ReflectionUtil.NO_PARAMS).toString()); 
364                     writer.write("</td>\n");
365                 }
366             }
367         }
368         writer.write("</tr>");
369     }
370 
371     private String getEntityClassName(String entity) {
372         return ENTITY_PACKAGE_NAME + "." + entity + "Entity";
373     }
374 
375     private String getPageHeader(){
376         return "<html>\n" +
377         		"\t<head>\n" +
378         		"\t\t<title>IMCA Data Administration</title>\n" +
379         		"\t\t<link rel=\"stylesheet\" href=\"style.css\" " +
380         		"type=\"text/css\" />\n" +
381         		"\t</head>\n" +
382         		"<body>\n" +
383         		"<h1>Data Admin.</h1>\n";
384     }
385 
386     /**
387      * Write out page footer.
388      * @return
389      */
390     private String getPageFooter() {
391         return "</form>\n" +
392                 "</body>\n" +
393                 "</html>\n";
394     } 
395 
396     /**
397      * Write out entity type selector.
398      * @param writer
399      * @param entityName
400      * @throws ClassNotFoundException
401      */
402     @SuppressWarnings("unchecked")
403     public void doEntitySwitcherForm(PrintWriter writer, String entityName) 
404             throws ClassNotFoundException {
405         
406         writer.write("<form action=\"/imca/faces/dataAdmin.jsp\" method=\"post\">\n" +
407         		"Entity: <select name=\"entity\">\n");
408         ArrayList<Class> entityPacakageClasses = ReflectionUtil.getClasses(ENTITY_PACKAGE_NAME);
409         for (int i=0; i <entityPacakageClasses.size(); i++) {
410             String className = entityPacakageClasses.get(i).getName();
411             if (className.endsWith(ReflectionUtil.ENTITY)) {
412                 
413                 String entityNameTemp = extractEntityName(entityPacakageClasses.get(i));
414                     
415                 writer.write("\t<option value=\"" + entityNameTemp + "\"");
416                 if (entityName != null && entityName.equals(entityNameTemp)) {
417                     writer.write(" selected=\"selected\"");
418                 }
419            		writer.write(">" + entityNameTemp + "</option>\n");
420             }
421         }
422         writer.write("<input type=\"submit\" value=\"Go\" /></select></form>");
423     }
424 
425     /**
426      * Find the entity name name form the class.
427      *
428      * @param clazz
429      * @return
430      */
431     @SuppressWarnings("unchecked")
432     private String extractEntityName(Class clazz) {
433         return extractEntityName(clazz.getName());
434     }
435 
436     /**
437      * Find the entity name name form the class name.
438      * @param className
439      * @return
440      */
441     private String extractEntityName(String className) {
442         return className.substring(
443                 ENTITY_PACKAGE_NAME.length() + 1, 
444                 className.lastIndexOf(ReflectionUtil.ENTITY));
445     }
446 }