/* * Copyright 2003-2010 Tufts University Licensed under the * Educational Community License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may * obtain a copy of the License at * * http://www.osedu.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing * permissions and limitations under the License. */ package edu.tufts.vue.fsm.impl; /** This Federated Search Manager works with data in the users extensions file to return type-specific UI controls and adjusters. The result set manager is handed a set of queries. That manager calls the search engine. */ public class VueFederatedSearchManager implements edu.tufts.vue.fsm.FederatedSearchManager { private edu.tufts.vue.fsm.SourcesAndTypesManager sourcesAndTypesManager = VueSourcesAndTypesManager.getInstance(); private static final org.apache.log4j.Logger Log = org.apache.log4j.Logger.getLogger(VueFederatedSearchManager.class); private static final String FILE_NOT_FOUND_MESSAGE = "Cannot find or open "; private static final String EXTENSIONS_TAG = "extensions"; private static final String QUERY_EDITORS_TAG = "queryeditors"; private static final String QUERY_EDITOR_TAG = "queryeditor"; private static final String SEARCH_TYPE_TAG = "searchtype"; private static final String CLASS_NAME_TAG = "classname"; private static final String ASSET_VIEWERS_TAG = "assetviewers"; private static final String ASSET_VIEWER_TAG = "assetviewer"; private static final String ASSET_TYPE_TAG = "assettype"; private static final String QUERY_ADJUSTERS_TAG = "queryadjusters"; private static final String QUERY_ADJUSTER_TAG = "queryadjuster"; private static final String REPOSITORY_ID_TAG = "repositoryid"; private static final String DEFAULT_SEARCH_TYPE = "search/keyword@mit.edu"; private static final String DEFAULT_CLASS_NAME = "edu.tufts.vue.ui.DefaultQueryEditor"; private static final String ARTIFACT_SEARCH_TYPE = "search/artifact@tufts.edu"; private static final String ARTIFACT_CLASS_NAME = "edu.tufts.artifact.ui.ArtifactQueryEditor"; private static edu.tufts.vue.fsm.FederatedSearchManager federatedSearchManager = new VueFederatedSearchManager(); private java.util.Vector queryEditorTypeVector = new java.util.Vector(); private java.util.Vector queryEditorClassNameVector = new java.util.Vector(); private java.util.Vector queryAdjusterRepositoryIdStringVector = new java.util.Vector(); private java.util.Vector queryAdjusterClassNameVector = new java.util.Vector(); private java.util.Vector assetViewerTypeVector = new java.util.Vector(); private java.util.Vector assetViewerClassNameVector = new java.util.Vector(); private static String xmlFilename = null; public static edu.tufts.vue.fsm.FederatedSearchManager getInstance() { return federatedSearchManager; } /* Look in directories beneath the install directory for an extensions file. */ private String[] getXMLFilenames() { java.util.Vector filenameVector = new java.util.Vector(); try { String targetFilename = tufts.vue.VueResources.getString("extensionsSaveToXmlFilename"); //System.out.println("target filename " + targetFilename); String installDirectory = tufts.vue.VueResources.getString("dataSourceInstallDirectory"); //System.out.println("install Directory " + installDirectory); Log.info("listing " + installDirectory + " to find \"" + targetFilename + "\""); java.io.File root = new java.io.File(installDirectory); java.io.File[] files = root.listFiles(); if (files != null) { for (int i=0; i < files.length; i++) { if (files[i].isDirectory()) { java.io.File[] subfiles = files[i].listFiles(); for (int j=0; j < subfiles.length; j++) { if (subfiles[j].getName().equals(targetFilename)) { filenameVector.addElement(subfiles[j].getAbsolutePath()); //System.out.println("added " + filenameVector.lastElement()); } } } } } } catch (Exception ex) { Log.warn(ex); edu.tufts.vue.util.Logger.log(ex); } // add the default file in the user's home folder java.io.File userFolder = tufts.vue.VueUtil.getDefaultUserFolder(); filenameVector.addElement(userFolder.getAbsolutePath() + "/" + tufts.vue.VueResources.getString("extensionsSaveToXmlFilename")); int size = filenameVector.size(); String result[] = new String[size]; for (int i=0; i < size; i++) { result[i] = (String)filenameVector.elementAt(i); } return result; } private VueFederatedSearchManager() { try { javax.xml.parsers.DocumentBuilderFactory dbf = null; javax.xml.parsers.DocumentBuilder db = null; org.w3c.dom.Document document = null; dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance(); db = dbf.newDocumentBuilder(); java.io.File userFolder = tufts.vue.VueUtil.getDefaultUserFolder(); if (!userFolder.exists()) { userFolder.mkdir(); } this.xmlFilename = userFolder.getAbsolutePath() + "/" + tufts.vue.VueResources.getString("extensionsSaveToXmlFilename"); java.io.File file = new java.io.File(this.xmlFilename); if (!file.exists()) { // make a minmal one document = db.newDocument(); org.w3c.dom.Element extensions = document.createElement(EXTENSIONS_TAG); org.w3c.dom.Element editors = document.createElement(QUERY_EDITORS_TAG); org.w3c.dom.Element editor = document.createElement(QUERY_EDITOR_TAG); org.w3c.dom.Element searchtype = document.createElement(SEARCH_TYPE_TAG); searchtype.appendChild(document.createTextNode(DEFAULT_SEARCH_TYPE)); org.w3c.dom.Element classname = document.createElement(CLASS_NAME_TAG); classname.appendChild(document.createTextNode(DEFAULT_CLASS_NAME)); editor.appendChild(classname); editor.appendChild(searchtype); editors.appendChild(editor); org.w3c.dom.Element artifactEditor = document.createElement(QUERY_EDITOR_TAG); org.w3c.dom.Element artifactSearchtype = document.createElement(SEARCH_TYPE_TAG); artifactSearchtype.appendChild(document.createTextNode(ARTIFACT_SEARCH_TYPE)); org.w3c.dom.Element artifactClassname = document.createElement(CLASS_NAME_TAG); artifactClassname.appendChild(document.createTextNode(ARTIFACT_CLASS_NAME)); artifactEditor.appendChild(classname); artifactEditor.appendChild(searchtype); editors.appendChild(artifactEditor); extensions.appendChild(editors); document.appendChild(extensions); javax.xml.transform.TransformerFactory tf = javax.xml.transform.TransformerFactory.newInstance(); javax.xml.transform.Transformer transformer = tf.newTransformer(); java.util.Properties properties = new java.util.Properties(); properties.put("indent","yes"); transformer.setOutputProperties(properties); javax.xml.transform.dom.DOMSource domSource = new javax.xml.transform.dom.DOMSource(document); javax.xml.transform.stream.StreamResult result = new javax.xml.transform.stream.StreamResult (this.xmlFilename); transformer.transform(domSource,result); } String files[] = getXMLFilenames(); for (int f=0; f < files.length; f++) { java.io.InputStream istream = new java.io.FileInputStream(files[f]); document = db.parse(istream); org.w3c.dom.NodeList queryEditors = document.getElementsByTagName(QUERY_EDITORS_TAG); int numQueryEditors = queryEditors.getLength(); for (int i=0; i < numQueryEditors; i++) { org.w3c.dom.Element queryEditor = (org.w3c.dom.Element)queryEditors.item(i); org.w3c.dom.NodeList typeNodeList = queryEditor.getElementsByTagName(SEARCH_TYPE_TAG); int numTypes = typeNodeList.getLength(); org.w3c.dom.NodeList classNameNodeList = queryEditor.getElementsByTagName(CLASS_NAME_TAG); int numClassNames = classNameNodeList.getLength(); for (int j=0; j < numTypes; j++) { org.w3c.dom.Element typeElement = (org.w3c.dom.Element)typeNodeList.item(j); if (typeElement.hasChildNodes()) { queryEditorTypeVector.addElement(typeElement.getFirstChild().getNodeValue()); // ensure there is some entry in the vector if (numClassNames >= j) { org.w3c.dom.Element classNameElement = (org.w3c.dom.Element)classNameNodeList.item(j); if (classNameElement.hasChildNodes()) { queryEditorClassNameVector.addElement(classNameElement.getFirstChild().getNodeValue()); } else { queryEditorClassNameVector.addElement(null); } } else { queryEditorClassNameVector.addElement(null); } } } } org.w3c.dom.NodeList queryAdjusters = document.getElementsByTagName(QUERY_ADJUSTERS_TAG); int numQueryAdjusters = queryAdjusters.getLength(); for (int i=0; i < numQueryAdjusters; i++) { org.w3c.dom.Element queryAdjuster = (org.w3c.dom.Element)queryAdjusters.item(i); org.w3c.dom.NodeList repositoryIdNodeList = queryAdjuster.getElementsByTagName(REPOSITORY_ID_TAG); int numRepositoryIds = repositoryIdNodeList.getLength(); org.w3c.dom.NodeList classNameNodeList = queryAdjuster.getElementsByTagName(CLASS_NAME_TAG); int numClassNames = classNameNodeList.getLength(); for (int j=0; j < numRepositoryIds; j++) { org.w3c.dom.Element repositoryIdElement = (org.w3c.dom.Element)repositoryIdNodeList.item(j); if (repositoryIdElement.hasChildNodes()) { queryAdjusterRepositoryIdStringVector.addElement(repositoryIdElement.getFirstChild().getNodeValue()); // ensure there is some entry in the vector if (numClassNames >= j) { org.w3c.dom.Element classNameElement = (org.w3c.dom.Element)classNameNodeList.item(j); if (classNameElement.hasChildNodes()) { queryAdjusterClassNameVector.addElement(classNameElement.getFirstChild().getNodeValue()); } else { queryAdjusterClassNameVector.addElement(null); } } else { queryAdjusterClassNameVector.addElement(null); } } } } org.w3c.dom.NodeList assetViewers = document.getElementsByTagName(ASSET_VIEWERS_TAG); int numAssetViewers = assetViewers.getLength(); for (int i=0; i < numAssetViewers; i++) { org.w3c.dom.Element assetViewer = (org.w3c.dom.Element)assetViewers.item(i); org.w3c.dom.NodeList typeNodeList = assetViewer.getElementsByTagName(ASSET_TYPE_TAG); int numTypes = typeNodeList.getLength(); org.w3c.dom.NodeList classNameNodeList = assetViewer.getElementsByTagName(CLASS_NAME_TAG); int numClassNames = classNameNodeList.getLength(); for (int j=0; j < numTypes; j++) { org.w3c.dom.Element typeElement = (org.w3c.dom.Element)typeNodeList.item(j); if (typeElement.hasChildNodes()) { assetViewerTypeVector.addElement(typeElement.getFirstChild().getNodeValue()); // ensure there is some entry in the vector if (numClassNames >= j) { org.w3c.dom.Element classNameElement = (org.w3c.dom.Element)classNameNodeList.item(j); if (classNameElement.hasChildNodes()) { assetViewerClassNameVector.addElement(classNameElement.getFirstChild().getNodeValue()); } else { assetViewerClassNameVector.addElement(null); } } else { assetViewerClassNameVector.addElement(null); } } } } } } catch (Throwable t) { edu.tufts.vue.util.Logger.log(t,"parsing " + this.xmlFilename); } } /* Look in a specific XML file for the query editors element. Within this are query editor elements with a search type and a class name. If the search type matchs, try and load and return a class from the class name. */ public edu.tufts.vue.fsm.QueryEditor getQueryEditorForType(org.osid.shared.Type searchType) { try { if (searchType == null) { // load a default Class c = Class.forName("edu.tufts.vue.ui.DefaultQueryEditor"); return (edu.tufts.vue.fsm.QueryEditor)c.newInstance(); } else { String searchTypeString = edu.tufts.vue.util.Utilities.typeToString(searchType); int startIndex = 0; int index = -1; while ( (index = queryEditorTypeVector.indexOf(searchTypeString,startIndex)) != -1) { String className = (String)queryEditorClassNameVector.elementAt(index); //TODO: we need to find this via Provider try { Class c = Class.forName(className); return (edu.tufts.vue.fsm.QueryEditor)c.newInstance(); } catch (Throwable t) { edu.tufts.vue.util.Logger.log(t,"failed to load class " + className); // keep looking startIndex = index + 1; } } // load a default Class c = Class.forName("edu.tufts.vue.ui.DefaultQueryEditor"); return (edu.tufts.vue.fsm.QueryEditor)c.newInstance(); } } catch (Throwable t) { edu.tufts.vue.util.Logger.log(t,"looking for a query editor"); } return null; } public edu.tufts.vue.fsm.QueryAdjuster getQueryAdjusterForRepository(org.osid.shared.Id repositoryId) { try { String repositoryIdString = repositoryId.getIdString(); int startIndex = 0; int index = -1; while ( (index = queryAdjusterRepositoryIdStringVector.indexOf(repositoryIdString,startIndex)) != -1) { String className = (String)queryAdjusterClassNameVector.elementAt(index); //TODO: we need to find this via Provider try { Class c = Class.forName(className); return (edu.tufts.vue.fsm.QueryAdjuster)c.newInstance(); } catch (Throwable t) { edu.tufts.vue.util.Logger.log(t,"failed to load class " + className); // keep looking startIndex = index + 1; } } } catch (Throwable t) { edu.tufts.vue.util.Logger.log(t,"looking for a query adjuster"); } return null; } public edu.tufts.vue.fsm.AssetViewer getAssetViewerForType(org.osid.shared.Type assetType) { try { String assetTypeString = edu.tufts.vue.util.Utilities.typeToString(assetType); int startIndex = 0; int index = -1; while ( (index = assetViewerTypeVector.indexOf(assetTypeString,startIndex)) != -1) { String className = (String)assetViewerClassNameVector.elementAt(index); //TODO: we need to find this via Provider try { Class c = Class.forName(className); return (edu.tufts.vue.fsm.AssetViewer)c.newInstance(); } catch (Throwable t) { edu.tufts.vue.util.Logger.log(t,"failed to load class " + className); // keep looking startIndex = index + 1; } } } catch (Throwable t) { edu.tufts.vue.util.Logger.log(t,"looking for a asset editor"); } return null; } public edu.tufts.vue.fsm.ResultSetManager getResultSetManager(java.io.Serializable searchCriteria, org.osid.shared.Type searchType, org.osid.shared.Properties searchProperties) { try { edu.tufts.vue.fsm.SearchEngine searchEngine = new VueSearchEngine(); org.osid.repository.Repository[] repositories = sourcesAndTypesManager.getRepositoriesToSearch(); edu.tufts.vue.dsm.DataSource[] dataSources = sourcesAndTypesManager.getDataSourcesToSearch(); // will be same length edu.tufts.vue.fsm.Query queries[] = new edu.tufts.vue.fsm.Query[repositories.length]; for (int i=0; i < repositories.length; i++) { org.osid.repository.Repository repository = repositories[i]; // We need to figure out how this should work under Provider edu.tufts.vue.fsm.QueryAdjuster adjuster = getQueryAdjusterForRepository(repository.getId()); if (adjuster != null) { queries[i] = adjuster.adjustQuery(repository, searchCriteria, searchType, searchProperties); } else { // System.out.println("Creating query for foreign id " + dataSources[i].getId().getIdString()); queries[i] = new VueQuery(dataSources[i].getId().getIdString(), repository, searchCriteria, searchType, searchProperties); } } searchEngine.search(queries); return new VueResultSetManager(searchEngine); } catch (Throwable t) { edu.tufts.vue.util.Logger.log(t,"preparing ResultSetManager"); } return null; } }