Project

General

Profile

1
/**
2
 *  Copyright: 2013 Regents of the University of California and the
3
 *             National Center for Ecological Analysis and Synthesis
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 */
19
package edu.ucsb.nceas.metacat.common.query;
20

    
21
import java.io.IOException;
22
import java.io.InputStream;
23
import java.net.MalformedURLException;
24
import java.net.URL;
25
import java.util.ArrayList;
26
import java.util.HashMap;
27
import java.util.List;
28
import java.util.Map;
29
import java.util.Set;
30
import java.util.Vector;
31

    
32
import javax.xml.parsers.DocumentBuilder;
33
import javax.xml.parsers.DocumentBuilderFactory;
34
import javax.xml.parsers.ParserConfigurationException;
35
import javax.xml.xpath.XPathConstants;
36
import javax.xml.xpath.XPathExpressionException;
37
import javax.xml.xpath.XPathFactory;
38

    
39
import org.apache.commons.codec.net.URLCodec;
40
import org.apache.commons.logging.Log;
41
import org.apache.commons.logging.LogFactory;
42
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
43
import org.apache.solr.client.solrj.util.ClientUtils;
44

    
45
import org.apache.solr.common.params.SolrParams;
46
import org.apache.solr.core.SolrConfig;
47
import org.apache.solr.schema.FieldType;
48
import org.apache.solr.schema.IndexSchema;
49
import org.apache.solr.schema.SchemaField;
50
import org.apache.solr.schema.TextField;
51
import org.dataone.configuration.Settings;
52
import org.dataone.service.exceptions.NotFound;
53
import org.dataone.service.exceptions.NotImplemented;
54
import org.dataone.service.types.v1.Subject;
55
import org.w3c.dom.Attr;
56
import org.w3c.dom.Document;
57
import org.w3c.dom.Element;
58
import org.w3c.dom.Node;
59
import org.w3c.dom.NodeList;
60
import org.xml.sax.Attributes;
61
import org.xml.sax.InputSource;
62
import org.xml.sax.SAXException;
63

    
64

    
65

    
66
/**
67
 * The query service for the http solr server.
68
 * @author tao
69
 *
70
 */
