package org.apache.solr.client; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import org.apache.solr.util.XML; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; /** * This class is for use in clients of the Solr webapp. Specifically, * it implements a set of methods that allow add, delete, commit and * optimize messages to be sent to the server without the caller having * to format XML messages. The APIs are exposed as normal java methods * and the XML generation and communication with the server happen behind * the scenes. *
* Usage is quite simple. Just construct an instance with the URL of the
* server you want to run against, then start calling add(),
* delete() and so on. The URL you use at construction time
* is typically something like "http://localhost:8983/solr/update"
* if you are using the standard distribution Solr webapp on your local machine.
* Obviously you will want to change this to hit other hosts as your needs
* dictate.
*
* Documents are represented as simple maps from
* We could have made a little document class to use as a parameter here, but it
* would have ended up just containing a map. Callers of this API are likely to
* be getting their data in any number of forms, so at least with the map
* representation, a non-zero percentage of them will be able to add documents
* without constructing objects of a special new class.
* @param document A document.
* @return status from the server.
* @throws SolrClientException
* @see #add(Collection)
*/
public int add(MapString to
* Object. If an object is multivalued, the value in the map
* can be either an array or a collection. The add code will iterate over
* all of the values and insert them correctly.
*
* @author vengroff
*/
public class DocumentManagerClient {
/**
* The URL of the Solr server.
*/
private URL solrServerUrl;
/**
* Factory for parsers for the XML we get back from the server.
*/
XmlPullParserFactory factory;
/**
* String representation of the last exception seen on the server side
* in handling one of our requests. This is normally set whenever we
* get a non-zero result from a server call.
*/
private String lastServerException = "";
/**
* This interface is for objects that write XML requests to the
* server. Normally, these objects are created on the fly and
* passed to ClientStub.serverCall(RequestWriter).
* All the public APIs that make calls to the server do so
* by constructing one of these and then passing it to
* serverCall(RequestWriter).
* @see DocumentManagerClient#serverCall(RequestWriter)
*/
protected static interface RequestWriter {
/**
* Write an XML request for a Solr server to the given writer.
* @param writer The writer to write the XML to.
* @throws IOException if writing fails.
*/
void writeRequest(Writer writer) throws IOException;
};
/**
* An implementation of the RequestWriter interface that writes
* a constant. Useful for e.g. commit and optimize messages.
*/
protected static class ConstantRequestWriter implements RequestWriter {
private final String constant;
/**
* @param constant
*/
public ConstantRequestWriter(String constant) {
this.constant = constant;
}
public void writeRequest(Writer writer) throws IOException {
writer.write(constant);
}
}
/**
* @param solrServerUrl The URL of the Solr server. For
* example, "http://localhost:8983/solr/update"
* if you are using the standard distribution Solr webapp
* on your local machine.
* @throws SolrClientException If unable to construct, typically
* due to some problem with the XPP parser factory.
*/
public DocumentManagerClient(URL solrServerUrl) throws SolrClientException {
this.solrServerUrl = solrServerUrl;
try {
factory = XmlPullParserFactory.newInstance();
} catch (XmlPullParserException e) {
throw new SolrClientException("Unable to get XPP factory instance", e);
}
factory.setNamespaceAware(false);
}
/**
* This is the meat of any call to the server. The specifics of what the call
* does are controlled by the RequestWriter that is passed in.
* @param requestWriter
* @return The status code from the server. If this is not 0, then the server
* exception that was returned from the server side is stored and can be examimed
* by calling getLastServerException().
* @throws SolrClientException to indicate there was a problem making the call.
* @see RequestWriter
*/
protected int serverCall(RequestWriter requestWriter) throws SolrClientException {
try {
URLConnection connection = solrServerUrl.openConnection();
connection.setDoOutput(true);
OutputStream outputStream = connection.getOutputStream();
try {
Writer writer = new OutputStreamWriter(outputStream);
try {
requestWriter.writeRequest(writer);
writer.close();
InputStream inputStream = connection.getInputStream();
try {
Reader reader = new InputStreamReader(inputStream);
try {
XmlPullParser xpp;
try {
xpp = factory.newPullParser();
xpp.setInput(reader);
xpp.nextTag();
} catch(XmlPullParserException e) {
throw new SolrClientException("XML parsing exception in solr client", e);
}
if(!"result".equals(xpp.getName())) {
throw new SolrClientException("Result from server is not rooted with a toString()
* is called on them to get strings to use as values in the XML sent to the server.
*