/** * '$RCSfile$' * Copyright: 2000-2011 Regents of the University of California and the * National Center for Ecological Analysis and Synthesis * * '$Author: leinfelder $' * '$Date: 2012-11-29 16:52:29 -0800 (Thu, 29 Nov 2012) $' * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package edu.ucsb.nceas.metacat.index; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.sql.SQLException; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.servlet.SolrRequestParsers; import org.dataone.service.exceptions.NotFound; import org.dataone.service.exceptions.NotImplemented; import org.dataone.service.exceptions.UnsupportedType; import org.dataone.service.types.v1.Event; import org.dataone.service.types.v1.Identifier; import org.dataone.service.types.v1.Subject; import org.dataone.service.types.v2.SystemMetadata; import org.dataone.service.util.Constants; import org.xml.sax.SAXException; import edu.ucsb.nceas.metacat.DBTransform; import edu.ucsb.nceas.metacat.EventLog; import edu.ucsb.nceas.metacat.common.index.IndexTask; import edu.ucsb.nceas.metacat.common.query.SolrQueryResponseWriterFactory; import edu.ucsb.nceas.metacat.common.query.SolrQueryService; import edu.ucsb.nceas.metacat.common.query.SolrQueryServiceController; import edu.ucsb.nceas.metacat.common.query.stream.ContentTypeByteArrayInputStream; import edu.ucsb.nceas.metacat.dataone.hazelcast.HazelcastService; import edu.ucsb.nceas.utilities.PropertyNotFoundException; /** * This class will query the solr server and return the result. * @author tao * */ public class MetacatSolrIndex { //public static final String SOLRQUERY = "solr"; //public static final String SOLR_HOME_PROPERTY_NAME = "solr.homeDir"; //public static final String SOLR_CONFIG_FILE_NAME_PROPERTY_NAME = "solr.configFileName"; //public static final String SOLR_COLLECTION_NAME_PROPERTY_NAME = "solr.collectionName"; //public static final String SOLR_SERVER_CLASSNAME_PROPERTY_NAME = "solr.server.classname"; private static Log log = LogFactory.getLog(MetacatSolrIndex.class); private static MetacatSolrIndex solrIndex = null; public static MetacatSolrIndex getInstance() throws Exception { if (solrIndex == null) { solrIndex = new MetacatSolrIndex(); } return solrIndex; } /** * Constructor * @throws SAXException * @throws IOException * @throws ParserConfigurationException */ private MetacatSolrIndex() throws Exception { } /** * Query the solr server * @param query the solr query * @param authorizedSubjects the authorized subjects in this query session * @param isMNadmin the indicator of the authorized subjects are the mn admin or not * @return the result as the InputStream * @throws SolrServerException * @throws ClassNotFoundException * @throws SQLException * @throws PropertyNotFoundException * @throws SAXException * @throws ParserConfigurationException * @throws UnsupportedType * @throws NotFound * @throws NotImplemented */ public InputStream query(String query, SetauthorizedSubjects, boolean isMNadmin) throws SolrServerException, IOException, PropertyNotFoundException, SQLException, ClassNotFoundException, ParserConfigurationException, SAXException, NotImplemented, NotFound, UnsupportedType { // allow "+" in query syntax, see: https://projects.ecoinformatics.org/ecoinfo/issues/6435 query = query.replaceAll("\\+", "%2B"); SolrParams solrParams = SolrRequestParsers.parseQueryString(query); return query(solrParams, authorizedSubjects, isMNadmin); } /** * Handle the query when the query is on the key/value format * @param solrParams the query with the key/value format * @param authorizedSubjects the authorized subjects in this query session * @param isMNadmin the indicator of the authorized subjects are the mn admin or not * @return the query result as the InputStream object * @throws SolrServerException * @throws IOException * @throws PropertyNotFoundException * @throws SQLException * @throws ClassNotFoundException * @throws ParserConfigurationException * @throws SAXException * @throws NotImplemented * @throws NotFound * @throws UnsupportedType */ public InputStream query(SolrParams solrParams, SetauthorizedSubjects, boolean isMNadmin) throws SolrServerException, IOException, PropertyNotFoundException, SQLException, ClassNotFoundException, ParserConfigurationException, SAXException, NotImplemented, NotFound, UnsupportedType { if(authorizedSubjects == null || authorizedSubjects.isEmpty()) { //throw new SolrServerException("MetacatSolrIndex.query - There is no any authorized subjects(even the public user) in this query session."); Subject subject = new Subject(); subject.setValue(Constants.SUBJECT_PUBLIC); authorizedSubjects = new HashSet(); authorizedSubjects.add(subject); } if(isMNadmin) { authorizedSubjects = null;//bypass the access rule since it is mn admin log.debug("MetacatSolrIndex.query - this is the mn admin object and the query will bypass the access controls rules."); } InputStream inputStream = null; String wt = solrParams.get(SolrQueryService.WT); // handle normal and skin-based queries if (SolrQueryService.isSupportedWT(wt)) { // just handle as normal solr query inputStream = SolrQueryServiceController.getInstance().query(solrParams, authorizedSubjects); } else { // assume it is a skin name String qformat = wt; // perform the solr query using wt=XML wt = SolrQueryResponseWriterFactory.XML; ModifiableSolrParams msp = new ModifiableSolrParams(solrParams); msp.set(SolrQueryService.WT, wt); inputStream = SolrQueryServiceController.getInstance().query(msp, authorizedSubjects); // apply the stylesheet (XML->HTML) DBTransform transformer = new DBTransform(); String documentContent = IOUtils.toString(inputStream, "UTF-8"); String sourceType = "solr"; String targetType = "-//W3C//HTML//EN"; ByteArrayOutputStream baos = new ByteArrayOutputStream(); Writer writer = new OutputStreamWriter(baos , "UTF-8"); // TODO: include more params? Hashtable params = new Hashtable(); params.put("qformat", new String[] {qformat}); transformer.transformXMLDocument( documentContent , sourceType, targetType , qformat, writer, params, null //sessionid ); // finally, get the HTML back inputStream = new ContentTypeByteArrayInputStream(baos.toByteArray()); ((ContentTypeByteArrayInputStream) inputStream).setContentType("text/html"); } return inputStream; } /** * Submit a deleting-index task * @param pid the pid's solr document will be deleted. */ public void submitDeleteTask(Identifier pid, SystemMetadata sysMeta) { IndexTask task = new IndexTask(); task.setSystemMetadata(sysMeta); task.setIsDeleteing(true); if(pid != null) { log.debug("MetacatSolrIndex.submitDeleteTask - will put the pid "+pid.getValue()+" into the index queue on hazelcast service."); HazelcastService.getInstance().getIndexQueue().put(pid, task); log.info("MetacatSolrIndex.submitDeleteTask - put the pid "+pid.getValue()+" into the index queue on hazelcast service successfully."); } } public void submit(Identifier pid, SystemMetadata systemMetadata, Map> fields, boolean followRevisions) { IndexTask task = new IndexTask(); task.setSystemMetadata(systemMetadata); task.setFields(fields); if(pid != null) { log.debug("MetacatSolrIndex.submit - will put the pid "+pid.getValue()+" into the index queue on hazelcast service."); } HazelcastService.getInstance().getIndexQueue().put(pid, task); if(pid != null) { log.info("MetacatSolrIndex.submit - put the pid "+pid.getValue()+" into the index queue on hazelcast service successfully."); } // submit older revisions recursively otherwise they stay in the index! if (followRevisions && systemMetadata != null && systemMetadata.getObsoletes() != null) { Identifier obsoletedPid = systemMetadata.getObsoletes(); SystemMetadata obsoletedSysMeta = HazelcastService.getInstance().getSystemMetadataMap().get(obsoletedPid); Map> obsoletedFields = EventLog.getInstance().getIndexFields(obsoletedPid, Event.READ.xmlValue()); if(obsoletedPid != null && pid != null) { log.debug("MetacatSolrIndex.submit - We will index the old version "+obsoletedPid.getValue()+" of the object "+ pid.getValue() + " as well. So we put "+obsoletedPid.getValue()+" into the index queue on hazelcast service."); } this.submit(obsoletedPid, obsoletedSysMeta , obsoletedFields, followRevisions); } } }