71
public class HttpSolrQueryService extends SolrQueryService {
72
    private static final String SELECTIONPHASE = "/select";
73
    private static final String SOLR_SYSTEMINFO_URLAPPENDIX = "solr.systeminfo.urlappendix";
74
    private static final String SOLR_SCHEMA_URLAPPENDIX = "sorl.schema.urlappendix";
75
    private static final String SOLR_CONFIG_URLAPPENDIX = "solr.config.urlappendix";
76
    private static final String SPEC_PATH = "//str[@name='solr-spec-version']";
77
    private static final String FIELDS_PATH = "//fields//field";
78
    private static final String COPY_FIELDS_PATH = "//copyField";
79
    private static final String DEST = "dest";
80
    private static final String TRUE = "true";
81
    
82
    private String solrServerBaseURL = null;
83
    private CommonsHttpSolrServer httpSolrServer = null;
84
    private static Log log = LogFactory.getLog(HttpSolrQueryService.class);
85
    /**
86
     * Constructor
87
     * @param httpSolrServer
88
     */
89
    public HttpSolrQueryService(CommonsHttpSolrServer httpSolrServer) {
90
        if(httpSolrServer == null) {
91
            throw new NullPointerException("HttpSolrQueryService.constructor - The httpSolrServer parameter can't be null");
92
        }
93
        this.httpSolrServer = httpSolrServer;
94
        this.solrServerBaseURL = httpSolrServer.getBaseURL();
95
    }
96
    
97
    /**
98
     * Query the Solr server with specified query string and the user's identity. This is the for the http solr server.
99
     * It is hard to transform the SolrQueryReponse object to the InputStream object for the HttpSolrServer
100
     * since the transform needs the SolrCore. We have to open the solr url directly to get the InputStream.
101
     * @param query the query string
102
     * @param subjects the user's identity which sent the query
103
     * @return the response
104
     * @throws NotFound 
105
     * @throws IOException 
106
     * @throws Exception
107
     */
108
    /*public InputStream query(String query, Set<Subject>subjects) throws NotFound, IOException {
109
        StringBuffer accessFilter = generateAccessFilterParamsString(subjects);
110
        if(accessFilter != null && accessFilter.length() != 0) {
111
            query = solrServerBaseURL+"/select?"+query+"&"+FILTERQUERY+"="+accessFilter.toString();
112
            query = ClientUtils.escapeQueryChars(query);
113
        } else {
114
            throw new NotFound("0000", "HttpSolrQueryService.query - There is no identity (even user public) for the user who issued the query");
115
        }
116
        log.info("==========HttpSolrQueryService.query - the final url for querying the solr http server is "+query);
117
        URL url = new URL(query);
118
        
119
        return url.openStream();
120
    }*/
121
    
122
    /**
123
     * Query the Solr server with specified query and user's identity. 
124
     * It is hard to transform the SolrQueryReponse object to the InputStream object for the HttpSolrServer
125
     * since the transform needs the SolrCore. We have to open the solr url directly to get the InputStream.
126
     * @param query the query params. 
127
     * @param subjects the user's identity which sent the query. If the Subjects is null, there wouldn't be any access control.
128
     * @return the response
129
     * @throws IOException 
130
     * @throws NotFound 
131
     * @throws Exception
132
     */
133
    public  InputStream query(SolrParams query, Set<Subject>subjects) throws IOException, NotFound {
134
        boolean xmlFormat = false;
135
        String queryString = ClientUtils.toQueryString(query, xmlFormat);
136
        log.info("==========HttpSolrQueryService.query - the query string after transforming from the SolrParams to the string "+queryString);
137
        StringBuffer accessFilter = generateAccessFilterParamsString(subjects);
138
        if(accessFilter != null && accessFilter.length() != 0) {
139
            String accessStr = accessFilter.toString();
140
            log.debug("==========HttpSolrQueryService.query - the access string is "+accessStr);
141
            URLCodec urlCodec = new URLCodec();
142
            accessStr = urlCodec.encode(accessStr, "UTF-8");
143
            log.debug("==========HttpSolrQueryService.query - the access string after escape special characters string "+accessStr);
144
            queryString = queryString+"&"+FILTERQUERY+"="+accessStr;
145
           
146
        }
147
        
148
        
149
        //queryString = ClientUtils.escapeQueryChars(queryString);
150
        queryString = solrServerBaseURL+SELECTIONPHASE+queryString;
151
        log.info("==========HttpSolrQueryService.query - the final url for querying the solr http server is "+queryString);
152
        URL url = new URL(queryString);    
153
        return url.openStream();
154
        //throw new NotImplemented("0000", "HttpSolrQueryService - the method of  query(SolrParams query, Set<Subject>subjects) is not for the HttpSolrQueryService. We donot need to implemente it");
155
    }
156
    
157
    
158
    
159
    
160
    /**
161
     * Get the fields list of the index schema
162
     * @return
163
     * @throws SAXException 
164
     * @throws IOException 
165
     * @throws ParserConfigurationException 
166
     * @throws MalformedURLException 
167
     * @throws Exception
168
     */
169
    public  Map<String, SchemaField> getIndexSchemaFields() throws MalformedURLException, ParserConfigurationException, IOException, SAXException  {
170
        if(fieldMap == null || fieldMap.isEmpty()) {
171
            getIndexSchemaFieldFromServer();
172
        }
173
        //System.out.println("get filed map ==========================");
174
        return fieldMap;
175
    }
176
    
177
   
178
    
179
    /**
180
     * Get the list of the valid field name (moved the fields names of the CopyFieldTarget).
181
     * @return
182
     * @throws SAXException 
183
     * @throws IOException 
184
     * @throws ParserConfigurationException 
185
     * @throws MalformedURLException 
186
     */
187
    public List<String> getValidSchemaField() throws MalformedURLException, ParserConfigurationException, IOException, SAXException {
188
        if(fieldMap == null || fieldMap.isEmpty()) {
189
            getIndexSchemaFields();
190
        }
191
        return super.getValidSchemaFields();
192
    }
193
    
194
   
195
    /*
196
     * Get the fieldMap from the http server. 
197
     * @throws MalformedURLException
198
     * @throws ParserConfigurationException
199
     * @throws IOException
200
     * @throws SAXException
201
     */
202
    private void getIndexSchemaFieldFromServer() throws MalformedURLException, ParserConfigurationException, IOException, SAXException {
203
        //System.out.println("get filed map from server (downloading files) ==========================");
204
        SolrConfig config = new SolrConfig("dataone", new InputSource(getSolrConfig())); 
205
        schema = new IndexSchema(config, "dataone", new InputSource(getSchema()));
206
        fieldMap = schema.getFields();
207
    }
208
    
209
    /*
210
     * Parse the schema.xml and get the validSolrFieldName list
211
     */
212
    /*private void parseSchema() throws MalformedURLException, ParserConfigurationException, SAXException, IOException, XPathExpressionException {
213
        validSolrFieldNames = new ArrayList<String>();
214
        Map<String, SchemaField> fieldMap = new HashMap<String, SchemaField>();
215
        Document schema = transformInputStreamToDoc(getSchema());
216
        Vector<String>copyFieldTargetNames = new Vector<String>();
217
        NodeList copyFields = (NodeList) XPathFactory.newInstance().newXPath()
218
                        .evaluate(COPY_FIELDS_PATH, schema, XPathConstants.NODESET);
219
        if(copyFields != null) {
220
            for(int i=0; i<copyFields.getLength(); i++) {
221
                Element copyField = (Element)copyFields.item(i);
222
                String target = copyField.getAttribute(DEST);
223
                if(target != null && !target.trim().equals("")) {
224
                    copyFieldTargetNames.add(target);
225
                }
226
            }
227
        }
228
        NodeList fields = (NodeList) XPathFactory.newInstance().newXPath()
229
                        .evaluate(FIELDS_PATH, schema, XPathConstants.NODESET);
230
        if(fields!= null) {
231
            for(int i=0; i<fields.getLength(); i++) {
232
                Element fieldElement = (Element) fields.item(i);
233
                String name = fieldElement.getAttribute("name");
234
                if(name != null && !name.trim().equals("")) {
235
                    if(!copyFieldTargetNames.contains(name)) {
236
                        validSolrFieldNames.add(name);
237
                    }
238
                }
239
            }
240
        }
241
    }*/
242
    
243
    
244
    /*
245
     * Get the SolrConfig InputStream.
246
     * @return
247
     * @throws MalformedURLException
248
     * @throws IOException
249
     */
250
    private InputStream getSolrConfig() throws MalformedURLException, IOException {
251
        String solrConfigAppendix = Settings.getConfiguration().getString(SOLR_CONFIG_URLAPPENDIX);
252
        String configURL = solrServerBaseURL+solrConfigAppendix;
253
        return (new URL(configURL)).openStream();
254
    }
255
    /*
256
     * Get the schema InputStream from the url which is specified in the metacat.properties and transform it to a Document.
257
     */
258
    private InputStream getSchema() throws MalformedURLException, IOException {
259
        String schemaURLAppendix = Settings.getConfiguration().getString(SOLR_SCHEMA_URLAPPENDIX);
260
        String schemaURL = solrServerBaseURL+schemaURLAppendix;
261
        return (new URL(schemaURL)).openStream();
262
    }
263
    
264
    /**
265
     * Get the version of the solr server.
266
     * @return
267
     */
268
    public String getSolrServerVersion() {
269
        if(solrSpecVersion == null) {
270
            getHttpSolrServerVersion();
271
        } 
272
        //System.out.println("get spec version  ==========================");
273
        return solrSpecVersion;
274
    }
275
    
276
    
277
    /*
278
     * Get the solr server version from the system information url. 
279
     */
280
    private void getHttpSolrServerVersion() {
281
        //System.out.println("get spec version from server (downloading files) ==========================");
282
        String systemInfoUrlAppendix = Settings.getConfiguration().getString(SOLR_SYSTEMINFO_URLAPPENDIX);
283
        String systemInfoUrl = solrServerBaseURL+systemInfoUrlAppendix;
284
        try {
285
            Document doc = transformInputStreamToDoc((new URL(systemInfoUrl)).openStream());
286
            NodeList nodeList = (NodeList) XPathFactory.newInstance().newXPath()
287
                            .evaluate(SPEC_PATH, doc, XPathConstants.NODESET);
288
            if(nodeList != null && nodeList.getLength() >0) {
289
                //System.out.println("nodelist is not null branch");
290
                Node specNode = nodeList.item(0);
291
                solrSpecVersion = specNode.getFirstChild().getNodeValue();
292
            } else {
293
                //System.out.println("nodelist is null branch");
294
                solrSpecVersion = UNKNOWN;
295
            }
296
            
297
        } catch (Exception e) {
298
            log.error("HttpSolrQueryService.getHttpSolrServerVersion - can't get the solr specification version since "+e.getMessage());
299
            solrSpecVersion = UNKNOWN;
300
        }
301
        
302
        
303
    }
304
    
305
    /**
306
     * Generate a Document from the InputStream
307
     * @param input
308
     * @return
309
     * @throws ParserConfigurationException
310
     * @throws SAXException
311
     * @throws IOException
312
     */
313
    private Document transformInputStreamToDoc(InputStream input) throws ParserConfigurationException, SAXException, IOException {
314
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
315
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
316
        Document doc = dBuilder.parse(input);
317
        return doc;
318
    }
319
    
320
 
321
}
(3-3/7)