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.
* @throws SolrClientException if there is a client-side problem.
* @throws SolrServerException if there is a server-side problem.
* @see #add(Collection)
*/
public void 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;
/**
* 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
* @throws SolrClientException if there is a client-side problem.
* @throws SolrServerException if there is a server-side problem.
* @see RequestWriter
*/
protected void serverCall(RequestWriter requestWriter) throws SolrClientException, SolrServerException {
try {
URLConnection connection = solrServerUrl.openConnection();
connection.setDoOutput(true);
OutputStream outputStream = connection.getOutputStream();
try {
Writer writer = new OutputStreamWriter(outputStream);
try {
requestWriter.writeRequest(writer);
} finally {
writer.close();
}
} finally {
outputStream.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.
*