merge 5911 from nihvivo-rel-1.1-maint to trunk

This commit is contained in:
bdc34 2010-10-06 20:02:20 +00:00
parent 4549e8e610
commit f0d55d6875
10 changed files with 683 additions and 232 deletions

View file

@ -2,20 +2,43 @@
package edu.cornell.mannlib.vitro.webapp.controller; package edu.cornell.mannlib.vitro.webapp.controller;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.net.URLEncoder;
import java.util.ArrayList;
import javax.servlet.RequestDispatcher; import java.util.Collections;
import javax.servlet.ServletException; import java.util.List;
import javax.servlet.http.HttpServletRequest; import java.util.Random;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.RequestDispatcher;
import org.apache.commons.logging.Log; import javax.servlet.ServletException;
import org.apache.commons.logging.LogFactory; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import edu.cornell.mannlib.vitro.webapp.auth.policy.JenaNetidPolicy.ContextSetup;
import edu.cornell.mannlib.vitro.webapp.beans.Tab; import org.apache.commons.logging.Log;
import edu.cornell.mannlib.vitro.webapp.web.TabWebUtil; import org.apache.commons.logging.LogFactory;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.RangeQuery;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.joda.time.DateTime;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.Tab;
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
import edu.cornell.mannlib.vitro.webapp.dao.TabDao;
import edu.cornell.mannlib.vitro.webapp.search.lucene.Entity2LuceneDoc;
import edu.cornell.mannlib.vitro.webapp.search.lucene.LuceneIndexFactory;
import edu.cornell.mannlib.vitro.webapp.search.lucene.LuceneIndexer;
import edu.cornell.mannlib.vitro.webapp.utils.FlagMathUtils;
import edu.cornell.mannlib.vitro.webapp.web.TabWebUtil;
/** /**
* Produces the entity lists for tabs. * Produces the entity lists for tabs.
@ -28,7 +51,12 @@ public class TabEntitiesController extends VitroHttpServlet {
private static final Log log = LogFactory.getLog(TabEntitiesController.class.getName()); private static final Log log = LogFactory.getLog(TabEntitiesController.class.getName());
public static int TAB_DEPTH_CUTOFF = 3; public static int TAB_DEPTH_CUTOFF = 3;
public static int MAX_PAGES = 40; //must be even
public static int DEFAULT_NUMBER_INDIVIDUALS_ON_TAB = 8;
private static int MAX_RESULTS=40000;
private static int NON_PAGED_LIMIT=1000;
private static Random random = new Random();
public void doPost(HttpServletRequest request, HttpServletResponse response) public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { throws ServletException, IOException {
doGet(request, response); doGet(request, response);
@ -50,147 +78,514 @@ public class TabEntitiesController extends VitroHttpServlet {
which we are doing entities. which we are doing entities.
leadingTab = 1, child of leadingTab = 2, etc. leadingTab = 1, child of leadingTab = 2, etc.
"alpha" if set to an uppercase letter entities will be filtered "alpha" if set to a letter entities will be filtered
to have only that initial. to have only that initial.
bdc34 2006-01-12 created bdc34 2006-01-12 created
bdc34 2010-09-17 modified to use lucene for some tasks.
*
*/ */
public void doGet( HttpServletRequest req, HttpServletResponse response ) public void doGet( HttpServletRequest req, HttpServletResponse response )
throws IOException, ServletException { throws IOException, ServletException {
//this will setup the portal super.doGet(req,response);
super.doGet(req,response);
VitroRequest request = new VitroRequest(req);
String obj = null; try{
try { VitroRequest request = new VitroRequest(req);
obj = request.getParameter("tabDepth"); TabDao tabDao = request.getWebappDaoFactory().getTabDao();
if( obj == null ){
String e="TabEntitesController expects that request parameter 'tabDepth' be set" int depth = getTabDepth(request);
+", use 1 as the leading tab's depth."; if( depth >= TAB_DEPTH_CUTOFF){
throw new ServletException(e); String tabId = request.getParameter("tabId");
} log.debug("\ttab "+tabId+" is at, "+ depth+" below "+ TAB_DEPTH_CUTOFF);
int depth = Integer.parseInt((String)obj); return;
if( depth >= TAB_DEPTH_CUTOFF){ }
String tabId = request.getParameter("tabId"); String tabId = request.getParameter("tabId");
log.debug("\ttab "+tabId+" is at, "+ depth+" below "+ TAB_DEPTH_CUTOFF); if( tabId == null ){
return; String e="TabEntitiesController expects that request parameter 'tabId' be set";
} throw new ServletException(e);
}
String tabId = request.getParameter("tabId");
if( tabId == null ){ Tab tab = TabWebUtil.findStashedTab(tabId,request);
String e="TabEntitiesController expects that request parameter 'tabId' be set"; if( tab == null ){
throw new ServletException(e); String e="TabEntitiesController expects that tab"+tabId+" will be in the request attribute. "
} +"It should have been placed there by a call to TabWebUtil.stashTabsInRequest in tabPrimary.jsp";
throw new ServletException(e);
Tab tab = TabWebUtil.findStashedTab(tabId,request); }
if( tab == null ){ req.setAttribute("tabId", tab.getTabId());
String e="TabEntitiesController expects that tab"+tabId+" will be in the request attribute. " request.setAttribute("controllerParam","primary=" + tab.getTabId());
+"It should have been placed there by a call to TabWebUtil.stashTabsInRequest in "
+"tabPrimary.jsp"; String alpha = request.getParameter("alpha");
throw new ServletException(e); boolean doAlphaFilter = false;
} if(( alpha != null && alpha.length() == 1) ){
doAlphaFilter = true;
String alpha = request.getParameter("alpha"); request.setAttribute("alpha", alpha.toUpperCase());
boolean doAlphaFilter = false; }
if(( alpha != null && alpha.length() == 1) || tab.getGalleryRows()>1)
/* bjl23 20061006: boolean doPagedFilter = request.getParameter("page") != null;
* The tab.getGalleryRows()>1 is a hack to use this field as boolean showPaged = true;
* a switch to turn on alpha filter display in if( tab.getGalleryRows() != 1 ){
* non-gallery tabs. We need to add a db field for this. */ /* bjl23 20061006: The tab.getGalleryRows()>1 is a hack to use this field as a switch to turn on
doAlphaFilter = true; * alpha filter display in non-gallery tabs. We need to add a db field for this. */
request.setAttribute("showAlpha","1");
//now we have the parameteres from the request, showPaged = true;
//branch to the different types of ways to handle things }
if(depth == 1 && tab.isGallery() && !doAlphaFilter){
doGallery(tab, request,response); List<String> manuallyLinkedUris = Collections.emptyList();
}else if( tab.isGallery() || doAlphaFilter ){ List<String> autoLinkedUris = Collections.emptyList();
doAlphaFiltered(alpha,tab,request,response); if( tab.isAutoLinked() || tab.isMixedLinked())
}else if( tab.isManualLinked() ){ autoLinkedUris = request.getWebappDaoFactory().getTabDao().getTabAutoLinkedVClassURIs(tab.getTabId());
doManual(tab, request, response); if( tab.isManualLinked() || tab.isMixedLinked())
}else if( tab.isAutoLinked() ){ manuallyLinkedUris = request.getWebappDaoFactory().getTabDao().getTabManuallyLinkedEntityURIs(tab.getTabId());
doAutoLinked( tab, request, response);
}else if( tab.isMixedLinked() ){ //If a tab is not linked to any types or individuals, don't show alpha or page filter links
doAutoLinked( tab, request, response); boolean tabNotLinked = tabNotLinked( tab, autoLinkedUris, manuallyLinkedUris);
}else{ if( tabNotLinked ){
//what to do here when the entity link mod is unknown? request.setAttribute("showAlpha", "0");
log.debug("TabEntitiesController: doing none for tabtypeid: "+ tab.getTabtypeId() +" and link mode: " + tab.getEntityLinkMethod()); showPaged = false;
} }
} catch (Throwable e) {
request.setAttribute("javax.servlet.jsp.jspException",e); int page = getPage(request);
RequestDispatcher rd = request.getRequestDispatcher("/error.jsp"); int entsPerTab = getSizeForNonGalleryTab(tab, showPaged);
rd.include(request, response);
int size = 0;
if( ! tabNotLinked ){
try{
//a lot of the work happens in this next line
size = addLinkedIndividualsForTab (tab,request, autoLinkedUris, manuallyLinkedUris,
alpha, page, entsPerTab, depth, doAlphaFilter, doPagedFilter);
}catch(Exception e){
log.warn(e,e);
}
}
//only show page list when the tab is depth 1.
if( showPaged && depth == 1 && size > 0 && size > entsPerTab ){
request.setAttribute("showPages",Boolean.TRUE);
//make a data structure to hold information about paged tabs
request.setAttribute("pages", makePagesList(size, entsPerTab, page ));
}else{
request.setAttribute("showPages",Boolean.FALSE);
}
if( tab.isAutoLinked() || tab.isGallery() ){
if( doAlphaFilter ){
doAlphaFiltered(alpha, tab, request, response, tabDao, size);
}else{
doAutoLinked( tab, request, response, tabDao, size);
}
}else if( tab.isMixedLinked() || tab.isManualLinked() ){
doAutoLinked(tab,request,response,tabDao,size);
}else{
log.debug("TabEntitiesController: doing none for tabtypeid: "
+ tab.getTabtypeId() +" and link mode: " + tab.getEntityLinkMethod());
}
} catch (Throwable e) {
req.setAttribute("javax.servlet.jsp.jspException",e);
RequestDispatcher rd = req.getRequestDispatcher("/error.jsp");
rd.include(req, response);
} }
} }
/**
* This build a lucene query for the tab, runs the query, gets individuals for that query,
* and adds the individuals to the tab.
*
* @param tab - this parameter is mutated by this method
* @param request
* @param autoLinkedUris
* @param manuallyLinkedUris
* @param alpha - letter for alpha filtering
* @param page - page for page filtering
* @param entsPerTab
* @param depth
* @param doAlphaFilter
* @param doPagedFilter
* @return total number of ents associated with tab regardless of filtering
*/
private int addLinkedIndividualsForTab(Tab tab, VitroRequest request,
List<String> autoLinkedUris, List<String> manuallyLinkedUris,
String alpha, int page, int entsPerTab, int depth,
boolean doAlphaFilter , boolean doPagedFilter) {
//try to get the URIs of the required individuals from the lucene index
IndexSearcher index = LuceneIndexFactory.getIndexSearcher(getServletContext());
boolean isSinglePortal = request.getWebappDaoFactory().getPortalDao().isSinglePortal();
BooleanQuery query = null;
if( tab.isAutoLinked() ){
query = getQuery(tab, autoLinkedUris, null, alpha, isSinglePortal);
}else if (tab.isManualLinked() ){
query = getQuery(tab, null, manuallyLinkedUris, alpha, isSinglePortal);
}else if ( tab.isMixedLinked() ){
query = getQuery(tab, autoLinkedUris, manuallyLinkedUris, alpha, isSinglePortal);
}else{
log.error("Tab " + tab.getTabId() + " is neither manually, auto nor mixed. ");
}
if( tab.getDayLimit() != 0 ){
query = addDayLimit( query, tab );
}
boolean onlyWithThumbImg = false;
if( depth > 1 && tab.getImageWidth() > 0 ){
onlyWithThumbImg = true;
}
IndividualDao indDao = request.getWebappDaoFactory().getIndividualDao();
int size = 0;
try {
String sortField = tab.getEntitySortField();
Sort sort = null;
if( sortField != null && !doAlphaFilter && !doPagedFilter ){
if( sortField.equalsIgnoreCase("timekey") || tab.getDayLimit() > 0){
sort = new Sort(Entity2LuceneDoc.term.TIMEKEY);
}else if( sortField.equalsIgnoreCase("sunrise") || tab.getDayLimit() < 0 ){
sort = new Sort(Entity2LuceneDoc.term.SUNRISE, true);
}else if( sortField.equalsIgnoreCase("sunset") ){
sort = new Sort(Entity2LuceneDoc.term.SUNSET);
}else{
sort = new Sort(Entity2LuceneDoc.term.NAMEUNANALYZED);
}
} else {
sort = new Sort(Entity2LuceneDoc.term.NAMEUNANALYZED);
}
if( depth > 1 && "rand()".equalsIgnoreCase(sortField) ){
sort = null;
}
TopDocs docs;
if( sort != null )
docs = index.search(query, null, MAX_RESULTS, sort);
else
docs = index.search(query, null, MAX_RESULTS);
if( docs == null ){
log.error("Search of lucene index returned null");
return 0;
}
size = docs.totalHits;
// don't get all the results, only get results for the requestedSize
List<Individual> results = new ArrayList<Individual>(entsPerTab);
int entsAddedToTab = 0;
int ii = (page-1)*entsPerTab;
boolean doingRandom = false;
if( !doAlphaFilter && !doPagedFilter && depth > 1 && size > 1 && "rand()".equalsIgnoreCase(tab.getEntitySortField())){
doingRandom = true;
ii = random.nextInt( size );
}
boolean looped = false;
while( entsAddedToTab < entsPerTab && ii < docs.scoreDocs.length ){
ScoreDoc hit = docs.scoreDocs[ii];
if (hit != null) {
Document doc = index.doc(hit.doc);
if (doc != null) {
if( onlyWithThumbImg && "0".equals(doc.getField(Entity2LuceneDoc.term.THUMBNAIL).stringValue()) ){
//do Nothing
}else{
String uri = doc.getField(Entity2LuceneDoc.term.URI).stringValue();
Individual ind = indDao.getIndividualByURI( uri );
results.add( ind );
entsAddedToTab++;
}
} else {
log.warn("no document found for lucene doc id " + hit.doc);
}
} else {
log.debug("hit was null");
}
if( doingRandom && ii >= docs.scoreDocs.length && ! looped){
ii=0;
looped = true;
}else{
ii++;
}
}
//mutate state of tab
tab.setRelatedEntityList(results);
}catch(IOException ex){
log.warn(ex,ex);
return size;
}
return size;
}
private boolean tabNotLinked(Tab tab, List<String> autoLinkedUris,
List<String> manuallyLinkedUris) {
if( tab.isManualLinked() )
return manuallyLinkedUris.isEmpty();
else if( tab.isAutoLinked() )
return autoLinkedUris.isEmpty();
else
return autoLinkedUris.isEmpty() && manuallyLinkedUris.isEmpty();
}
private BooleanQuery addDayLimit(BooleanQuery query, Tab tab) {
DateTime now = new DateTime();
if( tab.getDayLimit() > 0 ){
String start = now.toString(LuceneIndexer.DATE_FORMAT);
String future = now.plusDays( tab.getDayLimit() ).toString(LuceneIndexer.DATE_FORMAT);
query.add( new RangeQuery(new Term(Entity2LuceneDoc.term.TIMEKEY,start),new Term(Entity2LuceneDoc.term.TIMEKEY,future), true) , BooleanClause.Occur.MUST);
}else{
String end = now.toString(LuceneIndexer.DATE_FORMAT);
String past = now.minusDays( tab.getDayLimit() ).toString(LuceneIndexer.DATE_FORMAT);
query.add( new RangeQuery(new Term(Entity2LuceneDoc.term.SUNRISE,past),new Term(Entity2LuceneDoc.term.SUNRISE,end), true) , BooleanClause.Occur.MUST);
}
return query;
}
private void doAlphaFiltered(String alpha, Tab tab, private void doAlphaFiltered(String alpha, Tab tab,
HttpServletRequest request, HttpServletResponse response) VitroRequest request, HttpServletResponse response, TabDao tabDao, int size)
throws ServletException, IOException { throws ServletException, IOException {
Collection ents = tab.getRelatedEntityList(alpha); log.debug("in doAlphaFitlered");
if( ents != null ) {
request.setAttribute("entities", ents); request.setAttribute("entities", tab.getRelatedEntities());
request.setAttribute("alpha",alpha); request.setAttribute("alpha", alpha);
request.setAttribute("count",tab.grabEntityFactory().getRelatedEntityCount()+""); request.setAttribute("count", Integer.toString(size) );
request.setAttribute("tabParam",tab.getTabDepthName()+"="+tab.getTabId()); request.setAttribute("tabParam",tab.getTabDepthName()+"="+tab.getTabId());
request.setAttribute("letters",tab.grabEntityFactory().getLettersOfEnts()); request.setAttribute("letters",Controllers.getLetters());
request.setAttribute("servlet",Controllers.TAB); //request.setAttribute("letters",tab.grabEntityFactory().getLettersOfEnts());
String jsp = Controllers.ENTITY_LIST_FOR_TABS_JSP; request.setAttribute("servlet",Controllers.TAB);
RequestDispatcher rd = String jsp = Controllers.ENTITY_LIST_FOR_TABS_JSP;
request.getRequestDispatcher(jsp); RequestDispatcher rd =
rd.include(request, response); request.getRequestDispatcher(jsp);
}else{ rd.include(request, response);
//no entities, do nothing }
}
} private void doAutoLinked(Tab tab, VitroRequest request, HttpServletResponse response, TabDao tabDao, int size)
throws ServletException, IOException {
log.debug("in doAutoLinked");
request.setAttribute("entities", tab.getRelatedEntities());
request.setAttribute("count", Integer.toString(size));
request.setAttribute("tabParam",tab.getTabDepthName()+"="+tab.getTabId());
request.setAttribute("letters",Controllers.getLetters());
request.setAttribute("servlet",Controllers.TAB);
String jsp = Controllers.ENTITY_LIST_FOR_TABS_JSP;
RequestDispatcher rd =
request.getRequestDispatcher(jsp);
rd.include(request, response);
}
private void doGallery(Tab tab, HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Collection ents = tab.getRelatedEntityList(null);
if( ents != null && ents.size() > 0){
request.setAttribute("entities", ents);
request.setAttribute("rows", tab.getGalleryRows());
request.setAttribute("columns", tab.getGalleryCols());
String jsp = Controllers.TAB_ENTITIES_LIST_GALLERY_JSP;
RequestDispatcher rd =
request.getRequestDispatcher(jsp);
rd.include(request, response);
}else{
doAutoLinked(tab,request,response);
}
}
private void doAutoLinked(Tab tab, HttpServletRequest request, HttpServletResponse response) private int getPage(VitroRequest request) {
throws ServletException, IOException { String p = request.getParameter("page") ;
Collection ents = tab.getRelatedEntityList(null); if( p == null )
if( ents != null && ents.size() > 0 ) { return 1;
request.setAttribute("entities", ents); try{
request.setAttribute("alpha","none"); return Integer.parseInt(p);
request.setAttribute("count",tab.getAlphaUnfilteredEntityCount()+""); }catch(Exception e){
request.setAttribute("tabParam",tab.getTabDepthName()+"="+tab.getTabId()); return 1;
request.setAttribute("letters",Controllers.getLetters()); }
request.setAttribute("servlet",Controllers.TAB);
String jsp = Controllers.ENTITY_LIST_FOR_TABS_JSP;
RequestDispatcher rd =
request.getRequestDispatcher(jsp);
rd.include(request, response);
}else{
//no entities, do nothing
}
} }
private void doManual(Tab tab, HttpServletRequest request, HttpServletResponse response) /**
throws ServletException, IOException { * Mixed and auto linked tabs get their individuals via
Collection ents = tab.getRelatedEntityList(null); * a query to the lucene index. This is to allow sorting and alpha
if( ents != null && ents.size() > 0 ) { * filtering of the combined list. Manually linked tabs do not
request.setAttribute("entities", ents); * get their individuals using lucene, see doManual().
String jsp = Controllers.ENTITY_LIST_FOR_TABS_JSP; *
RequestDispatcher rd = */
request.getRequestDispatcher(jsp); private BooleanQuery getQuery(Tab tab, List<String> vclassUris, List<String> manualUris, String alpha , boolean isSinglePortal){
rd.include(request, response); BooleanQuery query = new BooleanQuery();
}else{ try{
//no entities, do nothing
} //make the type query if needed
BooleanQuery typeQuery = null;
if( tab.isAutoLinked() || tab.isMixedLinked() ){
typeQuery = new BooleanQuery();
BooleanQuery queryForTypes = new BooleanQuery();
//setup up type queries in their own sub query
for( String vclassUri : vclassUris ){
if( vclassUri != null && !"".equals(vclassUri)){
queryForTypes.add(
new TermQuery( new Term(Entity2LuceneDoc.term.RDFTYPE, vclassUri)),
BooleanClause.Occur.SHOULD );
}
}
typeQuery.add(queryForTypes, BooleanClause.Occur.MUST);
//check for portal filtering only on auto linked queries
if( ! isSinglePortal ){
int tabPortal = tab.getPortalId();
if( tabPortal < 16 ){ //could be a normal portal
typeQuery.add(
new TermQuery( new Term(Entity2LuceneDoc.term.PORTAL, Integer.toString(1 << tab.getPortalId() ))),
BooleanClause.Occur.MUST);
}else{ //could be a combined portal
BooleanQuery tabQueries = new BooleanQuery();
Long[] ids= FlagMathUtils.numeric2numerics(tabPortal);
for( Long id : ids){
tabQueries.add(
new TermQuery( new Term(Entity2LuceneDoc.term.PORTAL,id.toString()) ),
BooleanClause.Occur.SHOULD);
}
typeQuery.add(tabQueries,BooleanClause.Occur.MUST);
}
}
String flag2Set = tab.getFlag2Set();
if( tab.getFlag2Set() != null && ! tab.getFlag2Set().isEmpty()){
if( flag2Set != null && ! "".equals(flag2Set)){
BooleanQuery flag2Query = new BooleanQuery();
for( String flag2Value : flag2Set.split(",")){
if( flag2Value != null ){
String value = flag2Value.replace(",", "");
if(!value.isEmpty()){
flag2Query.add(new TermQuery(new Term(Entity2LuceneDoc.term.FLAG2,value)),
BooleanClause.Occur.SHOULD);
}
}
}
typeQuery.add(flag2Query, BooleanClause.Occur.MUST);
}
}
}
//make query for manually linked individuals
BooleanQuery manualQuery = null;
boolean foundManual = false;
if( tab.isManualLinked() || tab.isMixedLinked()){
manualQuery = new BooleanQuery();
BooleanQuery queryForManual = new BooleanQuery();
for( String indURI : manualUris){
if( indURI != null ){
queryForManual.add(
new TermQuery( new Term(Entity2LuceneDoc.term.URI, indURI)),
BooleanClause.Occur.SHOULD );
foundManual = true;
}
}
if( foundManual )
manualQuery.add( queryForManual, BooleanClause.Occur.MUST);
}
if( tab.isAutoLinked() || !foundManual ){
query = typeQuery;
}else if ( tab.isManualLinked() ){
query = manualQuery;
}else{
BooleanQuery orQuery = new BooleanQuery();
orQuery.add( typeQuery, BooleanClause.Occur.SHOULD);
orQuery.add( manualQuery, BooleanClause.Occur.SHOULD);
query.add( orQuery, BooleanClause.Occur.MUST);
}
//Add alpha filter if it is needed
Query alphaQuery = null;
if( alpha != null && !"".equals(alpha) && alpha.length() == 1){
alphaQuery =
new PrefixQuery(new Term(Entity2LuceneDoc.term.NAMEUNANALYZED, alpha.toLowerCase()));
query.add(alphaQuery,BooleanClause.Occur.MUST);
}
log.debug("Query for tab " + tab.getTabId() + ": " + query);
return query;
}catch (Exception ex){
log.error(ex,ex);
return new BooleanQuery();
}
}
private int getSizeForGalleryTab(Tab tab){
int rows = tab.getGalleryRows() != 0 ? tab.getGalleryRows() : 8;
int col = tab.getGalleryCols() != 0 ? tab.getGalleryCols() : 8;
return rows * col;
}
private int getSizeForNonGalleryTab(Tab tab, boolean showPaged ){
if( showPaged )
if( tab.getGalleryCols() == 0 || tab.getGalleryRows() == 0 )
return 8;
else
return getSizeForGalleryTab(tab);
else
return NON_PAGED_LIMIT;
}
private int getTabDepth(VitroRequest request){
String obj = null;
try {
obj = request.getParameter("tabDepth");
if( obj == null ){
String e="TabEntitesController expects that request parameter 'tabDepth' be set"
+", use 1 as the leading tab's depth.";
throw new ServletException(e);
}
return Integer.parseInt((String)obj);
}catch(Exception ex){
return 1;
}
}
public static List<PageRecord> makePagesList( int count, int pageSize, int selectedPage){
List<PageRecord> records = new ArrayList<PageRecord>( MAX_PAGES + 1 );
int requiredPages = count/pageSize ;
int remainder = count % pageSize ;
if( remainder > 0 )
requiredPages++;
if( selectedPage < MAX_PAGES && requiredPages > MAX_PAGES ){
//the selected pages is within the first maxPages, just show the normal pages up to maxPages.
for(int page = 1; page < requiredPages && page <= MAX_PAGES ; page++ ){
records.add( new PageRecord( "page=" + page, Integer.toString(page), Integer.toString(page), selectedPage == page ) );
}
records.add( new PageRecord( "page="+ MAX_PAGES+1, Integer.toString(MAX_PAGES+1), "more...", false));
}else if( requiredPages > MAX_PAGES && selectedPage+1 > MAX_PAGES && selectedPage < requiredPages - MAX_PAGES){
//the selected pages is in the middle of the list of page
int startPage = selectedPage - MAX_PAGES / 2;
int endPage = selectedPage + MAX_PAGES / 2;
for(int page = startPage; page <= endPage ; page++ ){
records.add( new PageRecord( "page=" + page, Integer.toString(page), Integer.toString(page), selectedPage == page ) );
}
records.add( new PageRecord( "page="+ endPage+1, Integer.toString(endPage+1), "more...", false));
}else if ( requiredPages > MAX_PAGES && selectedPage > requiredPages - MAX_PAGES ){
//the selected page is in the end of the list
int startPage = requiredPages - MAX_PAGES;
double max = Math.ceil(count/pageSize);
for(int page = startPage; page <= max; page++ ){
records.add( new PageRecord( "page=" + page, Integer.toString(page), Integer.toString(page), selectedPage == page ) );
}
}else{
//there are fewer than maxPages pages.
for(int i = 1; i <= requiredPages; i++ ){
records.add( new PageRecord( "page=" + i, Integer.toString(i), Integer.toString(i), selectedPage == i ) );
}
}
return records;
}
public static class PageRecord {
public PageRecord(String param, String index, String text, boolean selected) {
this.param = param;
this.index = index;
this.text = text;
this.selected = selected;
}
public String param;
public String index;
public String text;
public boolean selected=false;
public String getParam() {
return param;
}
public String getIndex() {
return index;
}
public String getText() {
return text;
}
public boolean getSelected(){
return selected;
}
} }
} }

