View Javadoc

1   /*
2    * Copyright 2000-2001,2004 The Apache Software Foundation.
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  
17  package org.apache.jetspeed.modules.actions.portlets.browser;
18  
19  // velocity
20  import org.apache.velocity.context.Context;
21  
22  // Java Stuff
23  import java.sql.Connection;
24  import java.sql.PreparedStatement;
25  import java.sql.ResultSet;
26  import java.sql.ResultSetMetaData;
27  import java.sql.SQLException;
28  import java.sql.Types;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.ArrayList;
32  import java.util.Vector;
33  import java.util.StringTokenizer;
34  
35  // turbine util
36  import org.apache.turbine.util.RunData;
37  import org.apache.turbine.util.StringUtils;
38  
39  import org.apache.torque.Torque;
40  
41  // jetspeed services
42  import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
43  import org.apache.jetspeed.services.logging.JetspeedLogger;
44  import org.apache.jetspeed.services.resources.JetspeedResources;
45  
46  // jetspeed velocity
47  import org.apache.jetspeed.modules.actions.portlets.VelocityPortletAction;
48  import org.apache.jetspeed.modules.actions.portlets.browser.ActionParameter;
49  import org.apache.jetspeed.modules.actions.portlets.browser.BrowserQuery;
50  import org.apache.jetspeed.portal.portlets.VelocityPortlet;
51  import org.apache.jetspeed.portal.portlets.browser.DatabaseBrowserIterator;
52  import org.apache.jetspeed.portal.portlets.browser.BrowserIterator;
53  import org.apache.jetspeed.util.PortletSessionState;
54  import org.apache.jetspeed.util.PortletConfigState;
55  
56  
57  
58  /***
59   * This action sets up the template context for retrieving paged data from the resultSet
60   * according to the quey speciified by the user.
61   *
62   * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
63   * @version $Id: DatabaseBrowserAction.java,v 1.34 2004/02/23 02:51:19 jford Exp $
64   */
65  public class DatabaseBrowserAction extends VelocityPortletAction implements BrowserQuery
66  {
67      protected static final String SQL = "sql";
68      protected static final String POOLNAME = "poolname";
69      protected static final String START = "start";
70      protected static final String CUSTOMIZE_TEMPLATE = "customizeTemplate";
71      protected static final String WINDOW_SIZE = "windowSize";
72  
73      protected static final String USER_OBJECT_NAMES = "user-object-names";
74      protected static final String USER_OBJECT_TYPES = "user-object-types";
75      protected static final String USER_OBJECTS = "user-objects";
76  
77      protected static final String SQL_PARAM_PREFIX = "sqlparam";
78  
79      protected static final String LINKS_READ = "linksRead";
80      protected static final String ROW_LINK = "rowLinks";
81      protected static final String TABLE_LINK = "tableLinks";
82      protected static final String ROW_LINK_IDS = "row-link-ids";
83      protected static final String ROW_LINK_TYPES = "row-link-types";
84      protected static final String ROW_LINK_TARGETS = "row-link-targets";
85      protected static final String TABLE_LINK_IDS = "table-link-ids";
86      protected static final String TABLE_LINK_TYPES = "table-link-types";
87      protected static final String TABLE_LINK_TARGETS = "table-link-targets";
88      protected static final String BROWSER_TABLE_SIZE = "tableSize";
89      protected static final String DATABASE_BROWSER_ACTION_KEY = "database_browser_action_key";
90      protected static final String BROWSER_ITERATOR = "table";
91      protected static final String BROWSER_TITLE_ITERATOR = "title";
92      protected static final String NEXT = "next";
93      protected static final String PREVIOUS = "prev";
94      protected static final String VELOCITY_NULL_ENTRY = "-";
95      // portlet entry Id
96      protected static final String PEID = "js_peid";
97      protected static final String SORT_COLUMN_NAME = "js_dbcolumn";
98  
99      protected List sqlParameters = new Vector();
100 
101     /***
102      * Static initialization of the logger for this class
103      */    
104     private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(DatabaseBrowserAction.class.getName());     
105     
106     /***
107      * Build the maximized state content for this portlet. (Same as normal state).
108      *
109      * @param portlet The velocity-based portlet that is being built.
110      * @param context The velocity context for this request.
111      * @param rundata The turbine rundata context for this request.
112      */
113     protected void buildMaximizedContext( VelocityPortlet portlet,
114                                           Context context,
115                                           RunData rundata )
116     {
117         buildNormalContext( portlet, context, rundata);
118     }
119 
120     /***
121      * Subclasses should override this method if they wish to
122      * provide their own customization behavior.
123      * Default is to use Portal base customizer action
124      */
125     protected void buildConfigureContext( VelocityPortlet portlet,
126                                           Context context,
127                                           RunData rundata )
128     {
129         try
130         {
131             super.buildConfigureContext( portlet, context, rundata);
132         }
133         catch (Exception ex)
134         {
135             logger.error("Exception", ex);
136         }
137         context.put(SQL, getQueryString(portlet, rundata, context));
138         context.put(WINDOW_SIZE, getParameterUsingFallback(portlet, rundata, WINDOW_SIZE, null));
139         setTemplate(rundata, getParameterUsingFallback(portlet, rundata, CUSTOMIZE_TEMPLATE, null));
140     }
141 
142     /***
143      * Build the normal state content for this portlet.
144      *
145      * @param portlet The velocity-based portlet that is being built.
146      * @param context The velocity context for this request.
147      * @param rundata The turbine rundata context for this request.
148      */
149     protected void buildNormalContext( VelocityPortlet portlet,
150                                        Context context,
151                                        RunData rundata )
152     {
153         int resultSetSize, next, prev, windowSize;
154 
155         BrowserIterator iterator = getDatabaseBrowserIterator(portlet, rundata);
156         String sortColName = getRequestParameter(portlet, rundata, SORT_COLUMN_NAME);
157         int start = getStartVariable(portlet, rundata, START, sortColName, iterator);
158 
159         windowSize = Integer.parseInt((String)getParameterUsingFallback(portlet, rundata, WINDOW_SIZE, "10"));
160         next = start + windowSize;
161         prev = start - windowSize;
162 
163         try
164         {
165             if(iterator == null || PortletSessionState.getPortletConfigChanged(portlet, rundata))
166             {
167                 String sql = getQueryString(portlet, rundata, context);
168                 //System.out.println("buildNormalContext SQL: "+sql);
169                 if(sql != null )
170                 {
171                     readUserParameters(portlet,rundata,context);
172                     getRows(portlet, rundata, sql, windowSize);
173                     iterator = getDatabaseBrowserIterator(portlet, rundata);
174                 }
175                 else
176                 {
177                     logger.info("The sql query is null, hence not generating the result set.");
178                 }
179             }
180             else
181             {
182                 if(sortColName != null)
183                 {
184                     iterator.sort(sortColName);
185                 }
186                 iterator.setTop(start);
187             }
188 
189             readLinkParameters(portlet, rundata, context);
190 
191             if(iterator != null)
192             {
193                 resultSetSize = iterator.getResultSetSize();
194 
195                 if(next < resultSetSize)
196                 {
197                     context.put(NEXT, String.valueOf(next));
198                 }
199                 if(prev <= resultSetSize && prev >=0 )
200                 {
201                     context.put(PREVIOUS, String.valueOf(prev));
202                 }
203 
204                 context.put(BROWSER_ITERATOR, iterator);
205                 context.put(BROWSER_TITLE_ITERATOR, iterator.getResultSetTitleList());
206                 context.put(BROWSER_TABLE_SIZE, new Integer(resultSetSize));
207 
208                 /*
209                 System.out.println("buildNormalContext Sort column name= "+sortColName);
210                 System.out.println("buildNormalContext Iterator: "+iterator);
211                 System.out.println("buildNormalContext Titles= "+iterator.getResultSetTitleList());
212                 System.out.println("buildNormalContext windowSize="+windowSize+" prev="+prev+
213                                    " next="+next+" start="+start+" resultSetSize="+resultSetSize);
214                 */
215             }
216 
217         }
218         catch (Exception e)
219         {
220            // log the error msg
221             logger.error("Exception", e);
222 
223             rundata.setMessage("Error in Jetspeed Database Browser: " + e.toString());
224             rundata.setStackTrace(StringUtils.stackTrace(e), e);
225             rundata.setScreenTemplate(JetspeedResources.getString("template.error","Error"));
226         }
227     }
228 
229     /***
230      * This method is called when the user configures any of the parameters.
231      * @param data The turbine rundata context for this request.
232      * @param context The velocity context for this request.
233      */
234     public void doUpdate(RunData rundata, Context context)
235     {
236         VelocityPortlet portlet = (VelocityPortlet)context.get("portlet");
237         String sql = getRequestParameter(portlet, rundata, SQL);
238         String pageSize = getRequestParameter(portlet, rundata, WINDOW_SIZE);
239 
240         if (sql!=null)
241         {
242             setParameterToPSML( portlet, rundata, SQL, sql);
243             context.put(SQL, sql);
244             clearDatabaseBrowserIterator(portlet, rundata);
245 
246         }
247         if(pageSize!=null)
248         {
249             setParameterToPSML( portlet, rundata, WINDOW_SIZE, pageSize);
250             context.put(WINDOW_SIZE, pageSize);
251 
252         }
253         /*
254         System.out.println("doUpdate SQL: "+sql+", Window Size: "+pageSize);
255         */
256         buildNormalContext( portlet, context, rundata);
257     }
258 
259     /***
260      * This method is called when the user hits refresh to refetch the result set.
261      * @param data The turbine rundata context for this request.
262      * @param context The velocity context for this request.
263      */
264     public void doRefresh(RunData rundata, Context context)
265     {
266         VelocityPortlet portlet = (VelocityPortlet)context.get("portlet");
267         if(isMyRequest(portlet,rundata))
268         {
269             clearDatabaseBrowserIterator(portlet, rundata);
270         }
271         buildNormalContext(portlet, context, rundata);
272     }
273 
274     /* (non-Javadoc)
275      * @see org.apache.jetspeed.modules.actions.portlets.browser.BrowserQuery#filter(java.util.List, RunData)
276      */
277     public boolean filter(List row, RunData rundata)
278     {
279         return false;
280     }
281 
282     /***
283      * Execute the sql statement as specified by the user or the default, and store the
284      * resultSet in a vector.
285      *
286      * @param sql The sql statement to be executed.
287      * @param data The turbine rundata context for this request.
288      */
289     protected void getRows(VelocityPortlet portlet, RunData rundata, String sql,
290                            int windowSize) throws Exception
291     {
292         List resultSetList = new ArrayList();
293         List resultSetTitleList = new ArrayList();
294         List resultSetTypeList = new ArrayList();
295         Connection con = null;
296         PreparedStatement selectStmt = null;
297         ResultSet rs = null;
298         try
299         {
300             String poolname = getParameterUsingFallback(portlet,rundata,POOLNAME,null);
301             if (poolname==null || poolname.length()==0)
302             {
303                 con = Torque.getConnection();
304             }
305             else
306             {
307                 con = Torque.getConnection(poolname);
308             }
309             selectStmt = con.prepareStatement(sql);
310 
311             readSqlParameters(portlet, rundata);
312             Iterator it = sqlParameters.iterator();
313             int ix = 0;
314             while (it.hasNext())
315             {
316                 ix++;
317                 Object object = it.next();
318                 selectStmt.setObject(ix, object);
319             }
320             rs = selectStmt.executeQuery();
321             ResultSetMetaData rsmd = rs.getMetaData();
322             int columnNum = rsmd.getColumnCount();
323             /*
324             get the user object types to be displayed and add them to the
325             title list as well as the result set list
326             */
327             List userObjList = (List)getParameterFromTemp(portlet, rundata, USER_OBJECTS);
328             int userObjListSize = 0;
329             if (userObjList != null)
330             {
331                 userObjListSize = userObjList.size();
332             }
333             //System.out.println("User List Size = "+ userObjListSize);
334             /*
335             the array columnDisplayed maintains a boolean value for each
336             column index. Only the columns that are set to true are added to
337             the resultSetList, resultSetTitleList and resultSetTypeList.
338             */
339             boolean[] columnDisplayed = new boolean [columnNum + userObjListSize];
340 
341             /*
342             this for loop constructs the columnDisplayed array as well as adds
343             to the resultSetTitleList and resultSetTypeList
344             */
345             for(int i = 1; i <= columnNum; i++)
346             {
347                 int type = rsmd.getColumnType(i);
348                 if( !((type == Types.BLOB) || (type == Types.CLOB) ||
349                       (type == Types.BINARY) || (type == Types.LONGVARBINARY) ||
350                       (type == Types.VARBINARY)) )
351                 {
352                     resultSetTitleList.add(rsmd.getColumnName(i));
353                     resultSetTypeList.add(String.valueOf(type));
354                     columnDisplayed[i-1] = true;
355                 }
356                 else
357                 {
358                     columnDisplayed[i-1] = false;
359                 }
360             }
361 
362             for (int i = columnNum; i < columnNum + userObjListSize; i++)
363             {
364                 ActionParameter usrObj = (ActionParameter)userObjList.get(i - columnNum);
365                 resultSetTitleList.add(usrObj.getName());
366                 resultSetTypeList.add(usrObj.getType());
367                 columnDisplayed[i] = true;
368                 //System.out.println("User List Name = "+ usrObj.getName()+" Type = "+usrObj.getType());
369             }
370             /*
371             this while loop adds each row to the resultSetList
372             */
373             int index = 0;
374             while(rs.next())
375             {
376                 List row = new ArrayList(columnNum);
377 
378                 for(int i = 1; i <= columnNum; i++)
379                 {
380                     if( columnDisplayed[i-1] )
381                     {
382                         Object obj = rs.getObject(i);
383                         if (obj == null)
384                         {
385                             obj = VELOCITY_NULL_ENTRY;
386                         }
387                         row.add(obj);
388                     }
389                 }
390                 for (int i = columnNum; i < columnNum + userObjListSize; i++)
391                 {
392                     ActionParameter usrObj = (ActionParameter)userObjList.get(i - columnNum);
393                     if( columnDisplayed[i] )
394                     {
395                         Class c = Class.forName(usrObj.getType());
396                         row.add(c.newInstance());
397                         populate(index, i, row);
398                     }
399                 }
400                 
401                 if (filter(row, rundata))
402                 {
403                     continue;
404                 }
405 
406                 resultSetList.add(row);
407                 index++;
408             }
409             BrowserIterator iterator =
410                 new DatabaseBrowserIterator( resultSetList, resultSetTitleList,
411                                              resultSetTypeList, windowSize);
412             setDatabaseBrowserIterator(portlet, rundata, iterator);
413 
414         }
415         catch (SQLException e)
416         {
417             throw e;
418         }
419         finally
420         {
421             try
422             {
423                 if (null != selectStmt)
424                     selectStmt.close();
425                 if (null != rs)
426                     rs.close();
427                 if (null != con) //closes con also
428                     Torque.closeConnection(con);
429 
430             }
431             catch (Exception e)
432             {
433                 throw e;
434             }
435         }
436 
437     }
438 
439     /***
440      * Centralizes the calls to runData.getUser.getTemp() - to retrieve
441      * the DatabaseBrowserIterator.
442      *
443      * @param data The turbine rundata context for this request.
444      *
445      */
446     protected BrowserIterator getDatabaseBrowserIterator(VelocityPortlet portlet,
447                                                          RunData rundata)
448     {
449 
450 
451         BrowserIterator iterator =
452             (BrowserIterator)getParameterFromTemp(portlet, rundata, DATABASE_BROWSER_ACTION_KEY);
453         return iterator;
454     }
455 
456     /***
457      * Centralizes the calls to runData.getUser.setTemp() - to set
458      * the DatabaseBrowserIterator.
459      *
460      * @param data The turbine rundata context for this request.
461      * @param iterator.
462      *
463      */
464     protected void setDatabaseBrowserIterator(VelocityPortlet portlet,
465                                               RunData rundata,
466                                               BrowserIterator iterator)
467     {
468         setParameterToTemp(portlet, rundata, DATABASE_BROWSER_ACTION_KEY, iterator);
469     }
470 
471     /***
472      * Centralizes the calls to runData.getUser.removeTemp() - to clear
473      * the DatabaseBrowserIterator from the temp storage.
474      *
475      * @param data The turbine rundata context for this request.
476      *
477      */
478     protected void clearDatabaseBrowserIterator(VelocityPortlet portlet, RunData rundata)
479     {
480         clearParameterFromTemp(portlet, rundata, DATABASE_BROWSER_ACTION_KEY);
481     }
482 
483     /***
484      * This method returns the query to be executed to get the results which will
485      * be opened in the browser.
486      *
487      */
488     public String getQueryString(RunData rundata, Context context)
489     {
490         return null;
491     }
492     /***
493      * This method returns the sql from the getQuery method which can be
494      * overwritten according to the needs of the application. If the getQuery()
495      * returns null, then it gets the value from the psml file. If the psml value is null
496      * then it returns the value from the xreg file.
497      *
498      */
499     protected String getQueryString(VelocityPortlet portlet, RunData rundata, Context context)
500     {
501         String sql = getQueryString(rundata, context);
502         if( sql==null )
503         {
504             sql = getParameterUsingFallback(portlet, rundata, SQL, null);
505         }
506         return sql;
507     }
508     /***
509      *
510      */
511     protected void clearQueryString(VelocityPortlet portlet, RunData rundata)
512     {
513         clearParameterFromPSML(portlet, rundata, SQL);
514     }
515     /***
516      * to be used if sorting behavior to be overwritten
517      */
518     protected int getStartIndex()
519     {
520         return 0;
521     }
522     /***
523      *
524      */
525     protected String getParameterUsingFallback(VelocityPortlet portlet, RunData rundata,
526                                              String attrName, String attrDefValue)
527     {
528         return PortletConfigState.getParameter(portlet, rundata, attrName, attrDefValue);
529     }
530     /***
531      *
532      */
533     protected void clearParameterFromPSML(VelocityPortlet portlet, RunData rundata,
534                                         String attributeName)
535     {
536         PortletConfigState.clearInstanceParameter(portlet, rundata, attributeName);
537     }
538     /***
539      *
540      */
541     protected void setParameterToPSML(VelocityPortlet portlet, RunData rundata,
542                                     String attrName, String attrValue)
543     {
544         PortletConfigState.setInstanceParameter(portlet, rundata, attrName, attrValue);
545     }
546 
547     /***
548      *
549      */
550     protected String getParameterFromPSML(VelocityPortlet portlet, RunData rundata,
551                                         String attrName, String attrDefValue)
552     {
553         return PortletConfigState.getInstanceParameter(portlet, rundata, attrName);
554 
555     }
556 
557     protected String getParameterFromRegistry(VelocityPortlet portlet,
558                                             String attrName,
559                                             String attrDefValue)
560     {
561         return PortletConfigState.getConfigParameter(portlet, attrName, attrDefValue);
562 
563     }
564 
565     /***
566      *
567      */
568     protected Object getParameterFromTemp(VelocityPortlet portlet, RunData rundata, String attrName)
569     {
570         return PortletSessionState.getAttribute(portlet, rundata, attrName);
571     }
572     /***
573      *
574      */
575     protected void setParameterToTemp(VelocityPortlet portlet, RunData rundata,
576                                       String attrName, Object attrValue)
577     {
578         PortletSessionState.setAttribute(portlet, rundata, attrName, attrValue);
579     }
580     /***
581      *
582      */
583     protected void clearParameterFromTemp(VelocityPortlet portlet, RunData rundata,
584                                           String attrName)
585     {
586         PortletSessionState.clearAttribute(portlet, rundata, attrName);
587     }
588 
589     /***
590      *
591      */
592     protected boolean isMyRequest(VelocityPortlet portlet, RunData rundata)
593     {
594         String peId = portlet.getID();
595 
596         if(peId != null && peId.equals(rundata.getParameters().getString(PEID)))
597             return true;
598         else
599             return false;
600     }
601     /***
602      *
603      */
604     protected String getRequestParameter(VelocityPortlet portlet, RunData rundata,
605                                                String attrName)
606     {
607         if(isMyRequest(portlet, rundata))
608             return rundata.getParameters().getString(attrName);
609         else
610             return null;
611     }
612     /***
613      *
614      */
615     protected int getStartVariable(VelocityPortlet portlet, RunData rundata,
616                                  String attrName, String sortColName,
617                                  BrowserIterator iterator)
618     {
619         int start = -1;
620         // if users want to overwrite how the sorting affects the cursor for
621         // the window
622         if( sortColName != null ) start = getStartIndex();
623 
624         if( start < 0 )
625         {
626             //fallback routine for start
627             String startStr = getRequestParameter(portlet, rundata, attrName);
628             if(startStr != null && startStr.length() > 0)
629             {
630                 start = Integer.parseInt(startStr);
631             }
632             else if( start == -1 && iterator != null )
633             {
634                 start = iterator.getTop();
635             }
636 
637             if( start < 0 ) start = 0;
638         }
639         return start;
640 
641     }
642 
643     public void setSQLParameters(List parameters)
644     {
645         this.sqlParameters = parameters;
646     }
647 
648     public List getSQLParameters()
649     {
650         return sqlParameters;
651     }
652 
653     protected void readSqlParameters(VelocityPortlet portlet, RunData rundata)
654     {
655         List sqlParamList = null;
656 
657         int i = 1;
658         while (true)
659         {
660             String param = getParameterUsingFallback(portlet, rundata, SQL_PARAM_PREFIX + i, null);
661             if (param == null)
662             {
663                 break;
664             }
665             else
666             {
667                 if (sqlParamList == null)
668                 {
669                     sqlParamList = new ArrayList();
670                 }
671                 sqlParamList.add(param);
672             }
673             i++;
674         }
675 
676         if (sqlParamList != null)
677         {
678             setSQLParameters(sqlParamList);
679         }
680 
681     }
682 
683     protected void readUserParameters(VelocityPortlet portlet, RunData rundata, Context context)
684     {
685         List userObjectList;
686         Object userObjRead = getParameterFromTemp(portlet, rundata, USER_OBJECTS);
687         if ( userObjRead != null)
688         {
689             context.put(USER_OBJECTS, (List)userObjRead);
690             //System.out.println("userObjectListSize: "+ ((List)userObjRead).size());
691         }
692         else
693         {
694             String userObjTypes= getParameterFromRegistry(portlet,USER_OBJECT_TYPES,null);
695             String userObjNames= getParameterFromRegistry(portlet,USER_OBJECT_NAMES,null);
696             if( userObjTypes != null && userObjTypes.length() > 0 )
697             {
698                 userObjectList = new ArrayList();
699                 int userObjectIndex = 0;
700                 StringTokenizer tokenizer1 = new StringTokenizer(userObjNames, ",");
701                 StringTokenizer tokenizer3 = new StringTokenizer(userObjTypes, ",");
702                 while(tokenizer1.hasMoreTokens() && tokenizer3.hasMoreTokens())
703                 {
704                     userObjectList.add(userObjectIndex,
705                                        new ActionParameter(tokenizer1.nextToken(), null, tokenizer3.nextToken()));
706                     userObjectIndex++;
707                 }
708                 context.put(USER_OBJECTS, userObjectList);
709                 setParameterToTemp(portlet, rundata, USER_OBJECTS, userObjectList);
710                 //System.out.println("readLink: userObjectTypesListSize: "+userObjectList.size());
711             }
712         }
713     }
714 
715     protected void readLinkParameters(VelocityPortlet portlet, RunData rundata, Context context)
716     {
717         List rowList, tableList;
718         Object linksRead = getParameterFromTemp(portlet, rundata, LINKS_READ);
719         if(linksRead != null && ((String)linksRead).equals(LINKS_READ))
720         {
721             Object tmp = getParameterFromTemp(portlet, rundata, ROW_LINK);
722             if(tmp != null)
723             {
724                 context.put(ROW_LINK, (List)tmp);
725                 //System.out.println("rowListSize"+ ((List)tmp).size());
726             }
727             tmp = getParameterFromTemp(portlet, rundata, TABLE_LINK);
728             if(tmp != null)
729             {
730                 context.put(TABLE_LINK, (List)tmp);
731                 //System.out.println("tableListSize: "+((List)tmp).size());
732             }
733         }
734         else
735         {
736             String rowLinkIds= getParameterFromRegistry(portlet,ROW_LINK_IDS,null);
737             String rowLinkClasses= getParameterFromRegistry(portlet,ROW_LINK_TARGETS,null);
738             String rowLinkTypes= getParameterFromRegistry(portlet,ROW_LINK_TYPES,null);
739             if( rowLinkIds != null && rowLinkIds.length() > 0 )
740             {
741                 rowList = new ArrayList();
742                 int rowIndex = 0;
743                 StringTokenizer tokenizer1 = new StringTokenizer(rowLinkIds, ",");
744                 StringTokenizer tokenizer2 = new StringTokenizer(rowLinkClasses, ",");
745                 StringTokenizer tokenizer3 = new StringTokenizer(rowLinkTypes, ",");
746                 while(tokenizer1.hasMoreTokens() && tokenizer2.hasMoreTokens() && tokenizer3.hasMoreTokens())
747                 {
748                     rowList.add(rowIndex,
749                                 new ActionParameter(tokenizer1.nextToken(), tokenizer2.nextToken(), tokenizer3.nextToken()));
750                     rowIndex++;
751                 }
752                 context.put(ROW_LINK, rowList);
753                 setParameterToTemp(portlet, rundata, ROW_LINK, rowList);
754                 //System.out.println("readLink: rowListSize"+rowList.size());
755             }
756 
757             String tableLinkIds= getParameterFromRegistry(portlet,TABLE_LINK_IDS,null);
758             String tableLinkClasses= getParameterFromRegistry(portlet,TABLE_LINK_TARGETS,null);
759             String tableLinkTypes= getParameterFromRegistry(portlet,TABLE_LINK_TYPES,null);
760             if( tableLinkIds != null && tableLinkIds.length() > 0 )
761             {
762                 tableList = new ArrayList();
763                 int tableIndex = 0;
764                 StringTokenizer tokenizer1 = new StringTokenizer(tableLinkIds, ",");
765                 StringTokenizer tokenizer2 = new StringTokenizer(tableLinkClasses, ",");
766                 StringTokenizer tokenizer3 = new StringTokenizer(tableLinkTypes, ",");
767                 while(tokenizer1.hasMoreTokens() && tokenizer2.hasMoreTokens() && tokenizer3.hasMoreTokens())
768                 {
769                     tableList.add(tableIndex,
770                                   new ActionParameter(tokenizer1.nextToken(), tokenizer2.nextToken(), tokenizer3.nextToken()));
771                     tableIndex++;
772                 }
773                 context.put(TABLE_LINK, tableList);
774                 setParameterToTemp(portlet, rundata, TABLE_LINK, tableList);
775                 //System.out.println("readLink: tableListSize: "+tableList.size());
776             }
777             setParameterToTemp(portlet, rundata, LINKS_READ, LINKS_READ);
778         }
779 
780     }
781 
782     /***
783      * This method should be overwritten every time the user object needs to be
784      * populated with some user specific constraints. As an example if the user wanted
785      * to track the parent of an object based on some calculation per row, it could be
786      * done here.
787      *
788      */
789     public void populate(int rowIndex, int columnIndex, List row)
790     {
791     }
792 
793 
794 }