001/*
002 * Copyright (c) 2004-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: barseghian $'
006 * '$Date: 2013-01-17 00:52:56 +0000 (Thu, 17 Jan 2013) $' 
007 * '$Revision: 31343 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.kepler.gui;
031
032import java.lang.reflect.Constructor;
033import java.lang.reflect.InvocationTargetException;
034import java.util.Iterator;
035import java.util.List;
036import java.util.Stack;
037import java.util.Vector;
038
039import javax.swing.JTree;
040import javax.swing.tree.TreeModel;
041import javax.swing.tree.TreePath;
042
043import org.apache.commons.logging.Log;
044import org.apache.commons.logging.LogFactory;
045import org.kepler.authentication.AuthenticationException;
046import org.kepler.configuration.ConfigurationManager;
047import org.kepler.configuration.ConfigurationProperty;
048import org.kepler.objectmanager.library.LibraryManager;
049import org.kepler.objectmanager.lsid.KeplerLSID;
050import org.kepler.objectmanager.repository.Repository;
051import org.kepler.objectmanager.repository.RepositoryException;
052import org.kepler.objectmanager.repository.RepositoryManager;
053
054import ptolemy.kernel.ComponentEntity;
055import ptolemy.kernel.util.IllegalActionException;
056import ptolemy.kernel.util.NamedObj;
057import ptolemy.moml.EntityLibrary;
058
059/**
060 * class to search the library. This class uses a simple name comparator to
061 * determine results. It uses a depth first traversal of the tree.
062 * 
063 *@author berkley
064 *@since February 17, 2005
065 */
066public class SimpleLibrarySearcher extends LibrarySearcher {
067        private static final Log log = LogFactory
068                        .getLog(SimpleLibrarySearcher.class.getName());
069        private static final boolean isDebugging = log.isDebugEnabled();
070
071        // the stack to create the return paths with
072        private Stack<Object> _pathStack;
073        private boolean skipRepositoryOntology = false;
074
075        /**
076         * constructor
077         * 
078         *@param library
079         *            Description of the Parameter
080         *@param searchPane
081         *            Description of the Parameter
082         */
083        public SimpleLibrarySearcher(JTree library, LibrarySearchPane searchPane) {
084                super(library, searchPane);
085        }
086        
087        /**
088         * Set true if want not to display remote ontology
089         */
090        public void setSkipReposiotryOntology(boolean skipRepositoryOntology){
091          this.skipRepositoryOntology = skipRepositoryOntology;
092        }
093
094        /**
095         * search for val in the library
096         * 
097         *@param val
098         *            Description of the Parameter
099         *@param authenticate
100         *                        if true prompt user to login if necessary
101         *@return Description of the Return Value
102         * @throws AuthenticationException 
103         * @throws RepositoryException 
104         */
105        public LibrarySearchResults search(String value, boolean authenticate)
106                        throws IllegalActionException, RepositoryException, AuthenticationException {
107                if (isDebugging) {
108                        log.debug("search(" + value + ")");
109                }
110
111                Long searchTime = System.currentTimeMillis();
112
113                value = value.trim();
114
115                // need to reset the results before doing the search
116                _results = new LibrarySearchResults();
117                if (value.trim().equals("")) {
118                        return _results;
119                }
120
121                // We'll need the tree model for the search
122                TreeModel model = _library.getModel();
123
124                // check if the search string is a KeplerLSID
125                if (KeplerLSID.isKeplerLSIDFormat(value)) {
126                        if (isDebugging)
127                                log.debug("User is searching for an LSID");
128
129                        try {
130                                KeplerLSID lsid = new KeplerLSID(value);
131                                Vector<KeplerLSID> lsids = new Vector<KeplerLSID>(1);
132                                lsids.add(lsid);
133                                if (isDebugging)
134                                        log.debug("Searching for " + lsid);
135
136                                Vector<Integer> liids = LibraryManager.getInstance()
137                                                .getLiidsFor(lsids);
138                                findLiids(liids, model);
139                        } catch (Exception e) {
140                                Vector<Integer> liids = LibraryManager.getInstance().getIndex()
141                                                .getSearcher().search(value);
142                                findLiids(liids, model);
143                        }
144
145                } else {
146                        Vector<Integer> liids = LibraryManager.getInstance().getIndex()
147                                        .getSearcher().search(value);
148                        if (isDebugging)
149                                log.debug("Index search generated " + liids.size()
150                                                + " results in "
151                                                + (System.currentTimeMillis() - searchTime) + "ms");
152                        searchTime = System.currentTimeMillis();
153                        findLiids(liids, model);
154                        if (isDebugging)
155                                log.debug("Model search generated " + _results.size()
156                                                + " results in "
157                                                + (System.currentTimeMillis() - searchTime) + "ms");
158
159                }
160                searchTime = System.currentTimeMillis();
161                if (isDebugging)
162                        log.debug("Start Repository Search");
163                try {
164                        RepositoryManager rm = null;
165                        try {
166                                rm = RepositoryManager.getInstance();
167                        } catch (Exception e) {
168                                // TODO Auto-generated catch block
169                                e.printStackTrace();
170                        }
171
172                        for (Repository r : rm.getRepositories()) {
173                                if (r.includeInSearch()) {
174                                        if (isDebugging) {
175                                                log.debug("Searching remote repository " + r.getName());
176                                        }
177
178                                        // use EcogridRepositoryLibrarySearcher as the default
179                                        String className = "org.kepler.objectmanager.repository.EcogridRepositoryLibrarySearcher";
180                                        List propList = ConfigurationManager.getInstance()
181                                                        .getProperties(
182                                                                        ConfigurationManager.getModule("gui"));
183                                        List reposSearcherList = ConfigurationProperty
184                                                        .findProperties(propList, "name",
185                                                                        "repositorySearcher", true);
186                                        if (reposSearcherList != null
187                                                        && reposSearcherList.size() > 0) {
188                                                className = ((ConfigurationProperty) reposSearcherList
189                                                                .get(0)).getProperty("value").getValue();
190                                        }
191
192                                        // Use reflection to instantiate the class
193                                        Class searchClass = Class.forName(className);
194
195                                        Class[] args = new Class[] { JTree.class,
196                                                        LibrarySearchPane.class, String.class };
197
198                                        // create a constructor
199                                        Constructor constructor = searchClass.getConstructor(args);
200
201                                        // set the args
202                                        Object[] argImp = new Object[] { _library, _searchPane,
203                                                        r.getName() };
204
205                                        RepositorySearcher reposSearcher = (RepositorySearcher) constructor
206                                                        .newInstance(argImp);
207                                        reposSearcher.setSkipOntology(skipRepositoryOntology);
208                                        // search the ecogrid repository
209                                        // you must call this or the
210                                        // default repository name of 'defaultRepository' is used.
211                                        log.debug("calling search using RepositorySearcher of class:"+className);
212                                        Iterator itr = null;
213                                        try{
214                                                itr = reposSearcher.search(value, authenticate).iterator();
215                                                while (itr.hasNext()) {
216                                                        TreePath p = (TreePath) itr.next();
217                                                        if (!_results.contains(p)) {
218                                                                _results.add(p);
219                                                        }
220                                                }
221                                        }catch(AuthenticationException ae){
222                                                if (ae.getType() != AuthenticationException.USER_CANCEL) {
223                                                        throw ae;
224                                                }
225                                                log.debug("caught AuthenticationException of type USER_CANCEL, taking no action, proceed...");
226                                        }
227                                }
228                        }
229                        if (isDebugging)
230                                log.debug("End Repository Search: "
231                                                + (System.currentTimeMillis() - searchTime) + "ms");
232
233                } catch (InvocationTargetException e) {
234                        // TODO Auto-generated catch block
235                        e.printStackTrace();
236                } catch (ClassNotFoundException e) {
237                        // TODO Auto-generated catch block
238                        e.printStackTrace();
239                } catch (SecurityException e) {
240                        // TODO Auto-generated catch block
241                        e.printStackTrace();
242                } catch (NoSuchMethodException e) {
243                        // TODO Auto-generated catch block
244                        e.printStackTrace();
245                } catch (IllegalArgumentException e) {
246                        // TODO Auto-generated catch block
247                        e.printStackTrace();
248                } catch (InstantiationException e) {
249                        // TODO Auto-generated catch block
250                        e.printStackTrace();
251                } catch (IllegalAccessException e) {
252                        // TODO Auto-generated catch block
253                        e.printStackTrace();
254                }
255
256                return _results;
257        }
258
259        /**
260         * pre-reads the library so searches will be faster. When the momlparser
261         * hits an error in the moml, it rebuilds the model which in turn collapses
262         * the entire library JTree. This presearches the tree which causes the
263         * parse errors to get thrown before the first search so the tree won't be
264         * collapsed the first time you search.
265         */
266        protected void init() {
267                _pathStack = new Stack<Object>();
268        }
269
270        /**
271         * Search the tree model and add any components that match any of the
272         * supplied KeplerLSIDs to the results. This method does not match
273         * EntityLibraries but only checks leaf nodes that are ComponentEntities.
274         * 
275         * @param lsids
276         * @param model
277         */
278        private void findLiids(Vector<Integer> liids, TreeModel model) {
279                if (isDebugging)
280                        log.debug("findLsids(" + liids + " " + model.getRoot() + "");
281
282                Object o = model.getRoot();
283
284                // start from the root
285                _pathStack = new Stack<Object>();
286
287                _pathStack.push(o);
288
289                for (int i = 0; i < model.getChildCount(o); i++) {
290                        Object child = model.getChild(o, i);
291                        if (child instanceof NamedObj) {
292                                NamedObj nobjChild = (NamedObj) child;
293                                String name = nobjChild.getName();
294                                if (name.startsWith("_"))
295                                        continue;
296
297                                _pathStack.push(child);
298
299                                if (nobjChild instanceof EntityLibrary) {
300                                        findLiids(liids, (EntityLibrary) nobjChild);
301                                } else if (nobjChild instanceof ComponentEntity) {
302                                        checkLiid((ComponentEntity) nobjChild, liids);
303                                }
304                        }
305                }
306        }
307
308        /**
309         * Recursive helper function for findLsids(Vector<KeplerLSID> lsids,
310         * TreeModel model)
311         * 
312         * @param lsids
313         * @param entity
314         */
315        private void findLiids(Vector<Integer> liids, EntityLibrary entity) {
316                if (isDebugging)
317                        log.debug("findLsids(" + liids + " " + entity.getName() + ")");
318
319                // loop through the children of the entity
320                for (Iterator i = entity.containedObjectsIterator(); i.hasNext();) {
321                        NamedObj e = (NamedObj) i.next();
322                        String name = e.getName();
323                        if (name.startsWith("_"))
324                                continue;
325
326                        _pathStack.push(e);
327
328                        if (e instanceof EntityLibrary) {
329                                // recurse
330                                findLiids(liids, (EntityLibrary) e);
331                        } else if (e instanceof ComponentEntity) {
332                                // leaf node
333                                checkLiid((ComponentEntity) e, liids);
334                                popstack();
335                        } else {
336                                popstack();
337                        }
338                }
339                popstack();
340
341        }
342
343        /**
344         * Check to see if the supplied NamedObj matches any of the LIIDs in the
345         * supplied list.
346         * 
347         * @param nobj
348         * @param lsids
349         */
350        private boolean checkLiid(ComponentEntity e, Vector<Integer> liids) {
351                if (isDebugging)
352                        log.debug("checkLsid(" + e.getName() + " " + liids + ")");
353                int thisLiid = LibraryManager.getLiidFor(e);
354                if (thisLiid != -1) {
355                        Integer iLiid = new Integer(thisLiid);
356                        if (isDebugging)
357                                log.debug(iLiid);
358                        if (liids.contains(iLiid)) {
359                                if (isDebugging)
360                                        log.debug("MATCH");
361                                addStackTopToResult();
362                                return true;
363                        }
364                }
365                return false;
366        }
367
368        /**
369         * pop the top off the stackeroo
370         */
371        private void popstack() {
372                if (!_pathStack.empty()) {
373                        _pathStack.pop();
374                }
375        }
376
377        /**
378         * adds the path at the top of the stack to the result
379         */
380        private void addStackTopToResult() {
381                _results.add(createPathFromStack());
382        }
383
384        /**
385         * return the path as a TreePath
386         * 
387         *@return Description of the Return Value
388         */
389        private TreePath createPathFromStack() {
390                return new TreePath(_pathStack.toArray());
391        }
392}