001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.search; 020 021import java.net.MalformedURLException; 022import java.net.URL; 023import java.util.Iterator; 024import java.util.Map; 025import java.util.Map.Entry; 026 027import lucee.commons.collection.MapFactory; 028import lucee.commons.io.FileUtil; 029import lucee.commons.io.log.Log; 030import lucee.commons.io.res.Resource; 031import lucee.commons.io.res.util.ResourceUtil; 032import lucee.commons.lang.StringUtil; 033import lucee.commons.lock.KeyLock; 034import lucee.commons.lock.Lock; 035import lucee.commons.net.HTTPUtil; 036import lucee.runtime.PageContext; 037import lucee.runtime.config.ConfigImpl; 038import lucee.runtime.exp.DatabaseException; 039import lucee.runtime.exp.PageException; 040import lucee.runtime.op.Caster; 041import lucee.runtime.type.ArrayImpl; 042import lucee.runtime.type.Collection.Key; 043import lucee.runtime.type.KeyImpl; 044import lucee.runtime.type.Query; 045import lucee.runtime.type.QueryColumn; 046import lucee.runtime.type.QueryImpl; 047import lucee.runtime.type.dt.DateTime; 048import lucee.runtime.type.dt.DateTimeImpl; 049import lucee.runtime.type.util.ArrayUtil; 050import lucee.runtime.type.util.KeyConstants; 051import lucee.runtime.type.util.ListUtil; 052 053import org.w3c.dom.Element; 054 055/** 056 * represent a single Collection 057 */ 058public abstract class SearchCollectionSupport implements SearchCollectionPlus { 059 060 private static final long serialVersionUID = 8089312879341384114L; 061 062 private static final int LOCK_TIMEOUT = 10*60*1000; // ten minutes 063 private final String name; 064 private final Resource path; 065 private String language; 066 private DateTime lastUpdate; 067 private SearchEngineSupport searchEngine; 068 //TODO change visibility to private 069 protected Map<String,SearchIndex> indexes=MapFactory.<String,SearchIndex>getConcurrentMap(); 070 071 private DateTime created; 072 073 private Log log; 074 //private static LockManager manager=Lock Manager Impl.getInstance(); 075 private KeyLock<String> lock=new KeyLock<String>(); 076 077 078 /** 079 * constructor of the class 080 * @param searchEngine 081 * @param name name of the Collection 082 * @param path 083 * @param language 084 * @param count total count of documents in the collection 085 * @param lastUpdate 086 * @param created 087 */ 088 public SearchCollectionSupport(SearchEngineSupport searchEngine, String name,Resource path, String language, DateTime lastUpdate, DateTime created) { 089 this.searchEngine=searchEngine; 090 this.name=name; 091 this.path=path; 092 this.language=SearchUtil.translateLanguage(language); 093 this.lastUpdate=lastUpdate; 094 this.created=created; 095 096 log=((ConfigImpl)searchEngine.getConfig()).getLog("search"); 097 } 098 099 @Override 100 public final void create() throws SearchException { 101 Lock l = lock(); 102 try { 103 _create(); 104 } 105 finally { 106 unlock(l); 107 } 108 } 109 110 /** 111 * create a collection 112 * @throws SearchException 113 */ 114 protected abstract void _create() throws SearchException; 115 116 @Override 117 public final void optimize() throws SearchException { 118 Lock l = lock(); 119 try { 120 _optimize(); 121 changeLastUpdate(); 122 } 123 finally { 124 unlock(l); 125 } 126 } 127 128 /** 129 * optimize a Collection 130 * @throws SearchException 131 */ 132 protected abstract void _optimize() throws SearchException ; 133 134 @Override 135 public final void map(Resource path) throws SearchException { 136 Lock l = lock(); 137 try { 138 _map(path); 139 changeLastUpdate(); 140 } 141 finally { 142 unlock(l); 143 } 144 } 145 146 /** 147 * map a Collection 148 * @param path 149 * @throws SearchException 150 */ 151 protected abstract void _map(Resource path) throws SearchException ; 152 153 @Override 154 public final void repair() throws SearchException { 155 Lock l = lock(); 156 try { 157 _repair(); 158 changeLastUpdate(); 159 } 160 finally { 161 unlock(l); 162 } 163 } 164 165 /** 166 * repair a Collection 167 * @throws SearchException 168 */ 169 protected abstract void _repair() throws SearchException ; 170 171 @Override 172 public IndexResult index(PageContext pc, String key, short type, String urlpath, String title, String body, String language, 173 String[] extensions, String query, boolean recurse,String categoryTree, String[] categories, 174 String custom1, String custom2, String custom3, String custom4) throws PageException, MalformedURLException, SearchException { 175 return index(pc, key, type, urlpath, title, body, language, extensions, query, recurse, categoryTree, categories, 10000, custom1, custom2, custom3, custom4); 176 } 177 178 // FUTURE add this to interface 179 public IndexResult index(PageContext pc, String key, short type, String urlpath, String title, String body, String language, 180 String[] extensions, String query, boolean recurse,String categoryTree, String[] categories, long timeout, 181 String custom1, String custom2, String custom3, String custom4) throws PageException, MalformedURLException, SearchException { 182 language=SearchUtil.translateLanguage(language); 183 Lock l = lock(); 184 try { 185 SearchIndex si = new SearchIndex(title,key,type,query,extensions,language,urlpath,categoryTree,categories,custom1,custom2,custom3,custom4); 186 String id=si.getId(); 187 IndexResult ir=IndexResultImpl.EMPTY; 188 if(type==SearchIndex.TYPE_FILE){ 189 Resource file=ResourceUtil.toResourceNotExisting(pc,key); 190 if(!file.isFile())throw new SearchException("value of attribute key must specify a existing file, ["+key+"] is invalid"); 191 ir=indexFile(id,title,file,language); 192 } 193 else if(type==SearchIndex.TYPE_PATH){ 194 Resource dir=ResourceUtil.toResourceNotExisting(pc,key); 195 if(!dir.isDirectory())throw new SearchException("value of attribute key must specify a existing directory, ["+key+"] is invalid"); 196 ir=indexPath(id,title,dir,extensions,recurse,language); 197 } 198 else if(type==SearchIndex.TYPE_URL) { 199 ir=indexURL(id,title,new URL(key),extensions,recurse,language,timeout); 200 } 201 else if(type==SearchIndex.TYPE_CUSTOM) { 202 Query qv; 203 if(StringUtil.isEmpty(query)){ 204 205 // set columns 206 lucee.runtime.type.Array columns=new ArrayImpl(); 207 columns.append("key"); 208 columns.append("body"); 209 if(!StringUtil.isEmpty(title))columns.append("title"); 210 if(!StringUtil.isEmpty(urlpath))columns.append("urlpath"); 211 if(!StringUtil.isEmpty(custom1))columns.append("custom1"); 212 if(!StringUtil.isEmpty(custom2))columns.append("custom2"); 213 if(!StringUtil.isEmpty(custom3))columns.append("custom3"); 214 if(!StringUtil.isEmpty(custom4))columns.append("custom4"); 215 216 // populate query with a single row 217 qv=new QueryImpl(columns,1,"query"); 218 // body 219 qv.setAt(KeyConstants._key, 1, key); 220 key="key"; 221 222 // body 223 qv.setAt(KeyConstants._body, 1, body); 224 body="body"; 225 226 // title 227 if(!StringUtil.isEmpty(title)){ 228 qv.setAt(KeyConstants._title, 1, title); 229 title="title"; 230 } 231 232 // urlpath 233 if(!StringUtil.isEmpty(urlpath)){ 234 qv.setAt("urlpath", 1, urlpath); 235 urlpath="urlpath"; 236 } 237 238 // custom1 239 if(!StringUtil.isEmpty(custom1)){ 240 qv.setAt("custom1", 1, custom1); 241 custom1="custom1"; 242 } 243 // custom2 244 if(!StringUtil.isEmpty(custom2)){ 245 qv.setAt("custom2", 1, custom2); 246 custom2="custom2"; 247 } 248 // custom3 249 if(!StringUtil.isEmpty(custom3)){ 250 qv.setAt("custom3", 1, custom3); 251 custom3="custom3"; 252 } 253 // custom4 254 if(!StringUtil.isEmpty(custom4)){ 255 qv.setAt("custom4", 1, custom4); 256 custom4="custom4"; 257 } 258 } 259 else qv = Caster.toQuery(pc.getVariable(query)); 260 261 QueryColumn keyColumn=qv.getColumn(key); 262 263 String[] strBodies=ListUtil.toStringArrayTrim(ListUtil.listToArrayRemoveEmpty(body,',')); 264 QueryColumn[] bodyColumns=new QueryColumn[strBodies.length]; 265 for(int i=0;i<bodyColumns.length;i++) { 266 bodyColumns[i]=qv.getColumn(strBodies[i]); 267 } 268 269 ir= indexCustom(id, 270 getValue(qv,title), 271 keyColumn, 272 bodyColumns, 273 language, 274 getValue(qv,urlpath), 275 getValue(qv,custom1), 276 getValue(qv,custom2), 277 getValue(qv,custom3), 278 getValue(qv,custom4)); 279 } 280 createIndex(si); 281 return ir; 282 } 283 finally { 284 unlock(l); 285 } 286 } 287 288 private QueryColumn getColumnEL(Query query, String column) { 289 if(StringUtil.isEmpty(column)) return null; 290 QueryColumn c = query.getColumn(column,null); 291 292 return c; 293 } 294 295 private Object getValue(Query query, String column) { 296 if(StringUtil.isEmpty(column)) return null; 297 QueryColumn c = query.getColumn(column,null); 298 if(c==null) return column; 299 return c; 300 } 301 302 @Override 303 public final IndexResult indexFile(String id,String title, Resource res, String language) throws SearchException { 304 IndexResult ir=_indexFile(id,title,res,language); 305 changeLastUpdate(); 306 return ir; 307 } 308 309 /** 310 * updates a collection with a file 311 * @param id 312 * @param title 313 * @param file 314 * @param language 315 * @throws SearchException 316 */ 317 protected abstract IndexResult _indexFile(String id, String title, Resource file, String language) throws SearchException; 318 319 @Override 320 public final IndexResult indexPath(String id, String title, Resource dir, String[] extensions, boolean recurse, String language) throws SearchException { 321 IndexResult ir=_indexPath(id,title,dir,extensions,recurse,language); 322 changeLastUpdate(); 323 return ir; 324 } 325 326 327 /** 328 * updates a collection with a path 329 * @param id 330 * @param title 331 * @param dir 332 * @param recurse 333 * @param extensions 334 * @param language 335 * @throws SearchException 336 */ 337 protected abstract IndexResult _indexPath(String id,String title, Resource dir, String[] extensions, boolean recurse, String language) throws SearchException; 338 339 @Override 340 public final IndexResult indexURL(String id,String title, URL url, String[] extensions, boolean recurse, String language) throws SearchException { 341 return indexURL(id, title, url, extensions, recurse, language, 10000); 342 } 343 // FUTURE replace this in interface with method above 344 public final IndexResult indexURL(String id,String title, URL url, String[] extensions, boolean recurse, String language,long timeout) throws SearchException { 345 IndexResult ir=_indexURL(id,title,url,extensions,recurse,language,timeout); 346 changeLastUpdate(); 347 return ir; 348 } 349 350 /** 351 * updates a collection with a url 352 * @param id 353 * @param title 354 * @param recurse 355 * @param extensions 356 * @param url 357 * @param language 358 * @throws SearchException 359 */ 360 protected abstract IndexResult _indexURL(String id,String title, URL url, String[] extensions, boolean recurse, String language,long timeout) throws SearchException ; 361 362 protected abstract IndexResult _indexURL(String id,String title, URL url, String[] extensions, boolean recurse, String language) throws SearchException ; 363 364 @Override 365 public final IndexResult indexCustom(String id, QueryColumn title, QueryColumn keyColumn, QueryColumn[] bodyColumns, String language, 366 QueryColumn custom1, QueryColumn custom2, QueryColumn custom3, QueryColumn custom4) throws SearchException { 367 IndexResult ir=_indexCustom(id,title,keyColumn,bodyColumns,language,null,custom1,custom2,custom3,custom4); 368 changeLastUpdate(); 369 return ir; 370 } 371 /*public final IndexResult indexCustom(String id, QueryColumn title, QueryColumn keyColumn, QueryColumn[] bodyColumns, String language, 372 QueryColumn urlpath,QueryColumn custom1, QueryColumn custom2, QueryColumn custom3, QueryColumn custom4) throws SearchException { 373 IndexResult ir=_indexCustom(id,title,keyColumn,bodyColumns,language,urlpath,custom1,custom2,custom3,custom4); 374 changeLastUpdate(); 375 return ir; 376 }*/ 377 public final IndexResult indexCustom(String id, Object title, QueryColumn keyColumn, QueryColumn[] bodyColumns, String language, 378 Object urlpath,Object custom1, Object custom2, Object custom3, Object custom4) throws SearchException { 379 IndexResult ir=_indexCustom(id,title,keyColumn,bodyColumns,language,urlpath,custom1,custom2,custom3,custom4); 380 changeLastUpdate(); 381 return ir; 382 } 383 384 385 public final IndexResult deleteCustom(String id, QueryColumn keyColumn) throws SearchException { 386 IndexResult ir = _deleteCustom(id,keyColumn); 387 changeLastUpdate(); 388 return ir; 389 } 390 391 protected abstract IndexResult _deleteCustom(String id, QueryColumn keyColumn) throws SearchException; 392 393 /** 394 * updates a collection with a custom 395 * @param id 396 * @param title Title for the Index 397 * @param keyColumn Key Column 398 * @param bodyColumns Body Column Array 399 * @param language Language for index 400 * @param custom1 401 * @param custom2 402 * @param custom3 403 * @param custom4 404 * @throws SearchException 405 */ 406 //protected abstract IndexResult _indexCustom(String id,QueryColumn title, QueryColumn keyColumn, QueryColumn[] bodyColumns, String language, QueryColumn custom1, QueryColumn custom2, QueryColumn custom3, QueryColumn custom4) throws SearchException; 407 protected abstract IndexResult _indexCustom( 408 String id,Object title, QueryColumn keyColumn, QueryColumn[] bodyColumns, String language, Object urlpath 409 , Object custom1, Object custom2, Object custom3, Object custom4) throws SearchException; 410 411 /** 412 * @param index 413 * @throws SearchException 414 */ 415 private void createIndex(SearchIndex index) throws SearchException { 416 Iterator<String> it = indexes.keySet().iterator(); 417 SearchIndex otherIndex=null; 418 419 while(it.hasNext()) { 420 Object key=it.next(); 421 if(key.equals(index.getId())) { 422 otherIndex=indexes.get(key); 423 break; 424 } 425 } 426 427 Element collElement=searchEngine.getCollectionElement(name); 428 429 // Insert 430 if(otherIndex==null) { 431 addIndex(index); 432 collElement.appendChild(searchEngine.toElement(index)); 433 } 434 // Update 435 else { 436 addIndex(index); 437 Element el=searchEngine.getIndexElement(collElement,index.getId()); 438 searchEngine.setAttributes(el,index); 439 } 440 changeLastUpdate(); 441 } 442 443 /** 444 * @param index 445 */ 446 public void addIndex(SearchIndex index) { 447 indexes.put(index.getId(),index); 448 } 449 450 @Override 451 public final String getLanguage() { 452 return language; 453 } 454 455 @Override 456 public final IndexResult purge() throws SearchException { 457 Lock l = lock(); 458 try { 459 indexes.clear(); 460 IndexResult ir=_purge(); 461 searchEngine.purgeCollection(this); 462 changeLastUpdate(); 463 return ir; 464 } 465 finally { 466 unlock(l); 467 } 468 } 469 470 /** 471 * purge a collection 472 * @throws SearchException 473 */ 474 protected abstract IndexResult _purge() throws SearchException; 475 476 @Override 477 public final IndexResult delete() throws SearchException { 478 Lock l = lock(); 479 try { 480 IndexResult ir=_delete(); 481 searchEngine.removeCollection(this); 482 return ir; 483 } 484 finally { 485 unlock(l); 486 } 487 } 488 489 /** 490 * delete the collection from a file 491 * @throws SearchException 492 */ 493 protected abstract IndexResult _delete() throws SearchException; 494 495 @Override 496 public final IndexResult deleteIndex(PageContext pc,String key,short type,String queryName) throws SearchException { 497 //if(queryName==null) queryName=""; 498 Key k; 499 500 if(type==SearchIndex.TYPE_CUSTOM) { 501 // delete all when no key is defined 502 if(StringUtil.isEmpty(key,true)) 503 return deleteIndexNotCustom(pc, key, type, queryName); 504 505 try{ 506 Query qv; 507 if(!StringUtil.isEmpty(queryName)) { 508 k=KeyImpl.init(key); 509 qv = Caster.toQuery(pc.getVariable(queryName)); 510 } 511 else { 512 k=KeyConstants._id; 513 Key[] cols = new Key[]{k}; 514 String[] types = new String[]{"VARCHAR"}; 515 qv=new QueryImpl(cols,types, 1,"query"); 516 qv.setAtEL(k, 1, key); 517 } 518 519 520 521 QueryColumn keyColumn=qv.getColumn(k); 522 return deleteCustom("custom", keyColumn); 523 } 524 catch(PageException pe){ 525 throw new SearchException(pe); 526 } 527 } 528 return deleteIndexNotCustom(pc, key, type, queryName); 529 530 531 } 532 533 534 public final IndexResult deleteIndexNotCustom(PageContext pc,String key,short type,String queryName) throws SearchException { 535 Iterator<String> it = indexes.keySet().iterator(); 536 while(it.hasNext()) { 537 String id = it.next(); 538 if(id.equals(SearchIndex.toId(type,key,queryName))) { 539 SearchIndex index=indexes.get(id); 540 541 IndexResult ir=_deleteIndex(index.getId()); 542 Element indexEl=searchEngine.getIndexElement(searchEngine.getCollectionElement(name),index.getId()); 543 if(indexEl!=null)indexEl.getParentNode().removeChild(indexEl); 544 changeLastUpdate(); 545 return ir; 546 } 547 } 548 return new IndexResultImpl(0,0,0); 549 } 550 551 /** 552 * delete a Index from collection 553 * @param id id ofthe Index to delete 554 * @throws SearchException 555 */ 556 protected abstract IndexResult _deleteIndex(String id) throws SearchException; 557 558 @Override 559 public final Resource getPath() { 560 return path; 561 } 562 563 @Override 564 public DateTime getCreated() { 565 return created; 566 } 567 568 @Override 569 public final DateTime getLastUpdate() { 570 return lastUpdate; 571 } 572 573 @Override 574 public final String getName() { 575 return name; 576 } 577 578 @Override 579 public final Log getLogger() { 580 return log; 581 } 582 583 @Override 584 public final SearchEngine getSearchEngine() { 585 return searchEngine; 586 } 587 588 /** 589 * change the last update attribute and store it 590 * @throws SearchException 591 */ 592 private void changeLastUpdate() throws SearchException { 593 lastUpdate=new DateTimeImpl(); 594 searchEngine.store(); 595 } 596 597 @Override 598 public Object created() { 599 return created; 600 } 601 602 @Override 603 public final int search(SearchData data, Query qry,String criteria, String language, short type,int startrow,int maxrow,String categoryTree, String[] categories) throws SearchException, PageException { 604 int len=qry.getRecordcount(); 605 SearchResulItem[] records; 606 607 AddionalAttrs aa = AddionalAttrs.getAddionlAttrs(); 608 boolean hasRowHandling=false; 609 aa.setStartrow(startrow); 610 if(maxrow!=-1)aa.setMaxrows(maxrow-len); 611 612 Lock l = lock(); 613 try { 614 records = _search(data, criteria,language,type,categoryTree,categories); 615 } 616 finally { 617 unlock(l); 618 if(hasRowHandling=aa.hasRowHandling()) 619 startrow = aa.getStartrow(); 620 621 } 622 623 624 625 // Startrow 626 if(!hasRowHandling && startrow>1) { 627 628 if(startrow>records.length) { 629 return startrow-records.length; 630 } 631 int start=startrow-1; 632 633 SearchResulItem[] tmpRecords=new SearchResulItem[records.length-start]; 634 for(int i=start;i<records.length;i++) { 635 tmpRecords[i-start]=records[i]; 636 } 637 records=tmpRecords; 638 startrow=1; 639 } 640 641 642 if(!ArrayUtil.isEmpty(records)) { 643 644 int to=(!hasRowHandling && maxrow>-1 && len+records.length>maxrow)?maxrow-len:records.length; 645 qry.addRow(to); 646 647 String title; 648 String custom1; 649 String custom2; 650 String custom3; 651 String custom4; 652 String url; 653 SearchResulItem record; 654 SearchIndex si; 655 for(int y=0;y<to;y++) { 656 657 int row=len+y+1; 658 record = records[y]; 659 si=indexes.get(record.getId()); 660 661 title=record.getTitle(); 662 custom1=record.getCustom1(); 663 custom2=record.getCustom2(); 664 custom3=record.getCustom3(); 665 custom4=record.getCustom4(); 666 url=record.getUrl(); 667 668 qry.setAt(KeyConstants._title,row,title); 669 qry.setAt(KeyConstants._custom1,row,custom1); 670 qry.setAt(KeyConstants._custom2,row,custom2); 671 qry.setAt(KeyConstants._custom3,row,custom3); 672 qry.setAt(KeyConstants._custom4,row,custom4); 673 qry.setAt("categoryTree",row,record.getCategoryTree()); 674 qry.setAt(KeyConstants._category,row,record.getCategory()); 675 qry.setAt(KeyConstants._type,row,record.getMimeType()); 676 qry.setAt(KeyConstants._author,row,record.getAuthor()); 677 qry.setAt(KeyConstants._size,row,record.getSize()); 678 679 qry.setAt(KeyConstants._summary,row,record.getSummary()); 680 qry.setAt(KeyConstants._context,row,record.getContextSummary()); 681 qry.setAt(KeyConstants._score,row,new Float(record.getScore())); 682 qry.setAt(KeyConstants._key,row,record.getKey()); 683 qry.setAt(KeyConstants._url,row,url); 684 qry.setAt(KeyConstants._collection,row,getName()); 685 qry.setAt(KeyConstants._rank,row,new Double(row)); 686 String rootPath,file; 687 String urlPath; 688 if(si!=null) { 689 switch(si.getType()){ 690 case SearchIndex.TYPE_PATH: 691 rootPath = si.getKey(); 692 rootPath=rootPath.replace(FileUtil.FILE_ANTI_SEPERATOR,FileUtil.FILE_SEPERATOR); 693 file=record.getKey(); 694 file=file.replace(FileUtil.FILE_ANTI_SEPERATOR,FileUtil.FILE_SEPERATOR); 695 qry.setAt(KeyConstants._url,row,toURL(si.getUrlpath(),StringUtil.replace(file, rootPath, "", true))); 696 697 698 break; 699 case SearchIndex.TYPE_URL: 700 rootPath = si.getKey(); 701 urlPath = si.getUrlpath(); 702 try { 703 rootPath = getDirectory(si.getKey()); 704 } 705 catch (MalformedURLException e) {} 706 if(StringUtil.isEmpty(urlPath))urlPath=rootPath; 707 file=record.getKey(); 708 qry.setAt(KeyConstants._url,row,toURL(urlPath,StringUtil.replace(file, rootPath, "", true))); 709 710 711 break; 712 case SearchIndex.TYPE_CUSTOM: 713 qry.setAt(KeyConstants._url,row,url); 714 break; 715 default: 716 qry.setAt(KeyConstants._url,row,toURL(si.getUrlpath(),url)); 717 break; 718 } 719 720 721 if(StringUtil.isEmpty(title)) qry.setAt(KeyConstants._title,row,si.getTitle()); 722 if(StringUtil.isEmpty(custom1)) qry.setAt(KeyConstants._custom1,row,si.getCustom1()); 723 if(StringUtil.isEmpty(custom2)) qry.setAt(KeyConstants._custom2,row,si.getCustom2()); 724 if(StringUtil.isEmpty(custom3)) qry.setAt(KeyConstants._custom3,row,si.getCustom3()); 725 if(StringUtil.isEmpty(custom4)) qry.setAt(KeyConstants._custom4,row,si.getCustom4()); 726 727 } 728 } 729 } 730 return startrow; 731 } 732 733 public static String getDirectory(String strUrl) throws MalformedURLException { 734 URL url = new URL(strUrl); 735 String path=url.getPath(); 736 int slashIndex = path.lastIndexOf('/'); 737 int dotIndex = path.lastIndexOf('.'); 738 // no dot 739 if(dotIndex==-1){ 740 if(path.endsWith("/"))return HTTPUtil.removeRef(url).toExternalForm(); 741 return HTTPUtil.removeRef(new URL( 742 url.getProtocol(), 743 url.getHost(), 744 url.getPort(),path+"/")).toExternalForm(); 745 } 746 if(slashIndex>dotIndex){ 747 path=path.substring(0,dotIndex); 748 slashIndex = path.lastIndexOf('/'); 749 } 750 751 return HTTPUtil.removeRef(new URL( 752 url.getProtocol(), 753 url.getHost(), 754 url.getPort(),path.substring(0,slashIndex+1))).toExternalForm(); 755 } 756 757 private static String toURL(String url, String path) { 758 if(StringUtil.isEmpty(url)) return path; 759 if(StringUtil.isEmpty(path)) return url; 760 761 url=url.replace('\\','/'); 762 path=path.replace('\\','/'); 763 if(StringUtil.startsWith(path, '/'))path=path.substring(1); 764 if(StringUtil.endsWith(url, '/'))url=url.substring(0,url.length()-1); 765 766 if(StringUtil.startsWithIgnoreCase(path, url)) 767 return path; 768 return url+"/"+path; 769 } 770 771 772 773 774 775 protected SearchIndex[] getIndexes() { 776 Iterator<Entry<String, SearchIndex>> it = indexes.entrySet().iterator(); 777 int len=indexes.size(); 778 SearchIndex[] rtn=new SearchIndex[len]; 779 int count=0; 780 while(it.hasNext()) { 781 rtn[count++]=it.next().getValue(); 782 } 783 return rtn; 784 } 785 786 787 private Lock lock() throws SearchException { 788 try { 789 return lock.lock(getId(),LOCK_TIMEOUT); 790 //manager.lock(LockManager.TYPE_EXCLUSIVE,getId(),LOCK_TIMEOUT,ThreadLocalPageContext.get().getId()); 791 } 792 catch (Exception e) { 793 throw new SearchException(e); 794 } 795 796 } 797 798 private void unlock(Lock l) { 799 lock.unlock(l); 800 //manager.unlock(ThreadLocalPageContext.get().getId()); 801 } 802 803 804 private String getId() { 805 return path.getRealResource(name).getAbsolutePath(); 806 } 807 808 // FUTURE 809 public Object getIndexesAsQuery() { 810 Iterator<Entry<String, SearchIndex>> it = indexes.entrySet().iterator(); 811 812 final String v="VARCHAR"; 813 Query query=null; 814 String[] cols = new String[]{ 815 "categories","categoryTree","custom1","custom2","custom3","custom4","extensions", 816 "key","language","query","title","urlpath","type"}; 817 String[] types = new String[]{ 818 v,v,v,v,v,v,v, 819 v,v,v,v,v,v}; 820 try { 821 query=new QueryImpl(cols,types, 0,"query"); 822 } catch (DatabaseException e) { 823 query=new QueryImpl(cols, 0,"query"); 824 } 825 826 Entry<String, SearchIndex> entry; 827 SearchIndex index; 828 int row=0; 829 while(it.hasNext()) { 830 query.addRow(); 831 row++; 832 entry = it.next(); 833 index= entry.getValue(); 834 if(index==null)continue; 835 try { 836 837 query.setAt("categories",row,ListUtil.arrayToList(index.getCategories(),"")); 838 query.setAt("categoryTree",row,index.getCategoryTree()); 839 840 query.setAt(KeyConstants._custom1,row,index.getCustom1()); 841 query.setAt(KeyConstants._custom2,row,index.getCustom2()); 842 query.setAt(KeyConstants._custom3,row,index.getCustom3()); 843 query.setAt(KeyConstants._custom4,row,index.getCustom4()); 844 845 query.setAt(KeyConstants._extensions,row,ListUtil.arrayToList(index.getExtensions(),",")); 846 query.setAt(KeyConstants._key,row,index.getKey()); 847 query.setAt(KeyConstants._language,row,index.getLanguage()); 848 query.setAt(KeyConstants._query,row,index.getQuery()); 849 query.setAt(KeyConstants._title,row,index.getTitle()); 850 query.setAt(KeyConstants._urlpath,row,index.getUrlpath()); 851 query.setAt(KeyConstants._type,row,SearchIndex.toStringTypeEL(index.getType())); 852 853 } 854 catch(PageException pe) {} 855 } 856 return query; 857 } 858 859}