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