/*
* Copyright 2000-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.portals.gems.browser;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletMode;
import javax.portlet.PortletConfig;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jetspeed.sso.SSOProvider;
import org.apache.portals.bridges.velocity.GenericVelocityPortlet;
import org.apache.portals.gems.util.StatusMessage;
import org.apache.portals.messaging.PortletMessaging;
import org.apache.velocity.context.Context;
/**
* AbstractBrowserPortlet
*
* @author <a href="mailto:taylor@apache.org">David Sean Taylor </a>
* @version $Id: AbstractBrowserPortlet.java,v 1.2 2005/01/01 00:01:29 taylor
* Exp $
*/
public class BrowserPortlet extends GenericVelocityPortlet implements Browser
{
protected static final String SQL = "sql";
protected static final String POOLNAME = "poolname";
protected static final String START = "start";
protected static final String FIND = "find";
protected static final String SEARCH_STRING = "searchString";
protected static final String SEARCH_COLUMN = "searchColumn";
protected static final String CUSTOMIZE_TEMPLATE = "customizeTemplate";
protected static final String WINDOW_SIZE = "WindowSize";
protected static final String USER_OBJECT_NAMES = "user-object-names";
protected static final String USER_OBJECT_TYPES = "user-object-types";
protected static final String USER_OBJECTS = "user-objects";
protected static final String SQL_PARAM_PREFIX = "sqlparam";
protected static final String LINKS_READ = "linksRead";
protected static final String ROW_LINK = "rowLinks";
protected static final String TABLE_LINK = "tableLinks";
protected static final String ROW_LINK_IDS = "row-link-ids";
protected static final String ROW_LINK_TYPES = "row-link-types";
protected static final String ROW_LINK_TARGETS = "row-link-targets";
protected static final String TABLE_LINK_IDS = "table-link-ids";
protected static final String TABLE_LINK_TYPES = "table-link-types";
protected static final String TABLE_LINK_TARGETS = "table-link-targets";
protected static final String BROWSER_TABLE_SIZE = "tableSize";
protected static final String BROWSER_ACTION_KEY = "browser_action_key";
protected static final String BROWSER_ITERATOR = "table";
protected static final String BROWSER_TITLE_ITERATOR = "title";
protected static final String NEXT = "next";
protected static final String PREVIOUS = "prev";
protected static final String FIRST = "first";
protected static final String LAST = "last";
protected static final String VELOCITY_NULL_ENTRY = "-";
// portlet entry Id
protected static final String PEID = "js_peid";
protected static final String SORT_COLUMN_NAME = "js_dbcolumn";
protected List sqlParameters = new Vector();
/*
* SSO link
*/
protected PortletContext context;
protected SSOProvider sso;
/**
* Static initialization of the logger for this class
*/
protected Log log = LogFactory.getLog(BrowserPortlet.class);
public void init(PortletConfig config) throws PortletException
{
super.init(config);
context = getPortletContext();
sso = (SSOProvider)context.getAttribute("cps:SSO");
if (null == sso)
{
log.info("Warning: SSO provider not found.");
//throw new PortletException("Failed to find SSO Provider on portlet initialization");
}
}
public void getRows(RenderRequest request, String sql, int windowSize)
throws Exception
{
}
public void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException
{
int resultSetSize, next, prev, windowSize;
response.setContentType("text/html");
BrowserIterator iterator = getBrowserIterator(request);
Context context = this.getContext(request);
String sortColName = request.getParameter(SORT_COLUMN_NAME);
int start = getStartVariable(request, START, sortColName, iterator);
PortletPreferences prefs = request.getPreferences();
windowSize = Integer.parseInt(prefs.getValue(WINDOW_SIZE, "10"));
StatusMessage message = (StatusMessage)PortletMessaging.consume(request, "DatabaseBrowserPortlet", "action");
if (message != null)
{
this.getContext(request).put("statusMsg", message);
}
try
{
if (iterator == null)
{
String sql = getQueryString(request, context);
// System.out.println("buildNormalContext SQL: "+sql);
readUserParameters(request, context);
getRows(request, sql, windowSize);
iterator = getBrowserIterator(request);
start = 0;
}
else
{
if (sortColName != null)
{
iterator.sort(sortColName);
}
}
resultSetSize = iterator.getResultSetSize();
if (start >= resultSetSize)
{
if ((start - windowSize) > 0)
start = resultSetSize - windowSize;
else
start = 0;
}
next = start + windowSize;
prev = start - windowSize;
if (prev < 0 && start > 0)
prev = 0;
iterator.setTop(start);
readLinkParameters(request, context);
if (iterator != null)
{
resultSetSize = iterator.getResultSetSize();
if (next <= resultSetSize)
{
context.put(NEXT, String.valueOf(next));
}
if (prev <= resultSetSize && prev >= 0)
{
context.put(PREVIOUS, String.valueOf(prev));
}
context.put(BROWSER_ITERATOR, iterator);
context.put(BROWSER_TITLE_ITERATOR, iterator
.getResultSetTitleList());
context.put(BROWSER_TABLE_SIZE, new Integer(resultSetSize));
context.put(WINDOW_SIZE, new Integer(windowSize));
context.put(START, new Integer(start));
/*
* System.out.println("buildNormalContext Sort column name=
* "+sortColName); System.out.println("buildNormalContext
* Iterator: "+iterator); System.out.println("buildNormalContext
* Titles= "+iterator.getResultSetTitleList());
* System.out.println("buildNormalContext
* windowSize="+windowSize+" prev="+prev+ " next="+next+"
* start="+start+" resultSetSize="+resultSetSize);
*/
}
} catch (Exception e)
{
String msg = e.toString();
Throwable cause = e.getCause();
if (cause != null)
{
msg = msg + ", " + cause.getMessage();
}
context.put("statusMsg", new StatusMessage(msg, StatusMessage.ERROR));
// log the error msg
log.error("Exception", e);
/*
* TODO: error logging
*
* rundata.setMessage("Error in Portals Gems Browser: " +
* e.toString()); rundata.setStackTrace(StringUtils.stackTrace(e),
* e);
* rundata.setScreenTemplate(JetspeedResources.getString("template.error","Error"));
*/
}
super.doView(request, response);
}
public void doEdit(RenderRequest request, RenderResponse response)
throws PortletException, IOException
{
response.setContentType("text/html");
doPreferencesEdit(request, response);
}
public void processAction(ActionRequest request, ActionResponse response)
throws PortletException, IOException
{
if (request.getPortletMode() == PortletMode.EDIT)
{
processPreferencesAction(request, response);
clearBrowserIterator(request);
} else
{
String browserAction = request.getParameter("db.browser.action");
if (browserAction != null)
{
if (browserAction.equals("refresh"))
{
clearBrowserIterator(request);
}
String start = request.getParameter(START);
if (start != null)
{
response.setRenderParameter(START, start);
}
String searchString = request.getParameter(SEARCH_STRING);
if (searchString != null)
{
String searchColumn = request.getParameter(SEARCH_COLUMN);
int index = find(this.getBrowserIterator(request), searchString, searchColumn);
if (index == -1)
{
try
{
StatusMessage sm = new StatusMessage("Could not find match for: " + searchString, StatusMessage.ALERT);
PortletMessaging.publish(request, "DatabaseBrowserPortlet", "action", sm);
}
catch (Exception e)
{}
}
else
{
response.setRenderParameter(START, Integer.toString(index));
}
}
}
}
}
/**
* Centralizes the calls to session - to retrieve the BrowserIterator.
*
* @param data
* The turbine rundata context for this request.
*
*/
protected BrowserIterator getBrowserIterator(PortletRequest request)
{
BrowserIterator iterator = (BrowserIterator) request
.getPortletSession().getAttribute(BROWSER_ACTION_KEY,
PortletSession.PORTLET_SCOPE);
return iterator;
}
/**
* Centralizes the calls to session - to set the BrowserIterator.
*
* @param data
* The turbine rundata context for this request.
* @param iterator.
*
*/
protected void setBrowserIterator(RenderRequest request,
BrowserIterator iterator)
{
request.getPortletSession().setAttribute(BROWSER_ACTION_KEY, iterator);
}
/**
* Centralizes the calls to session - to clear the BrowserIterator from the
* temp storage.
*
* @param data
* The turbine rundata context for this request.
*
*/
protected void clearBrowserIterator(PortletRequest request)
{
request.getPortletSession().removeAttribute(BROWSER_ACTION_KEY);
}
protected int getStartVariable(RenderRequest request, String attrName,
String sortColName, BrowserIterator iterator)
{
int start = -1;
// if users want to overwrite how the sorting affects the cursor for
// the window
if (sortColName != null)
start = getStartIndex();
if (start < 0)
{
// fallback routine for start
String startStr = request.getParameter(attrName);
if (startStr != null && startStr.length() > 0)
{
try
{
start = Integer.parseInt(startStr);
}
catch (Exception e)
{
if (iterator != null)
start = iterator.getTop();
else
start = 0;
}
} else if (start == -1 && iterator != null)
{
start = iterator.getTop();
}
if (start < 0) start = 0;
}
return start;
}
/**
* to be used if sorting behavior to be overwritten
*/
protected int getStartIndex()
{
return 0;
}
/**
* This method returns the sql from the getQuery method which can be
* overwritten according to the needs of the application. If the getQuery()
* returns null, then it gets the value from the psml file. If the psml
* value is null then it returns the value from the xreg file.
*
*/
protected String getQueryString(RenderRequest request, Context context)
{
String sql = getQueryString(request);
if (null == sql)
{
sql = getPreference(request, SQL, null);
}
return sql;
}
public String getQueryString(RenderRequest request)
{
return null;
}
protected String getPreference(RenderRequest request, String attrName,
String attrDefValue)
{
return request.getPreferences().getValue(attrName, attrDefValue);
}
protected void readUserParameters(RenderRequest request, Context context)
{
List userObjectList;
Object userObjRead = request.getPortletSession().getAttribute(
USER_OBJECTS, PortletSession.PORTLET_SCOPE);
if (userObjRead != null)
{
context.put(USER_OBJECTS, (List) userObjRead);
// System.out.println("userObjectListSize: "+
// ((List)userObjRead).size());
} else
{
/*
* TODO: implement user parameters
*
* String userObjTypes=
* getParameterFromRegistry(portlet,USER_OBJECT_TYPES,null); String
* userObjNames=
* getParameterFromRegistry(portlet,USER_OBJECT_NAMES,null); if(
* userObjTypes != null && userObjTypes.length() > 0 ) {
* userObjectList = new ArrayList(); int userObjectIndex = 0;
* StringTokenizer tokenizer1 = new StringTokenizer(userObjNames,
* ","); StringTokenizer tokenizer3 = new
* StringTokenizer(userObjTypes, ",");
* while(tokenizer1.hasMoreTokens() && tokenizer3.hasMoreTokens()) {
* userObjectList.add(userObjectIndex, new
* ActionParameter(tokenizer1.nextToken(), null,
* tokenizer3.nextToken())); userObjectIndex++; }
* context.put(USER_OBJECTS, userObjectList);
* setParameterToTemp(portlet, rundata, USER_OBJECTS,
* userObjectList); //System.out.println("readLink:
* userObjectTypesListSize: "+userObjectList.size()); }
*/
}
}
protected void readSqlParameters(RenderRequest request)
{
List sqlParamList = null;
int i = 1;
while (true)
{
String param = getPreference(request, SQL_PARAM_PREFIX + i, null);
if (param == null)
{
break;
} else
{
if (sqlParamList == null)
{
sqlParamList = new ArrayList();
}
sqlParamList.add(param);
}
i++;
}
if (sqlParamList != null)
{
setSQLParameters(sqlParamList);
}
}
public void setSQLParameters(List parameters)
{
this.sqlParameters = parameters;
}
protected void readLinkParameters(RenderRequest request, Context context)
{
// TODO: implement me
}
/**
* This method should be overwritten every time the user object needs to be
* populated with some user specific constraints. As an example if the user
* wanted to track the parent of an object based on some calculation per
* row, it could be done here.
*
*/
public void populate(int rowIndex, int columnIndex, List row)
{
}
/*
* (non-Javadoc)
*
* @see org.apache.jetspeed.modules.actions.portlets.browser.BrowserQuery#filter(java.util.List,
* RunData)
*/
public boolean filter(List row, RenderRequest request)
{
return false;
}
public void publishStatusMessage(PortletRequest request, String portlet, String topic, Throwable e, String message)
{
String msg = message + ": " + e.toString();
Throwable cause = e.getCause();
if (cause != null)
{
msg = msg + ", " + cause.getMessage();
}
StatusMessage sm = new StatusMessage(msg, StatusMessage.ERROR);
try
{
// TODO: fixme, bug in Pluto on portlet session
PortletMessaging.publish(request, portlet, topic, sm);
}
catch (Exception ee)
{
System.err.println("Failed to publish message: " + e);
}
}
public int find(BrowserIterator iterator, String searchString, String searchColumn)
{
int index = 0;
int column = 1;
if (searchColumn != null)
column = Integer.parseInt(searchColumn);
Iterator it = iterator.getResultSet().iterator();
while (it.hasNext())
{
// TODO: this only works on String columns
List row = (List)it.next();
String item = (String)row.get(column);
if (item.startsWith(searchString))
{
return index;
}
index++;
}
return -1;
}
}