/********************************************************************************** * $URL: $ * $Id: $ *********************************************************************************** * * Copyright (c) 2006, 2007, 2008, 2009 The Sakai Foundation * * 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.opensource.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 org.sakaiproject.citation.impl; import java.io.InputStream; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Observable; import java.util.Observer; import java.util.SortedSet; import java.util.TreeSet; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.authz.api.SecurityAdvisor; import org.sakaiproject.authz.cover.SecurityService; import org.sakaiproject.citation.api.ConfigurationService; import org.sakaiproject.citation.api.SiteOsidConfiguration; import org.sakaiproject.citation.util.api.OsidConfigurationException; import org.sakaiproject.component.api.ServerConfigurationService; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.content.api.ContentHostingService; import org.sakaiproject.content.api.ContentResource; import org.sakaiproject.entity.api.Reference; import org.sakaiproject.entity.cover.EntityManager; import org.sakaiproject.event.api.Event; import org.sakaiproject.event.cover.EventTrackingService; import org.sakaiproject.exception.IdInvalidException; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.exception.IdUsedException; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.exception.ServerOverloadException; import org.sakaiproject.exception.TypeException; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SitePage; import org.sakaiproject.site.api.SiteService; import org.sakaiproject.tool.api.Session; import org.sakaiproject.tool.api.SessionManager; import org.sakaiproject.user.api.UserDirectoryService; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.thoughtworks.xstream.XStream; import edu.indiana.lib.twinpeaks.util.DomException; /** * */ public class BaseConfigurationService implements ConfigurationService, Observer { private static Log m_log = LogFactory.getLog(BaseConfigurationService.class); /** * Locale that will be used if user's locale is not available. */ private static final String SERVER_DEFAULT_LOCALE = Locale.ENGLISH.getLanguage(); public static final String DEFAULT_SECONDS_BETWEEN_SAVECITE_REFRESHES = "5"; public static final int MAXIMUM_SECONDS_BETWEEN_SAVECITE_REFRESHES = 30; public static final String PARAM_SECONDS_BETWEEN_SAVECITE_REFRESHES = "secondsBetweenSaveciteRefreshes"; /* * All the following properties will be set by Spring using components.xml */ // enable/disable entire helper protected boolean m_citationsEnabledByDefault = false; protected boolean m_allowSiteBySiteOverride = false; // enable/disable helper features --> protected String m_googleSearchEnabled = "false"; protected String m_librarySearchEnabled = "false"; protected boolean m_externalSearchEnabled = false; protected String m_adminSiteName = "citationsAdmin"; protected String m_configFolder = "config"; protected String m_configXml = "sakai/citationsConfig.xml"; protected String m_categoriesXml = "sakai/databaseHierarchy.xml"; protected SortedSet<String> m_updatableResources = Collections.synchronizedSortedSet(new TreeSet<String>()); // configuration XML file location protected String m_databaseXml; protected String m_siteConfigXml; // metasearch engine parameters protected String m_metasearchUsername; protected String m_metasearchPassword; protected String m_metasearchBaseUrl; // which osid impl to use protected String m_osidImpl; // extended repository id (optional, leave as null if not used) protected String m_extendedRepositoryId; // openURL parameters --> protected String m_openUrlLabel; protected String m_openUrlResolverAddress; // google scholar parameters --> protected String m_googleBaseUrl; protected String m_sakaiServerKey; protected String m_externalSearchUrl; // site-specific config/authentication/authorization implementation --> protected String m_osidConfig; /* * End of components.xml properties */ // other config services --> protected SessionManager m_sessionManager; protected ServerConfigurationService m_serverConfigurationService; private TreeSet<String> m_categories; private TreeSet<String> m_configs; /* * Site specific OSID configuration instance */ private static SiteOsidConfiguration m_siteConfigInstance = null; /* * Dynamic configuration parameters */ protected static Map<String, Map<String,String>> m_configMaps = new HashMap<String, Map<String,String>>(); protected static String m_configListRef = null; /** * */ protected Map<String, List<Map<String, String>>> saveciteClients = new HashMap<String, List<Map<String,String>>>(); /* * Interface methods */ /** * Fetch the appropriate XML configuration document for this user * @return Configuration XML resource name */ public String getConfigurationXml() throws OsidConfigurationException { SiteOsidConfiguration siteConfig = getSiteOsidConfiguration(); String configXml = null; if (siteConfig != null) { configXml = siteConfig.getConfigurationXml(); } if (isNull(configXml)) { configXml = m_siteConfigXml; } return configXml; } /** * Is the configuration XML file provided and readable * @return true If the XML file is provided and readable, false otherwise */ public boolean isConfigurationXmlAvailable() { try { String configXml = getConfigurationXml(); if (configXml == null) { return false; } return exists(configXml); } catch (OsidConfigurationException exception) { m_log.warn("Unexpected exception: " + exception); } return false; } public String getConfigFolderReference() { String configFolderRef = null; if(! isNull(this.m_adminSiteName) && ! isNull(this.m_configFolder)) { configFolderRef = "/content/group/" + this.m_adminSiteName + "/" + this.m_configFolder + "/"; } return configFolderRef; } public String getConfigFolderId() { String configFolderId = null; if(! isNull(this.m_adminSiteName) && ! isNull(this.m_configFolder)) { configFolderId = "/group/" + this.m_adminSiteName + "/" + this.m_configFolder + "/"; } return configFolderId; } /** * Fetch the appropriate XML database hierarchy document for this user * @return Hierarchy XML resource name */ public String getDatabaseHierarchyXml() throws OsidConfigurationException { SiteOsidConfiguration siteConfig = getSiteOsidConfiguration(); String databaseXml = null; if (siteConfig != null) { databaseXml = siteConfig.getDatabaseHierarchyXml(); } if (isNull(databaseXml)) { databaseXml = m_databaseXml; } return databaseXml; } /** * Is the database hierarchy XML file provided and readable * @return true If the XML file is provided and readable, false otherwise */ public boolean isDatabaseHierarchyXmlAvailable() { try { String dbXml = getDatabaseHierarchyXml(); if( dbXml == null ) { return false; } return exists(dbXml); } catch (OsidConfigurationException exception) { m_log.warn("Unexpected exception: " + exception); } return false; } /** * Fetch this user's group affiliations * @return A list of group IDs (empty if no IDs exist) */ public List<String> getGroupIds() throws OsidConfigurationException { SiteOsidConfiguration siteConfig = getSiteOsidConfiguration(); if (siteConfig == null) { ArrayList<String> emptyList = new ArrayList(); return emptyList; } return siteConfig.getGroupIds(); } /** * Fetch the site specific Repository OSID package name * @return Repository Package (eg org.sakaibrary.osid.repository.xserver) */ public synchronized String getSiteConfigOsidPackageName() { String value = getConfigurationParameter("osid-impl"); return (value != null) ? value : getOsidImpl(); } /** * Fetch the site specific extended Repository ID * @return The Repository ID */ public synchronized String getSiteConfigExtendedRepositoryId() { String value = getConfigurationParameter("extended-repository-id"); return (value != null) ? value : getExtendedRepositoryId(); } /** * Fetch the meta-search username * @return the username */ public synchronized String getSiteConfigMetasearchUsername() { String value = getConfigurationParameter("metasearch-username"); return (value != null) ? value : getMetasearchUsername(); } /** * Fetch the meta-search password * @return the password */ public synchronized String getSiteConfigMetasearchPassword() { String value = getConfigurationParameter("metasearch-password"); return (value != null) ? value : getMetasearchPassword(); } /** * Fetch the meta-search base-URL * @return the username */ public synchronized String getSiteConfigMetasearchBaseUrl() { String value = getConfigurationParameter("metasearch-baseurl"); return (value != null) ? value : getMetasearchBaseUrl(); } /** * Fetch the OpenURL label * @return the label text */ public synchronized String getSiteConfigOpenUrlLabel() { String value = getConfigurationParameter("openurl-label"); return (value != null) ? value : getOpenUrlLabel(); } /** * Fetch the OpenURL resolver address * @return the resolver address (domain name or IP) */ public synchronized String getSiteConfigOpenUrlResolverAddress() { String value = getConfigurationParameter("openurl-resolveraddress"); return (value != null) ? value : getOpenUrlResolverAddress(); } /** * Fetch the Google base-URL * @return the URL */ public synchronized String getSiteConfigGoogleBaseUrl() { String value = getConfigurationParameter("google-baseurl"); return (value != null) ? value : getGoogleBaseUrl(); } /** * Fetch the Sakai server key * @return the key text */ public synchronized String getSiteConfigSakaiServerKey() { String value = getConfigurationParameter("sakai-serverkey"); return (value != null) ? value : getSakaiServerKey(); } /** * Get the maximum number of databases we can search at one time * @return The maximum value (defaults to <code>SEARCHABLE_DATABASES</code> * if no other value is specified) */ public synchronized int getSiteConfigMaximumSearchableDBs() { String configValue = getConfigurationParameter("searchable-databases"); int searchableDbs = SEARCHABLE_DATABASES; /* * Supply the default if no value was configured */ if (configValue == null) { return searchableDbs; } /* * Make sure we have a good value */ try { searchableDbs = Integer.parseInt(configValue); if (searchableDbs <= 0) { throw new NumberFormatException(configValue); } } catch (NumberFormatException exception) { if(m_log.isDebugEnabled()) { m_log.debug("Maximum searchable database exception: " + exception.toString()); } searchableDbs = SEARCHABLE_DATABASES; } finally { return searchableDbs; } } /** * How should we use URLs marked as "preferred" by the OSID implementation? * The choices are: *<ul> * <li> "false" (do not use the preferred URL at all) * <li> "title-link" (provide the preferred URL as the title link) * <li> "related-link" (provide as a related link, not as the title link) *</ul> * Note: "false" is the default value if nothing is specified in the * configuration file * * @return "related-link", "title-link", or "false" */ public synchronized String getSiteConfigUsePreferredUrls() { String value = getConfigurationParameter("provide-direct-url"); if (value == null) { return "false"; } value = value.trim().toLowerCase(); if (!(value.equals("false") || value.equals("related-link") || value.equals("title-link"))) { m_log.debug("Invalid value for <provide-direct-url>: \"" + value + "\", using \"false\""); value = "false"; } return value; } /** * Prefix string for "preferred" URLs (when used as title or related links). * * This is likely to be the proxy information for the direct URL. * * @return The prefix String (null if none) */ public synchronized String getSiteConfigPreferredUrlPrefix() { return getConfigurationParameter("direct-url-prefix"); } /** * Enable/disable Citations Helper by default * @param state true to set default 'On' */ public void setCitationsEnabledByDefault(boolean citationsEnabledByDefault) { m_citationsEnabledByDefault = citationsEnabledByDefault; } /** * Is the Citations Helper [potentially] available for all sites? * @return true if so */ public boolean isCitationsEnabledByDefault() { String state = getConfigurationParameter("citations-enabled-by-default"); if (state != null) { m_log.debug("Citations enabled by default (1): " + state.equals("true")); return state.equals("true"); } m_log.debug("Citations enabled by default (2): " + m_citationsEnabledByDefault); return m_citationsEnabledByDefault; } /** * Enable/disable site by site Citations Helper override * @param state true to enable site by site Citations Helper */ public void setAllowSiteBySiteOverride(boolean allowSiteBySiteOverride) { m_allowSiteBySiteOverride = allowSiteBySiteOverride; } /** * Is the Citations Helper enabled site-by-site? * @return true if so */ public boolean isAllowSiteBySiteOverride() { String state = getConfigurationParameter("citations-enabled-site-by-site"); if (state != null) { m_log.debug("Citations enabled site-by-site (1): " + state.equals("true")); return state.equals("true"); } m_log.debug("Citations enabled site-by-site (2): " + m_allowSiteBySiteOverride); return m_allowSiteBySiteOverride; } /** * Enable/disable Google support (no support for site specific XML configuration) * @param state true to enable Google support */ public void setGoogleScholarEnabled(boolean state) { String enabled = state ? "true" : "false"; setGoogleSearchEnabled(enabled); } /** * Is Google search enabled? (no support for site specific XML configuration) * @return true if so */ public boolean isGoogleScholarEnabled() { String state = getConfigurationParameter("google-scholar-enabled"); if (state == null) { state = getGoogleSearchEnabled(); } m_log.debug("Google enabled: " + state.equals("true")); return state.equals("true"); } /** * Enable/disable library search support (no support for site specific XML configuration) * @param state true to enable support */ public void setLibrarySearchEnabled(boolean state) { String enabled = state ? "true" : "false"; setLibrarySearchEnabled(enabled); } /** * Is library search enabled for any users? (no support for site specific XML configuration) * @return true if so */ public boolean isLibrarySearchEnabled() { String state = getConfigurationParameter("library-search-enabled"); if (state == null) { state = getLibrarySearchEnabled(); } m_log.debug("Library Search enabled: " + state.equals("true")); return state.equals("true"); } /* * Helpers */ /** * Get a named value from the site-specific XML configuration file * @param parameter Configuration parameter to lookup * @return Parameter value (null if none [or error]) */ protected String getConfigurationParameter(String parameter) { Map<String, String> parameterMap = null; try { SiteOsidConfiguration siteConfig; String configXml, configXmlRef; /* * Fetch the configuration XML resource name */ siteConfig = getSiteOsidConfiguration(); if (siteConfig == null) { return null; } if ((configXml = siteConfig.getConfigurationXml()) == null) { return null; } /* * Construct the full reference and look up the requested configuration */ configXmlRef = this.getConfigFolderReference() + configXml; synchronized (this) { parameterMap = m_configMaps.get(configXmlRef); } } catch (OsidConfigurationException exception) { m_log.warn("Failed to get a dynamic XML value for " + parameter + ": " + exception); } /* * Finally, return the requested configuration parameter */ return (parameterMap == null) ? null : parameterMap.get(parameter); } /** * Load and initialize the site-specific OSID configuration code * @return The initialized, site-specific OSID configuration * object (null on error) */ protected SiteOsidConfiguration getSiteOsidConfiguration() { SiteOsidConfiguration siteConfig; try { siteConfig = getConfigurationHandler(m_osidConfig); siteConfig.init(); } catch (Exception exception) { m_log.warn("Failed to get " + m_osidConfig + ": " + exception); siteConfig = null; } return siteConfig; } /** * Return a SiteOsidConfiguration instance * @return A SiteOsidConfiguration */ public synchronized SiteOsidConfiguration getConfigurationHandler(String osidConfigHandler) throws java.lang.ClassNotFoundException, java.lang.InstantiationException, java.lang.IllegalAccessException { if (m_siteConfigInstance == null) { Class configClass = Class.forName(osidConfigHandler); m_siteConfigInstance = (SiteOsidConfiguration) configClass.newInstance(); } return m_siteConfigInstance; } /** * Populate cached values from a configuration XML resource. We always try * to parse the resource, regardless of any prior success or failure. * * @param configurationXml Configuration resource name (this doubles as a * unique key into the configuration cache) */ public void populateConfig(String configurationXml, InputStream stream) { org.w3c.dom.Document document; String value; /* * Parse the XML - if that fails, give up now */ if ((document = parseXmlFromStream(stream)) == null) { return; } synchronized (this) { Map<String, String> parameterMap; /* * Successful parse - save the values */ if ((parameterMap = m_configMaps.get(configurationXml)) == null) { parameterMap = new HashMap<String, String>(); } parameterMap.clear(); saveParameter(document, parameterMap, "citations-enabled-by-default"); saveParameter(document, parameterMap, "citations-enabled-site-by-site"); saveParameter(document, parameterMap, "google-scholar-enabled"); saveParameter(document, parameterMap, "library-search-enabled"); saveParameter(document, parameterMap, "osid-impl"); saveParameter(document, parameterMap, "extended-repository-id"); saveParameter(document, parameterMap, "metasearch-username"); saveParameter(document, parameterMap, "metasearch-password"); saveParameter(document, parameterMap, "metasearch-baseurl"); saveParameter(document, parameterMap, "metasearch-enabled"); saveParameter(document, parameterMap, "openurl-label"); saveParameter(document, parameterMap, "openurl-resolveraddress"); saveParameter(document, parameterMap, "provide-direct-url"); saveParameter(document, parameterMap, "direct-url-prefix"); saveParameter(document, parameterMap, "google-baseurl"); saveParameter(document, parameterMap, "sakai-serverkey"); saveParameter(document, parameterMap, "searchable-databases"); saveParameter(document, parameterMap, "config-id"); // obsolete? saveParameter(document, parameterMap, "database-xml"); // obsolete? saveParameter(document, parameterMap, PARAM_SECONDS_BETWEEN_SAVECITE_REFRESHES); saveServletClientMappings(document); m_configMaps.put(configurationXml, parameterMap); } } protected void saveServletClientMappings(Document document) { Element clientElement = document.getElementById("saveciteClients"); if(clientElement == null) { NodeList mapNodes = document.getElementsByTagName("map"); if(mapNodes != null) { for(int i = 0; i < mapNodes.getLength(); i++) { Element mapElement = (Element) mapNodes.item(i); if(mapElement.hasAttribute("id") && mapElement.getAttribute("id").equals("saveciteClients")) { clientElement = mapElement; break; } } } } if(clientElement != null) { try { XStream xstream = new XStream(); TransformerFactory transFactory = TransformerFactory.newInstance(); Transformer transformer = transFactory.newTransformer(); StringWriter buffer = new StringWriter(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); transformer.transform(new DOMSource(clientElement), new StreamResult(buffer)); String str = buffer.toString(); // DOMImplementationLS domImplLS = (DOMImplementationLS) document.getImplementation(); // LSSerializer serializer = domImplLS.createLSSerializer(); // String str = serializer.writeToString(clientElement); this.saveciteClients = (Map<String, List<Map<String, String>>>) xstream.fromXML(str); } catch(Exception e) { m_log.warn("Exception trying to read saveciteClients from config XML", e); } } } /** * Lookup and save one dynamic configuration parameter * @param Configuration XML * @param parameterMap Parameter name=value pairs * @param name Parameter name */ protected void saveParameter(org.w3c.dom.Document document, Map parameterMap, String name) { String value; if ((value = getText(document, name)) != null) { parameterMap.put(name, value); } } /* * XML helpers */ /** * Parse an XML resource * @param filename The filename (or URI) to parse * @return DOM Document (null if parse fails) */ protected Document parseXmlFromStream(InputStream stream) { try { DocumentBuilder documentBuilder = getXmlDocumentBuilder(); if (documentBuilder != null) { return documentBuilder.parse(stream); } } catch (Exception exception) { m_log.warn("XML parse on \"" + stream + "\" failed: " + exception); } return null; } /** * Get a DOM Document builder. * @return The DocumentBuilder * @throws DomException */ protected DocumentBuilder getXmlDocumentBuilder() { try { DocumentBuilderFactory factory; factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(false); factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); factory.setFeature("http://xml.org/sax/features/external-general-entities", false); factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); return factory.newDocumentBuilder(); } catch (Exception exception) { m_log.warn("Failed to get XML DocumentBuilder: " + exception); } return null; } /** * "Normalize" XML text node content to create a simple string * @param original Original text * @param update Text to add to the original string (a space separates the two) * @return Concatenated contents (trimmed) */ protected String normalizeText(String original, String update) { StringBuilder result; if (original == null) { return (update == null) ? "" : update.trim(); } result = new StringBuilder(original.trim()); result.append(' '); result.append(update.trim()); return result.toString(); } /** * Get the text associated with this element * @param root The document containing the text element * @return Text (trimmed of leading/trailing whitespace, null if none) */ protected String getText(Document root, String elementName) { return getText(root.getDocumentElement(), elementName); } /** * Get the text associated with this element * @param root The root node of the text element * @return Text (trimmed of leading/trailing whitespace, null if none) */ protected String getText(Element root, String elementName) { NodeList nodeList; Node parent; String text; nodeList = root.getElementsByTagName(elementName); if (nodeList.getLength() == 0) { return null; } text = null; parent = (Element) nodeList.item(0); for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { switch (child.getNodeType()) { case Node.TEXT_NODE: text = normalizeText(text, child.getNodeValue()); break; default: break; } } return text == null ? text : text.trim(); } /* * Inititialize and destroy */ public void init() { m_log.info("init()"); EventTrackingService.addObserver(this); SiteService siteService = (SiteService) ComponentManager.get(SiteService.class); ContentHostingService contentService = (ContentHostingService) ComponentManager.get(ContentHostingService.class); m_log.info("init() site m_adminSiteName == \"" + this.m_adminSiteName + "\""); if(isNull(this.m_adminSiteName)) { // can't create m_log.info("init() m_adminSiteName is null"); } else if(siteService.siteExists(this.m_adminSiteName)) { // no need to create m_log.info("init() site " + this.m_adminSiteName + " already exists"); } else if(!m_serverConfigurationService.getBoolean("citationsAdmin.autocreate", true)) { //do not autocreate m_log.info("init() skipping autocreate of citationsAdmin site"); } else { SecurityAdvisor pushed = null; // need to create try { pushed = enableSecurityAdvisor(); Session s = m_sessionManager.getCurrentSession(); s.setUserId(UserDirectoryService.ADMIN_ID); Site adminSite = siteService.addSite(this.m_adminSiteName, "project"); adminSite.setTitle("Citations Admin"); adminSite.setPublished(true); adminSite.setJoinable(false); // add Resources tool SitePage page = adminSite.addPage(); page.setTitle("Resources"); page.addTool("sakai.resources"); siteService.save(adminSite); m_log.debug("init() site " + this.m_adminSiteName + " has been created"); } catch (IdInvalidException e) { // TODO Auto-generated catch block m_log.warn("IdInvalidException ", e); } catch (IdUsedException e) { // we've already verified that the site doesn't exist but // this can occur if site was created by another server // in a cluster that is starting up at the same time. m_log.warn("IdUsedException ", e); } catch (PermissionException e) { // TODO Auto-generated catch block m_log.warn("PermissionException ", e); } catch (IdUnusedException e) { // TODO Auto-generated catch block m_log.warn("IdUnusedException ", e); } finally { if(pushed != null) { boolean found = false; while(SecurityService.hasAdvisors() && ! found) { SecurityAdvisor popped = SecurityService.popAdvisor(); found = pushed == popped; } } } } for(String config : this.m_configs) { String configFileRef = this.getConfigFolderReference() + config; updateConfig(configFileRef); } } public void destroy() { m_log.info("destroy()"); } /* * Getters/setters for components.xml parameters */ /** * @return the OSID package name */ public String getOsidImpl() { return m_osidImpl; } /** * @param osidImpl the OSID package name */ public void setOsidImpl(String osidImpl) { m_osidImpl = osidImpl; } /** * @return the extended Repository ID */ public String getExtendedRepositoryId() { return m_extendedRepositoryId; } /** * @param extendedRepositoryId the extended Repository ID */ public void setExtendedRepositoryId(String extendedRepositoryId) { m_extendedRepositoryId = extendedRepositoryId; } /** * @return the m_metasearchUsername */ public String getMetasearchUsername() { return m_metasearchUsername; } /** * @param username the m_metasearchUsername to set */ public void setMetasearchUsername(String username) { m_metasearchUsername = username; } /** * @return the m_metasearchBaseUrl */ public String getMetasearchBaseUrl() { return m_metasearchBaseUrl; } /** * @param baseUrl the m_metasearchBaseUrl to set */ public void setMetasearchBaseUrl(String baseUrl) { m_metasearchBaseUrl = baseUrl; } /** * @return the m_metasearchPassword */ public String getMetasearchPassword() { return m_metasearchPassword; } /** * @param password the m_metasearchPassword to set */ public void setMetasearchPassword(String password) { m_metasearchPassword = password; } /** * @return the Google base URL */ public String getGoogleBaseUrl() { return m_googleBaseUrl; } /** * @param googleBaseUrl the base URL to set */ public void setGoogleBaseUrl(String googleBaseUrl) { m_googleBaseUrl = googleBaseUrl; } /** * @return the sakaiServerKey */ public String getSakaiServerKey() { return m_sakaiServerKey; } /** * @param sakaiServerKey the sakaiServerKey to set */ public void setSakaiServerKey(String sakaiId) { m_sakaiServerKey = sakaiId; } /** * @return the OpenURL label */ public String getOpenUrlLabel() { return m_openUrlLabel; } /** * @param set the OpenURL label */ public void setOpenUrlLabel(String openUrlLabel) { m_openUrlLabel = openUrlLabel; } /** * @return the OpenURL resolver address */ public String getOpenUrlResolverAddress() { return m_openUrlResolverAddress; } /** * @param set the OpenURL resolver address */ public void setOpenUrlResolverAddress(String openUrlResolverAddress) { m_openUrlResolverAddress = openUrlResolverAddress; } /** * @return the database hierarchy XML filename/URI */ public String getDatabaseXml() { return m_databaseXml; } /** * @param set the database hierarchy XML filename/URI */ public void setDatabaseXml(String databaseXml) { m_databaseXml = databaseXml; } /** * @return the configuration XML filename/URI */ public String getSiteConfigXml() { return m_siteConfigXml; } /** * @param set the configuration XML filename/URI */ public void setSiteConfigXml(String siteConfigXml) { m_siteConfigXml = siteConfigXml; } /** * @return the serverConfigurationService */ public ServerConfigurationService getServerConfigurationService() { return m_serverConfigurationService; } /** * @param serverConfigurationService the serverConfigurationService to set */ public void setServerConfigurationService(ServerConfigurationService serverConfigurationService) { m_serverConfigurationService = serverConfigurationService; } /** * @param sessionManager the SessionManager to save */ public void setSessionManager(SessionManager sessionManager) { m_sessionManager = sessionManager; } /** * @return the SessionManager */ public SessionManager getSessionManager() { return m_sessionManager; } /** * @return the site specific "OSID configuration" package name */ public String getOsidConfig() { return m_osidConfig; } /** * @param osidConfig the site specific "OSID configuration" package name */ public void setOsidConfig(String osidConfig) { m_osidConfig = osidConfig; } /** * @return Google search support status */ public String getGoogleSearchEnabled() { return m_googleSearchEnabled; } /** * @param googleSearchEnabled ("true" or "false") */ public void setGoogleSearchEnabled(String googleSearchEnabled) { if (googleSearchEnabled.equalsIgnoreCase("true") || googleSearchEnabled.equalsIgnoreCase("false")) { m_googleSearchEnabled = googleSearchEnabled; return; } m_log.warn("Invalid Google support setting \"" + googleSearchEnabled + "\", disabling Google search"); m_googleSearchEnabled = "false"; } /** * @return library search support status */ public String getLibrarySearchEnabled() { return m_librarySearchEnabled; } /** * @param librarySearchEnabled ("true" or "false") */ public void setLibrarySearchEnabled(String librarySearchEnabled) { if (librarySearchEnabled.equalsIgnoreCase("true") || librarySearchEnabled.equalsIgnoreCase("false")) { m_librarySearchEnabled = librarySearchEnabled; return; } m_log.warn("Invalid library support setting \"" + librarySearchEnabled + "\", disabling library search"); m_librarySearchEnabled = "false"; } /** * @return the adminSiteName */ public String getAdminSiteName() { return m_adminSiteName; } /** * @param adminSiteName the adminSiteName to set */ public void setAdminSiteName(String adminSiteName) { this.m_adminSiteName = adminSiteName; } /** * @return the configFolder */ public String getConfigFolder() { return m_configFolder; } /** * @param configFolder the configFolder to set */ public void setConfigFolder(String configFolder) { this.m_configFolder = configFolder; } /** * @return the configFile */ public String getConfigXmlCache() { StringBuilder buf = new StringBuilder(); for(Iterator<String> it = this.m_configs.iterator(); it.hasNext();) { String str = it.next(); buf.append(str); if(it.hasNext()) { buf.append(','); } } return buf.toString(); } /** * @param configFile the configFile to set */ public void setConfigXmlCache(String configXml) { this.m_configs = new TreeSet<String>(); if(!isNull(configXml)) { String[] configs = configXml.split("\\s*,\\s*"); for(String config : configs) { this.m_configs.add(config); } } } /** * @return the categoriesXml resource names */ public String getDatabaseXmlCache() { StringBuilder buf = new StringBuilder(); for(Iterator<String> it = this.m_categories.iterator(); it.hasNext();) { String str = it.next(); buf.append(str); if(it.hasNext()) { buf.append(','); } } return buf.toString(); } /** * @param categoriesXml the categoriesXml to set */ public void setDatabaseXmlCache(String categoriesXml) { this.m_categories = new TreeSet<String>(); if(!isNull(categoriesXml)) { String[] categories = categoriesXml.split("\\s*,\\s*"); for(String category : categories) { this.m_categories.add(category); } } } /** * @return the saveciteClients */ public Map<String, List<Map<String,String>>> getSaveciteClients() { return saveciteClients; } /** * @param saveciteClients the saveciteClients to set */ public void setSaveciteClients(Map<String, List<Map<String,String>>> saveciteClients) { m_log.info("saveciteClients updated"); this.saveciteClients = saveciteClients; if(m_log.isDebugEnabled()) { if(this.saveciteClients == null) { m_log.debug("setSaveciteClients() called but saveciteClients is null"); return; } StringBuilder buf = new StringBuilder("setSaveciteClients()\n"); buf.append('\n'); buf.append('\n'); addMapToStringBuilder(buf,this.saveciteClients,4,4); buf.append('\n'); buf.append('\n'); m_log.debug(buf.toString()); } } public List<Map<String, String>> getSaveciteClientsForLocale(Locale locale) { List<Map<String, String>> clients = null; if(this.saveciteClients == null || this.saveciteClients.isEmpty()) { clients = new ArrayList<Map<String, String>>(); } else if(this.saveciteClients.containsKey(locale.toString())) { clients = this.saveciteClients.get(locale.toString()); } else if(this.saveciteClients.containsKey(locale.getLanguage() + "_" + locale.getCountry())) { clients = this.saveciteClients.get(locale.getLanguage() + "_" + locale.getCountry()); } else if(this.saveciteClients.containsKey(locale.getLanguage())) { clients = this.saveciteClients.get(locale.getLanguage()); } else if(this.saveciteClients.containsKey(SERVER_DEFAULT_LOCALE)) { clients = this.saveciteClients.get(SERVER_DEFAULT_LOCALE); } else { clients = new ArrayList<Map<String, String>>(); } return clients; } protected void addMapToStringBuilder(StringBuilder buf, Map map, int indent, int indentIncrement) { for(Entry<String,Object> entry : ((Map<String,Object>) map).entrySet()) { String key = entry.getKey(); for(int i = 0; i < indent; i++) { buf.append(' '); } buf.append(key); Object val = entry.getValue(); if(val instanceof Map) { buf.append('\n'); addMapToStringBuilder(buf,(Map) val,indent + indentIncrement, indentIncrement); } else if(val instanceof List) { addListToStringBuilder(buf, (List) val, indent + indentIncrement, indentIncrement); } else { buf.append(" == "); buf.append(val); buf.append('\n'); } } } protected void addListToStringBuilder(StringBuilder buf, List list, int indent, int indentIncrement) { buf.append('\n'); for(Object val : list) { if(val instanceof Map) { addMapToStringBuilder(buf,(Map) val,indent + indentIncrement, indentIncrement); } else if(val instanceof List) { for(int i = 0; i < indent; i++) { buf.append(' '); } buf.append("----------\n"); for(int i = 0; i < indent; i++) { buf.append(' '); } addListToStringBuilder(buf, (List) val, indent + indentIncrement, indentIncrement); } else { for(int i = 0; i < indent; i++) { buf.append(' '); } buf.append(val); buf.append('\n'); } } } public Collection<String> getAllCategoryXml() { return new TreeSet<String>(this.m_categories); } /* * Configuration update */ /** * Called when an observed object chnages (@see java.util.Observer#update) * @param arg0 - The observed object * @param arg1 - Event argument */ public void update(Observable arg0, Object arg1) { if (arg1 instanceof Event) { Event event = (Event) arg1; /* * Modified? If so (and this is our file) update the the configuration */ if (event.getModify()) { String refstr = event.getResource(); if (this.m_updatableResources.contains(refstr)) { m_log.debug("Updating configuration from " + refstr); updateConfig(refstr); } } } } /** * Update configuration data from an XML resource * @param configFileRef XML configuration reference (/content/...) */ protected void updateConfig(String configFileRef) { Reference ref = EntityManager.newReference(configFileRef); SecurityAdvisor pushed = null; if (ref != null) { try { ContentResource resource; /* * Fetch configuration details from our XML resource */ pushed = enableSecurityAdvisor(); resource = org.sakaiproject.content.cover.ContentHostingService.getResource(ref.getId()); if (resource != null) { populateConfig(configFileRef, resource.streamContent()); } } catch (PermissionException e) { m_log.warn("Exception: " + e + ", continuing"); } catch (IdUnusedException e) { m_log.warn("Citations configuration XML is missing (" + configFileRef + "); Citations ConfigurationService will watch for its creation"); } catch (TypeException e) { m_log.warn("Exception: " + e + ", continuing"); } catch (ServerOverloadException e) { m_log.warn("Exception: " + e + ", continuing"); } finally { if(pushed != null) { boolean found = false; while(SecurityService.hasAdvisors() && ! found) { SecurityAdvisor popped = SecurityService.popAdvisor(); found = popped == pushed; } } } } /* * Always add our reference to the list of observed resources */ m_updatableResources.add(configFileRef); } /* * Miscellanous helpers */ /** * Does the specified configuration/hierarchy resource exist? * @param resourceName Resource name * @return true If we can access this content */ private boolean exists(String resourceName) { SecurityAdvisor pushed = null; try { String configFolderRef = getConfigFolderReference(); if (!isNull(configFolderRef) && !isNull(resourceName)) { String referenceName = configFolderRef + resourceName; Reference reference = EntityManager.newReference(referenceName); if (reference == null) return false; pushed = enableSecurityAdvisor(); ContentResource resource = org.sakaiproject.content.cover.ContentHostingService.getResource(reference.getId()); return (resource != null); } } catch (IdUnusedException exception) { m_log.debug("exists() failed find resource: " + exception); } catch (Exception exception) { m_log.warn("exists() failed find resource: ", exception); } finally { if(pushed != null) { boolean found = false; while(SecurityService.hasAdvisors() && ! found) { SecurityAdvisor popped = SecurityService.popAdvisor(); found = popped == pushed; } } } return false; } /** * Establish a security advisor to allow the "embedded" azg work to occur * with no need for additional security permissions. * @return the advisor */ protected SecurityAdvisor enableSecurityAdvisor() { SecurityAdvisor advisor = new SecurityAdvisor() { public SecurityAdvice isAllowed(String userId, String function, String reference) { return SecurityAdvice.ALLOWED; } }; // put in a security advisor so we can create citationAdmin site without need // of further permissions SecurityService.pushAdvisor(advisor ); return advisor; } /** * Null (or empty) String? * @param string String to check * @return true if so */ private boolean isNull(String string) { return (string == null) || (string.trim().equals("")); } /** * Is library search enabled for the current user? * @return true if so */ public boolean librarySearchEnabled() { return isLibrarySearchEnabled() && isConfigurationXmlAvailable() && isDatabaseHierarchyXmlAvailable(); } public void setExternalSearchEnabled(boolean state) { this.m_externalSearchEnabled = state; } public boolean isExternalSerarchEnabled() { boolean enabled = m_externalSearchEnabled; String state = getConfigurationParameter("external-search-enabled"); if (state != null) { enabled = "true".equals(state); } m_log.debug("External Search enabled: " + enabled); return enabled && getExternalSearchUrl() != null; } public void setExternalSearchUrl(String url) { this.m_externalSearchUrl = url; } public String getExternalSearchUrl() { String url = getConfigurationParameter("external-search-url"); if (url == null) { url = m_externalSearchUrl; } return url; } /* * (non-Javadoc) * @see org.sakaiproject.citation.api.ConfigurationService#getSecondsBetweenSaveciteRefreshes() */ public String getSecondsBetweenSaveciteRefreshes() { String secondsBetweenRefreshes = this.getConfigurationParameter(PARAM_SECONDS_BETWEEN_SAVECITE_REFRESHES); if(secondsBetweenRefreshes == null) { // no stored value for secondsBetweenRefreshes; use default secondsBetweenRefreshes = DEFAULT_SECONDS_BETWEEN_SAVECITE_REFRESHES; } else { try { int num = Integer.parseInt(secondsBetweenRefreshes); if(num < 1) { // stored value of secondsBetweenRefreshes is too small; use default secondsBetweenRefreshes = DEFAULT_SECONDS_BETWEEN_SAVECITE_REFRESHES; } else if(num > MAXIMUM_SECONDS_BETWEEN_SAVECITE_REFRESHES) { // stored value of secondsBetweenRefreshes is too big; use max secondsBetweenRefreshes = Integer.toString(MAXIMUM_SECONDS_BETWEEN_SAVECITE_REFRESHES); } } catch(NumberFormatException e) { // stored value of secondsBetweenRefreshes is not a number; use default secondsBetweenRefreshes = DEFAULT_SECONDS_BETWEEN_SAVECITE_REFRESHES; } } return secondsBetweenRefreshes ; } }