View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.portals.gems.browser;
18  
19  import java.io.IOException;
20  import java.util.ArrayList;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Vector;
24  
25  import javax.portlet.ActionRequest;
26  import javax.portlet.ActionResponse;
27  import javax.portlet.PortletContext;
28  import javax.portlet.PortletException;
29  import javax.portlet.PortletMode;
30  import javax.portlet.PortletConfig;
31  import javax.portlet.PortletPreferences;
32  import javax.portlet.PortletRequest;
33  import javax.portlet.PortletSession;
34  import javax.portlet.RenderRequest;
35  import javax.portlet.RenderResponse;
36  
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  import org.apache.jetspeed.sso.SSOProvider;
40  import org.apache.portals.bridges.velocity.GenericVelocityPortlet;
41  import org.apache.portals.gems.util.StatusMessage;
42  import org.apache.portals.messaging.PortletMessaging;
43  import org.apache.velocity.context.Context;
44  
45  /***
46   * AbstractBrowserPortlet
47   * 
48   * @author <a href="mailto:taylor@apache.org">David Sean Taylor </a>
49   * @version $Id: AbstractBrowserPortlet.java,v 1.2 2005/01/01 00:01:29 taylor
50   *          Exp $
51   */
52  public class BrowserPortlet extends GenericVelocityPortlet implements Browser
53  {
54  
55      protected static final String SQL = "sql";
56  
57      protected static final String POOLNAME = "poolname";
58  
59      protected static final String START = "start";
60      protected static final String FIND = "find";
61      protected static final String SEARCH_STRING = "searchString";
62      protected static final String SEARCH_COLUMN = "searchColumn";
63      protected static final String FILTERED = "filtered";
64      protected static final String FILTER = "filter";
65      
66      protected static final String CUSTOMIZE_TEMPLATE = "customizeTemplate";
67  
68      protected static final String WINDOW_SIZE = "WindowSize";
69  
70      protected static final String USER_OBJECT_NAMES = "user-object-names";
71  
72      protected static final String USER_OBJECT_TYPES = "user-object-types";
73  
74      protected static final String USER_OBJECTS = "user-objects";
75  
76      protected static final String SQL_PARAM_PREFIX = "sqlparam";
77  
78      protected static final String LINKS_READ = "linksRead";
79  
80      protected static final String ROW_LINK = "rowLinks";
81  
82      protected static final String TABLE_LINK = "tableLinks";
83  
84      protected static final String ROW_LINK_IDS = "row-link-ids";
85  
86      protected static final String ROW_LINK_TYPES = "row-link-types";
87  
88      protected static final String ROW_LINK_TARGETS = "row-link-targets";
89  
90      protected static final String TABLE_LINK_IDS = "table-link-ids";
91  
92      protected static final String TABLE_LINK_TYPES = "table-link-types";
93  
94      protected static final String TABLE_LINK_TARGETS = "table-link-targets";
95  
96      protected static final String BROWSER_TABLE_SIZE = "tableSize";
97  
98      protected static final String BROWSER_ACTION_KEY = "browser_action_key";
99  
100     protected static final String BROWSER_ITERATOR = "table";
101 
102     protected static final String BROWSER_TITLE_ITERATOR = "title";
103 
104     protected static final String NEXT = "next";
105 
106     protected static final String PREVIOUS = "prev";
107 
108     protected static final String FIRST = "first";
109 
110     protected static final String LAST = "last";
111     
112     protected static final String VELOCITY_NULL_ENTRY = "-";
113 
114     // portlet entry Id
115     protected static final String PEID = "js_peid";
116 
117     protected static final String SORT_COLUMN_NAME = "js_dbcolumn";
118 
119     protected List sqlParameters = new Vector();
120     
121     /*
122      * SSO link
123      */
124     protected PortletContext context;
125     protected SSOProvider sso;
126 
127     /***
128      * Static initialization of the logger for this class
129      */
130     protected Log log = LogFactory.getLog(BrowserPortlet.class);
131 
132     public void init(PortletConfig config) throws PortletException
133     {
134         super.init(config);
135         
136         context = getPortletContext();
137         sso = (SSOProvider)context.getAttribute("cps:SSO");
138         if (null == sso)
139         {
140             log.info("Warning: SSO provider not found.");
141            //throw new PortletException("Failed to find SSO Provider on portlet initialization");
142         }        
143     }
144 
145     public void getRows(RenderRequest request, String sql, int windowSize)
146             throws Exception
147     {
148     }
149 
150     public void getRows(RenderRequest request, String sql, int windowSize, String filter)
151     throws Exception
152     {
153     }
154     
155     public void doView(RenderRequest request, RenderResponse response)
156             throws PortletException, IOException
157     {
158         int resultSetSize, next, prev, windowSize;
159 
160         response.setContentType("text/html");
161 
162         BrowserIterator iterator = getBrowserIterator(request);
163         Context context = this.getContext(request);
164 
165         String sortColName = request.getParameter(SORT_COLUMN_NAME);
166         int start = getStartVariable(request, START, sortColName, iterator);
167         
168         PortletPreferences prefs = request.getPreferences();
169 
170         windowSize = Integer.parseInt(prefs.getValue(WINDOW_SIZE, "10"));
171         
172         StatusMessage message = (StatusMessage)PortletMessaging.consume(request, "DatabaseBrowserPortlet", "action");
173         if (message != null)
174         {
175             this.getContext(request).put("statusMsg", message);            
176         }
177         
178         try
179         {
180             if (iterator == null)
181             {
182                 String sql = getQueryString(request, context);
183                 // System.out.println("buildNormalContext SQL: "+sql);
184                 readUserParameters(request, context);
185                 String filter = request.getParameter(FILTER);
186                 if (filter != null)
187                     getRows(request, sql, windowSize, filter);
188                 else                    
189                     getRows(request, sql, windowSize);
190                 iterator = getBrowserIterator(request);
191                 start = 0;
192             } 
193             else
194             {
195                 if (sortColName != null)
196                 {
197                     iterator.sort(sortColName);
198                 }
199             }
200 
201             resultSetSize = iterator.getResultSetSize();                    
202             if (start >= resultSetSize)
203             {
204                 if ((start - windowSize) > 0)
205                     start = resultSetSize - windowSize;
206                 else
207                     start = 0;            
208             }        
209             next = start + windowSize;
210             prev = start - windowSize;
211             if (prev < 0 && start > 0)
212                prev = 0;
213             iterator.setTop(start);
214             
215             
216             readLinkParameters(request, context);
217 
218             if (iterator != null)
219             {
220                 resultSetSize = iterator.getResultSetSize();
221 
222                 if (next <= resultSetSize)
223                 {
224                     context.put(NEXT, String.valueOf(next));
225                 }
226                 if (prev <= resultSetSize && prev >= 0)
227                 {
228                     context.put(PREVIOUS, String.valueOf(prev));
229                 }
230 
231                 context.put(BROWSER_ITERATOR, iterator);
232                 context.put(BROWSER_TITLE_ITERATOR, iterator
233                         .getResultSetTitleList());
234                 context.put(BROWSER_TABLE_SIZE, new Integer(resultSetSize));
235                 context.put(WINDOW_SIZE, new Integer(windowSize));
236                 context.put(START, new Integer(start));
237                 /*
238                  * System.out.println("buildNormalContext Sort column name=
239                  * "+sortColName); System.out.println("buildNormalContext
240                  * Iterator: "+iterator); System.out.println("buildNormalContext
241                  * Titles= "+iterator.getResultSetTitleList());
242                  * System.out.println("buildNormalContext
243                  * windowSize="+windowSize+" prev="+prev+ " next="+next+"
244                  * start="+start+" resultSetSize="+resultSetSize);
245                  */
246             }
247 
248         } catch (Exception e)
249         {
250             String msg = e.toString();
251             Throwable cause = e.getCause();
252             if (cause != null)
253             {
254                 msg = msg + ", " + cause.getMessage();
255             }
256             
257             context.put("statusMsg", new StatusMessage(msg, StatusMessage.ERROR));
258             // log the error msg
259             log.error("Exception", e);
260 
261             /*
262              * TODO: error logging
263              * 
264              * rundata.setMessage("Error in Portals Gems Browser: " +
265              * e.toString()); rundata.setStackTrace(StringUtils.stackTrace(e),
266              * e);
267              * rundata.setScreenTemplate(JetspeedResources.getString("template.error","Error"));
268              */
269         }
270 
271         super.doView(request, response);
272     }
273 
274     public void doEdit(RenderRequest request, RenderResponse response)
275             throws PortletException, IOException
276     {
277         response.setContentType("text/html");
278         doPreferencesEdit(request, response);
279     }
280 
281     public void processAction(ActionRequest request, ActionResponse response)
282             throws PortletException, IOException
283     {
284         if (request.getPortletMode() == PortletMode.EDIT)
285         {
286             processPreferencesAction(request, response);
287             clearBrowserIterator(request);            
288         } else
289         {
290             String browserAction = request.getParameter("db.browser.action");
291             if (browserAction != null)
292             {
293                 if (browserAction.equals("refresh"))
294                 {
295                     clearBrowserIterator(request);
296                 }
297                 String start = request.getParameter(START);
298                 if (start != null)
299                 {
300                     response.setRenderParameter(START, start);
301                 }
302                 String searchString = request.getParameter(SEARCH_STRING);
303                 if (searchString != null)
304                 {                    
305                     String searchColumn = request.getParameter(SEARCH_COLUMN);
306                     String filtered = request.getParameter(FILTERED);                    
307                     if (filtered != null)
308                     {
309                         clearBrowserIterator(request);                        
310                         response.setRenderParameter(FILTER, searchString);
311                     }
312                     else
313                     {
314                         int index = find(this.getBrowserIterator(request), searchString, searchColumn);
315                         if (index == -1)
316                         {
317                             try
318                             {
319                                 StatusMessage sm = new StatusMessage("Could not find match for: " + searchString, StatusMessage.ALERT);        
320                                 PortletMessaging.publish(request, "DatabaseBrowserPortlet", "action", sm);
321                             }
322                             catch (Exception e)
323                             {}
324                         }
325                         else
326                         {
327                             response.setRenderParameter(START, Integer.toString(index));                        
328                         }
329                     }
330                 }                
331             }
332         }
333     }
334 
335     /***
336      * Centralizes the calls to session - to retrieve the BrowserIterator.
337      * 
338      * @param data
339      *            The turbine rundata context for this request.
340      * 
341      */
342     protected BrowserIterator getBrowserIterator(PortletRequest request)
343     {
344         BrowserIterator iterator = (BrowserIterator) request
345                 .getPortletSession().getAttribute(BROWSER_ACTION_KEY,
346                         PortletSession.PORTLET_SCOPE);
347         return iterator;
348     }
349 
350     /***
351      * Centralizes the calls to session - to set the BrowserIterator.
352      * 
353      * @param data
354      *            The turbine rundata context for this request.
355      * @param iterator.
356      * 
357      */
358     protected void setBrowserIterator(RenderRequest request,
359             BrowserIterator iterator)
360     {
361         request.getPortletSession().setAttribute(BROWSER_ACTION_KEY, iterator);
362     }
363 
364     /***
365      * Centralizes the calls to session - to clear the BrowserIterator from the
366      * temp storage.
367      * 
368      * @param data
369      *            The turbine rundata context for this request.
370      * 
371      */
372     protected void clearBrowserIterator(PortletRequest request)
373     {
374         request.getPortletSession().removeAttribute(BROWSER_ACTION_KEY);
375     }
376 
377     protected int getStartVariable(RenderRequest request, String attrName,
378             String sortColName, BrowserIterator iterator)
379     {
380         int start = -1;
381         // if users want to overwrite how the sorting affects the cursor for
382         // the window
383         if (sortColName != null) 
384             start = getStartIndex();
385 
386         if (start < 0)
387         {
388             // fallback routine for start
389             String startStr = request.getParameter(attrName);
390             if (startStr != null && startStr.length() > 0)
391             {
392                 try
393                 {
394                     start = Integer.parseInt(startStr);                    
395                 }
396                 catch (Exception e)
397                 {
398                     if (iterator != null)
399                         start = iterator.getTop();
400                     else
401                         start = 0;
402                 }
403             } else if (start == -1 && iterator != null)
404             {
405                 start = iterator.getTop();
406             }
407 
408             if (start < 0) start = 0;
409         }
410         return start;
411     }
412 
413     /***
414      * to be used if sorting behavior to be overwritten
415      */
416     protected int getStartIndex()
417     {
418         return 0;
419     }
420 
421     /***
422      * This method returns the sql from the getQuery method which can be
423      * overwritten according to the needs of the application. If the getQuery()
424      * returns null, then it gets the value from the psml file. If the psml
425      * value is null then it returns the value from the xreg file.
426      * 
427      */
428     protected String getQueryString(RenderRequest request, Context context)
429     {
430         String sql = getQueryString(request);
431         if (null == sql)
432         {
433             sql = getPreference(request, SQL, null);
434         }
435         return sql;
436     }
437 
438     public String getQueryString(RenderRequest request)
439     {
440         return null;
441     }
442 
443     protected String getPreference(RenderRequest request, String attrName,
444             String attrDefValue)
445     {
446         return request.getPreferences().getValue(attrName, attrDefValue);
447     }
448 
449     protected void readUserParameters(RenderRequest request, Context context)
450     {
451         Object userObjRead = request.getPortletSession().getAttribute(
452                 USER_OBJECTS, PortletSession.PORTLET_SCOPE);
453         if (userObjRead != null)
454         {
455             context.put(USER_OBJECTS, userObjRead);
456             // System.out.println("userObjectListSize: "+
457             // ((List)userObjRead).size());
458         } else
459         {
460             /*
461              * TODO: implement user parameters
462              * 
463              * String userObjTypes=
464              * getParameterFromRegistry(portlet,USER_OBJECT_TYPES,null); String
465              * userObjNames=
466              * getParameterFromRegistry(portlet,USER_OBJECT_NAMES,null); if(
467              * userObjTypes != null && userObjTypes.length() > 0 ) {
468              * userObjectList = new ArrayList(); int userObjectIndex = 0;
469              * StringTokenizer tokenizer1 = new StringTokenizer(userObjNames,
470              * ","); StringTokenizer tokenizer3 = new
471              * StringTokenizer(userObjTypes, ",");
472              * while(tokenizer1.hasMoreTokens() && tokenizer3.hasMoreTokens()) {
473              * userObjectList.add(userObjectIndex, new
474              * ActionParameter(tokenizer1.nextToken(), null,
475              * tokenizer3.nextToken())); userObjectIndex++; }
476              * context.put(USER_OBJECTS, userObjectList);
477              * setParameterToTemp(portlet, rundata, USER_OBJECTS,
478              * userObjectList); //System.out.println("readLink:
479              * userObjectTypesListSize: "+userObjectList.size()); }
480              */
481         }
482     }
483 
484     protected void readSqlParameters(RenderRequest request)
485     {
486         List sqlParamList = null;
487 
488         int i = 1;
489         while (true)
490         {
491             String param = getPreference(request, SQL_PARAM_PREFIX + i, null);
492             if (param == null)
493             {
494                 break;
495             } else
496             {
497                 if (sqlParamList == null)
498                 {
499                     sqlParamList = new ArrayList();
500                 }
501                 sqlParamList.add(param);
502             }
503             i++;
504         }
505 
506         if (sqlParamList != null)
507         {
508             setSQLParameters(sqlParamList);
509         }
510     }
511 
512     public void setSQLParameters(List parameters)
513     {
514         this.sqlParameters = parameters;
515     }
516 
517     protected void readLinkParameters(RenderRequest request, Context context)
518     {
519         // TODO: implement me
520     }
521 
522     /***
523      * This method should be overwritten every time the user object needs to be
524      * populated with some user specific constraints. As an example if the user
525      * wanted to track the parent of an object based on some calculation per
526      * row, it could be done here.
527      * 
528      */
529     public void populate(int rowIndex, int columnIndex, List row)
530     {
531     }
532 
533     /*
534      * (non-Javadoc)
535      * 
536      * @see org.apache.jetspeed.modules.actions.portlets.browser.BrowserQuery#filter(java.util.List,
537      *      RunData)
538      */
539     public boolean filter(List row, RenderRequest request)
540     {
541         return false;
542     }
543 
544     public void publishStatusMessage(PortletRequest request, String portlet, String topic, Throwable e, String message)
545     {
546         String msg = message + ": " + e.toString();
547         Throwable cause = e.getCause();
548         if (cause != null)
549         {
550             msg = msg + ", " + cause.getMessage();
551         }
552         StatusMessage sm = new StatusMessage(msg, StatusMessage.ERROR);
553         try
554         {
555             // TODO: fixme, bug in Pluto on portlet session
556             PortletMessaging.publish(request, portlet, topic, sm);
557         }
558         catch (Exception ee)
559         {
560             System.err.println("Failed to publish message: " + e);
561         }        
562     }
563 
564     public int find(BrowserIterator iterator, String searchString, String searchColumn)
565     {
566         int index = 0;
567         int column = 1; 
568         
569         if (searchColumn != null)
570             column = Integer.parseInt(searchColumn);
571         
572         Iterator it = iterator.getResultSet().iterator();
573         while (it.hasNext())
574         {
575             Object row = it.next();
576             String item = "";
577             if (row instanceof String)
578                 item = (String)row;
579             else if (row instanceof List)
580             {
581                 // TODO: this only works on String columns                
582                 item = (String)((List)row).get(column); 
583             }
584             if (item.startsWith(searchString))
585             {
586                 return index;
587             }
588             index++;
589         }
590         
591         return -1;
592     }
593 }