View file

@ -29,6 +29,7 @@ import com.hp.hpl.jena.util.iterator.ClosableIterator;
import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
import edu.cornell.mannlib.vitro.webapp.beans.Tab; import edu.cornell.mannlib.vitro.webapp.beans.Tab;
import edu.cornell.mannlib.vitro.webapp.beans.TabIndividualRelation;
import edu.cornell.mannlib.vitro.webapp.dao.TabDao; import edu.cornell.mannlib.vitro.webapp.dao.TabDao;
import edu.cornell.mannlib.vitro.webapp.dao.TabEntityFactory; import edu.cornell.mannlib.vitro.webapp.dao.TabEntityFactory;
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
@ -262,30 +263,16 @@ public class TabDaoJena extends JenaBaseDao implements TabDao {
/** /**
* returns a list of URI strings of Entities manually linked to tab (tabId) * returns a list of URI strings of Entities manually linked to tab (tabId)
*/ */
public List<String> getTabManuallyLinkedEntityURIs(int tabId) { public List<String> getTabManuallyLinkedEntityURIs(int tab_id) {
List<String> entityURIs = new LinkedList<String>(); List<String> entityURIs = new LinkedList<String>();
// getOntModel().enterCriticalSection(Lock.READ); TabIndividualRelationDaoJena tabToIndDao = new TabIndividualRelationDaoJena( getWebappDaoFactory() );
// try { List<TabIndividualRelation> tabsToInd = tabToIndDao.getTabIndividualRelationsByTabURI( DEFAULT_NAMESPACE+"tab"+tab_id );
// Resource tab = getOntModel().getResource(DEFAULT_NAMESPACE+"tab"+tabId); if( tabsToInd != null ){
// if (tab != null && TAB_LINKEDENTITY != null) { for( TabIndividualRelation rel : tabsToInd){
// ClosableIterator entityIt = getOntModel().listStatements(tab, TAB_LINKEDENTITY, (Resource)null); if( rel != null && rel.getEntURI() != null)
// try { entityURIs.add( rel.getEntURI() );
// while (entityIt.hasNext()) { }
// Statement st = (Statement) entityIt.next(); }
// Resource entity = (Resource) st.getObject();
// if (entity != null) {
// entityURIs.add(entity.getURI());
// }
// }
// } catch (Exception e) {
// e.printStackTrace();
// } finally {
// entityIt.close();
// }
// }
// } finally {
// getOntModel().leaveCriticalSection();
// }
return entityURIs; return entityURIs;
} }

View file

@ -18,7 +18,8 @@ import edu.cornell.mannlib.vitro.webapp.search.beans.VitroQueryFactory;
* is specified to run as a listener in the application's web.xml. * is specified to run as a listener in the application's web.xml.
* *
* @author bdc34 * @author bdc34
* *
*@deprecated Use LuceneIndexFactory instead
*/ */
public interface Searcher { public interface Searcher {

View file

@ -26,6 +26,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
* *
* @author bdc34 * @author bdc34
* *
* @deprecated there is no replacement
*/ */
public abstract class VitroHighlighter extends UnaryFunctor<String,String> { public abstract class VitroHighlighter extends UnaryFunctor<String,String> {

View file

@ -79,7 +79,9 @@ import edu.cornell.mannlib.vitro.webapp.search.beans.VitroQueryWrapper;
* are different ways of doing this. We will just get an object out * are different ways of doing this. We will just get an object out
* of the application scope. This object was set when the context * of the application scope. This object was set when the context
* started up and can be set in the web.xml. See LuceneSetup.java * started up and can be set in the web.xml. See LuceneSetup.java
* for an exmple. * for an example.
*
* @deprecated Use PagedSearchController instead.
*/ */
public class SearchController extends VitroHttpServlet{ public class SearchController extends VitroHttpServlet{
private static final Log log = LogFactory.getLog(SearchController.class.getName()); private static final Log log = LogFactory.getLog(SearchController.class.getName());

View file

@ -20,6 +20,8 @@ public class IndexBuilderThread extends Thread{
public IndexBuilderThread(IndexBuilder ib){ public IndexBuilderThread(IndexBuilder ib){
super("IndexBuilderThread"); super("IndexBuilderThread");
if( ib == null )
log.error("IndexBuilderThread needs an IndexBuilder, search is not configured.");
this.indexBuilder = ib; this.indexBuilder = ib;
} }
@ -31,8 +33,11 @@ public class IndexBuilderThread extends Thread{
return; return;
} }
if( indexBuilder == null )
log.warn("IndexBuilderThread needs a IndexBuilder, search may not be configured.");
try{ try{
if( indexBuilder.isReindexRequested() ){ if( indexBuilder != null && indexBuilder.isReindexRequested() ){
log.debug("full re-index requested"); log.debug("full re-index requested");
indexBuilder.indexRebuild(); indexBuilder.indexRebuild();
}else{ }else{

View file

@ -2,7 +2,9 @@
package edu.cornell.mannlib.vitro.webapp.search.lucene; package edu.cornell.mannlib.vitro.webapp.search.lucene;
import java.util.HashSet; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -12,15 +14,12 @@ import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.openrdf.model.vocabulary.OWL;
import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.IndividualImpl; import edu.cornell.mannlib.vitro.webapp.beans.IndividualImpl;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.beans.VClass;
import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup;
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
import edu.cornell.mannlib.vitro.webapp.search.IndexingException; import edu.cornell.mannlib.vitro.webapp.search.IndexingException;
import edu.cornell.mannlib.vitro.webapp.search.docbuilder.Obj2DocIface; import edu.cornell.mannlib.vitro.webapp.search.docbuilder.Obj2DocIface;
import edu.cornell.mannlib.vitro.webapp.utils.FlagMathUtils; import edu.cornell.mannlib.vitro.webapp.utils.FlagMathUtils;
@ -51,11 +50,15 @@ public class Entity2LuceneDoc implements Obj2DocIface{
public static String NAMEUNANALYZED = "nameunanalyzed" ; public static String NAMEUNANALYZED = "nameunanalyzed" ;
/** Name of entity, unstemmed */ /** Name of entity, unstemmed */
public static String NAMEUNSTEMMED = "nameunstemmed"; public static String NAMEUNSTEMMED = "nameunstemmed";
/** Name of portal */ /** portal ( 2 ^ portalId ) */
public static String PORTAL = "portal"; public static String PORTAL = "portal";
/** Flag 2 (legacy, only used at Cornell) */
public static String FLAG2 = "FLAG2";
/** time of index in msec since epoc */ /** time of index in msec since epoc */
public static String INDEXEDTIME= "indexedTime"; public static String INDEXEDTIME= "indexedTime";
/** time of sunset/end of entity */ /** timekey of entity in yyyymmddhhmm */
public static String TIMEKEY="TIMEKEY";
/** time of sunset/end of entity in yyyymmddhhmm */
public static String SUNSET="SUNSET"; public static String SUNSET="SUNSET";
/** time of sunrise/start of entity in yyyymmddhhmm */ /** time of sunrise/start of entity in yyyymmddhhmm */
public static String SUNRISE="SUNRISE"; public static String SUNRISE="SUNRISE";
@ -66,6 +69,8 @@ public class Entity2LuceneDoc implements Obj2DocIface{
public static String ALLTEXTUNSTEMMED = "ALLTEXTUNSTEMMED"; public static String ALLTEXTUNSTEMMED = "ALLTEXTUNSTEMMED";
/** keywords */ /** keywords */
public static final String KEYWORDS = "KEYWORDS"; public static final String KEYWORDS = "KEYWORDS";
/** Does the individual have a thumbnail image? 1=yes 0=no */
public static final String THUMBNAIL = "THUMBNAIL";
} }
private static final Log log = LogFactory.getLog(Entity2LuceneDoc.class.getName()); private static final Log log = LogFactory.getLog(Entity2LuceneDoc.class.getName());
@ -107,11 +112,13 @@ public class Entity2LuceneDoc implements Obj2DocIface{
//java class //java class
doc.add( new Field(term.JCLASS, entClassName, Field.Store.YES, Field.Index.NOT_ANALYZED)); doc.add( new Field(term.JCLASS, entClassName, Field.Store.YES, Field.Index.NOT_ANALYZED));
//Entity Name //Entity Name
if( ent.getName() != null ) if( ent.getRdfsLabel() != null )
value=ent.getName(); value=ent.getRdfsLabel();
else else{
value=""; log.debug("Skipping individual without rdfs:label " + ent.getURI());
return null;
}
Field name =new Field(term.NAME, value, Field name =new Field(term.NAME, value,
Field.Store.YES, Field.Index.ANALYZED); Field.Store.YES, Field.Index.ANALYZED);
name.setBoost( NAME_BOOST ); name.setBoost( NAME_BOOST );
@ -123,7 +130,7 @@ public class Entity2LuceneDoc implements Obj2DocIface{
doc.add( nameUn ); doc.add( nameUn );
Field nameUnanalyzed = new Field(term.NAMEUNANALYZED, value.toLowerCase(), Field nameUnanalyzed = new Field(term.NAMEUNANALYZED, value.toLowerCase(),
Field.Store.NO, Field.Index.NOT_ANALYZED); Field.Store.YES, Field.Index.NOT_ANALYZED);
doc.add( nameUnanalyzed ); doc.add( nameUnanalyzed );
//boost for entity //boost for entity
@ -200,6 +207,26 @@ public class Entity2LuceneDoc implements Obj2DocIface{
doc.add(new Field(term.SUNSET, latestTime, Field.Store.YES, Field.Index.NOT_ANALYZED)); doc.add(new Field(term.SUNSET, latestTime, Field.Store.YES, Field.Index.NOT_ANALYZED));
} }
try{
value = null;
if( ent.getTimekey() != null ){
value = (new DateTime(ent.getTimekey().getTime())).toString(LuceneIndexer.DATE_FORMAT);
doc.add(new Field(term.TIMEKEY, value, Field.Store.YES, Field.Index.NOT_ANALYZED));
}
}catch(Exception ex){
log.error("could not save timekey " + ex);
}
try{
value = null;
if( ent.getThumbUrl() != null )
doc.add(new Field(term.THUMBNAIL, "1", Field.Store.YES, Field.Index.NOT_ANALYZED));
else
doc.add(new Field(term.THUMBNAIL, "0", Field.Store.YES, Field.Index.NOT_ANALYZED));
}catch(Exception ex){
log.debug("could not index thumbnail: " + ex);
}
//time of index in millis past epoc //time of index in millis past epoc
Object anon[] = { new Long((new DateTime() ).getMillis()) }; Object anon[] = { new Long((new DateTime() ).getMillis()) };
doc.add( new Field(term.INDEXEDTIME, String.format( "%019d", anon ), doc.add( new Field(term.INDEXEDTIME, String.format( "%019d", anon ),
@ -208,7 +235,9 @@ public class Entity2LuceneDoc implements Obj2DocIface{
//portal Flags //portal Flags
doPortalFlags(ent, doc); doPortalFlags(ent, doc);
//do flag 2 legacy, only used at Cornell
doFlag2( ent, doc );
//ALLTEXT, all of the 'full text' //ALLTEXT, all of the 'full text'
String t=null; String t=null;
value =""; value ="";
@ -252,6 +281,23 @@ public class Entity2LuceneDoc implements Obj2DocIface{
return doc; return doc;
} }
/**
* Flag two is a legacy field that is used only by Cornell.
* It is related to the old portal filtering.
*/
private void doFlag2(Individual ent, Document doc) {
String flag2Set = ent.getFlag2Set();
if( flag2Set != null && ! "".equals(flag2Set)){
for( String flag2Value : flag2Set.split(",")){
if( flag2Value != null ){
String value = flag2Value.replace(",", "");
if(!value.isEmpty())
doc.add( new Field(term.FLAG2, value, Field.Store.NO, Field.Index.ANALYZED));
}
}
}
}
/** /**
* Splits up the entity's flag1 value into portal id and then * Splits up the entity's flag1 value into portal id and then
* adds the id to the doc. * adds the id to the doc.
@ -282,18 +328,21 @@ public class Entity2LuceneDoc implements Obj2DocIface{
Long[] portalIds = FlagMathUtils.numeric2numerics( ent.getFlag1Numeric() ); Long[] portalIds = FlagMathUtils.numeric2numerics( ent.getFlag1Numeric() );
if( portalIds == null || portalIds.length == 0) if( portalIds == null || portalIds.length == 0)
return; return;
log.debug("Flag 1 numeric: " + ent.getFlag1Numeric() + " for " + ent.getURI());
// System.out.print('\n'+"numeric: " + ent.getFlag1Numeric()
// + " " + Arrays.toString(portalIds) +" = ");
//
long id = -1; long id = -1;
for( Long idLong : portalIds){ for( Long idLong : portalIds){
id = idLong.longValue(); if( idLong != null ){
String numericPortal = Long.toString(id); id = idLong.longValue();
doc.add( new Field(term.PORTAL,numericPortal, String numericPortal = Long.toString(id);
Field.Store.NO, Field.Index.NOT_ANALYZED)); if( numericPortal != null ){
// System.out.print(numericPortal+" "); doc.add( new Field(term.PORTAL,numericPortal,
}/* end of portal id code */ Field.Store.NO, Field.Index.NOT_ANALYZED));
log.debug("adding portal " + numericPortal + " to " + ent.getURI());
}
}
}
} }
@SuppressWarnings("static-access") @SuppressWarnings("static-access")

View file

@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.search.lucene;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
@ -38,10 +39,11 @@ public class LuceneIndexer implements IndexerIface {
LinkedList<Obj2DocIface> obj2DocList = new LinkedList<Obj2DocIface>(); LinkedList<Obj2DocIface> obj2DocList = new LinkedList<Obj2DocIface>();
String indexDir = null; String indexDir = null;
Analyzer analyzer = null; Analyzer analyzer = null;
List<Searcher> searchers = null; List<Searcher> searchers = Collections.EMPTY_LIST;
IndexWriter writer = null; IndexWriter writer = null;
boolean indexing = false; boolean indexing = false;
HashSet<String> urisIndexed; HashSet<String> urisIndexed;
private LuceneIndexFactory luceneIndexFactory;
//JODA timedate library can use java date format strings. //JODA timedate library can use java date format strings.
//http://java.sun.com/j2se/1.3/docs/api/java/text/SimpleDateFormat.html //http://java.sun.com/j2se/1.3/docs/api/java/text/SimpleDateFormat.html
@ -70,8 +72,9 @@ public class LuceneIndexer implements IndexerIface {
public LuceneIndexer(String indexDir, List<Searcher> searchers, Analyzer analyzer ) throws IOException{ public LuceneIndexer(String indexDir, List<Searcher> searchers, Analyzer analyzer ) throws IOException{
this.indexDir = indexDir; this.indexDir = indexDir;
this.analyzer = analyzer; this.analyzer = analyzer;
this.searchers = searchers; if( searchers != null )
this.searchers = searchers;
makeIndexIfNone(); makeIndexIfNone();
} }
@ -162,11 +165,14 @@ public class LuceneIndexer implements IndexerIface {
log.info("ending index"); log.info("ending index");
if( writer != null ) if( writer != null )
writer.optimize(); writer.optimize();
//close the searcher so it will find the newly indexed documents //close the searcher so it will find the newly indexed documents
for( Searcher s : searchers){ for( Searcher s : searchers){
s.close(); s.close();
} }
//this is the call that replaces Searcher.close()
luceneIndexFactory.forceNewIndexSearcher();
} catch (IOException e) { } catch (IOException e) {
log.error("LuceneIndexer.endIndexing() - " log.error("LuceneIndexer.endIndexing() - "
+ "unable to optimize lucene index: \n" + e); + "unable to optimize lucene index: \n" + e);
@ -216,7 +222,8 @@ public class LuceneIndexer implements IndexerIface {
log.debug("added " + ind.getName() + " " + ind.getURI()); log.debug("added " + ind.getName() + " " + ind.getURI());
} }
}else{ }else{
log.debug("could not translate " + ind.getURI()); log.debug("could not translate, removing from index " + ind.getURI());
writer.deleteDocuments((Term)obj2doc.getIndexId(ind));
} }
} }
} }
@ -251,23 +258,18 @@ public class LuceneIndexer implements IndexerIface {
* clear the index by deleting the directory and make a new empty index. * clear the index by deleting the directory and make a new empty index.
*/ */
public synchronized void clearIndex() throws IndexingException{ public synchronized void clearIndex() throws IndexingException{
// if( indexing )
// throw new IndexingException("Cannot clear search index because an" +
// "index rebuild in in progress.");
log.debug("Clearing the index at "+indexDir); log.debug("Clearing the index at "+indexDir);
closeModifier(); closeModifier();
deleteDir(new File(indexDir)); deleteDir(new File(indexDir));
//might not be thread safe since searchers can try to open a new index
// for(LuceneSearcher s : searchers){
// s.close();
// }
try { try {
makeNewIndex(); makeNewIndex();
for(Searcher s : searchers){ for(Searcher s : searchers){
s.close(); s.close();
} }
//this is the call that replaces Searcher.close()
luceneIndexFactory.forceNewIndexSearcher();
} catch (IOException e) { } catch (IOException e) {
throw new IndexingException(e.getMessage()); throw new IndexingException(e.getMessage());
} }
@ -330,5 +332,8 @@ public class LuceneIndexer implements IndexerIface {
return dir.delete(); return dir.delete();
} }
public void setLuceneIndexFactory(LuceneIndexFactory lif) {
luceneIndexFactory = lif;
}
} }

View file

@ -74,23 +74,18 @@ public class LuceneSetupCJK implements javax.servlet.ServletContextListener {
HashSet objectPropertyBlacklist = new HashSet<String>(); HashSet objectPropertyBlacklist = new HashSet<String>();
objectPropertyBlacklist.add("http://www.w3.org/2002/07/owl#differentFrom"); objectPropertyBlacklist.add("http://www.w3.org/2002/07/owl#differentFrom");
context.setAttribute(LuceneSetup.SEARCH_OBJECTPROPERTY_BLACKLIST, objectPropertyBlacklist); context.setAttribute(LuceneSetup.SEARCH_OBJECTPROPERTY_BLACKLIST, objectPropertyBlacklist);
//Here we want to put the LuceneSearcher in the application scope.
// the queries need to know the analyzer to use so that the same one can be used
// to analyze the fields in the incoming user query terms.
LuceneSearcher searcher = new LuceneSearcher(
new LuceneQueryFactory(getAnalyzer(), Entity2LuceneDoc.term.ALLTEXT),
indexDir);
searcher.addObj2Doc(new Entity2LuceneDoc());
context.setAttribute(Searcher.class.getName(), searcher);
//here we want to put the LuceneIndex object into the application scope //here we want to put the LuceneIndex object into the application scope
LuceneIndexer indexer = new LuceneIndexer(indexDir, null, getAnalyzer()); LuceneIndexer indexer = new LuceneIndexer(indexDir, null, getAnalyzer());
indexer.addSearcher(searcher);
context.setAttribute(LuceneSetup.ANALYZER, getAnalyzer()); context.setAttribute(LuceneSetup.ANALYZER, getAnalyzer());
context.setAttribute(LuceneSetup.INDEX_DIR, indexDir); context.setAttribute(LuceneSetup.INDEX_DIR, indexDir);
indexer.addObj2Doc(new Entity2LuceneDoc()); indexer.addObj2Doc(new Entity2LuceneDoc());
//This is where to get a LucenIndex from. The indexer will
//need to reference this to notify it of updates to the index
LuceneIndexFactory lif = LuceneIndexFactory.getLuceneIndexFactoryFromContext(context);
indexer.setLuceneIndexFactory(lif);
//This is where the builder gets the list of places to try to //This is where the builder gets the list of places to try to
//get objects to index. It is filtered so that non-public text //get objects to index. It is filtered so that non-public text
//does not get into the search index. //does not get into the search index.

View file

@ -10,7 +10,7 @@
request attributres: request attributres:
'alpha' - set to currently displaying alpha, 'none' or 'all' 'alpha' - set to currently displaying alpha, 'none' or 'all'
'tabParam' - parameter for tab 'controllerParam' - parameter for controller
'count' - count of entites in the index 'count' - count of entites in the index
'letters' - List of STrings, letters for index. 'letters' - List of STrings, letters for index.
'servlet' - name of servlet to put in links. 'servlet' - name of servlet to put in links.
@ -32,17 +32,28 @@
portalId=portal.getPortalId(); portalId=portal.getPortalId();
} }
/**************************************************/ /**************************************************/
%> %>
<c:set var="portalId" value="<%=portalId%>" /> <c:set var="portalId" value="<%=portalId%>" />
<c:if test="${ requestScope.showAlpha == 1 }">
<c:if test="${requestScope.alpha != 'none'}">
<div class='alphaIndex'> <div class='alphaIndex'>
<c:forEach items='${requestScope.letters}' var='letter'> <c:forEach items='${requestScope.letters}' var='letter'>
<a <c:if test="${letter == requestScope.alpha}">class='selected' </c:if> href='<c:url value=".${requestScope.servlet}?home=${portalId}&amp;alpha=${letter}&amp;${requestScope.tabParam}"/>'>${letter} </a> <c:if test="${letter == requestScope.alpha}"> ${requestScope.alpha }&nbsp;</c:if>
</c:forEach> <c:if test="${letter != requestScope.alpha}">
<c:if test='${not empty requestScope.count}'> <c:url var="url" value=".${requestScope.servlet}">
(${requestScope.count}) <c:param name="alpha">${letter}</c:param>
</c:if> </c:url>
<a href='<c:url value="${url}&amp;${requestScope.controllerParam}"/>'>${letter} </a>
</c:if>
</c:forEach>
<% if( request.getAttribute("alpha") != null && ! "all".equalsIgnoreCase((String)request.getAttribute("alpha"))) { %>
<a href='<c:url value=".${requestScope.servlet}?&amp;alpha=all&amp;${requestScope.controllerParam}"/>'>all </a>
<c:if test='${not empty requestScope.count }'>
(${requestScope.count} that start with ${requestScope.alpha })
</c:if>
<% }else{ %>
(${requestScope.count})
<% } %>
</div> </div>
</c:if> </c:if>