diff --git a/src/test/org/apache/solr/servlet/DirectSolrConnectionTest.java b/src/test/org/apache/solr/servlet/DirectSolrConnectionTest.java
new file mode 100644
index 00000000000..688d692193a
--- /dev/null
+++ b/src/test/org/apache/solr/servlet/DirectSolrConnectionTest.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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.apache.solr.servlet;
+
+import org.apache.solr.request.SolrParams;
+import org.apache.solr.util.AbstractSolrTestCase;
+
+
+
+public class DirectSolrConnectionTest extends AbstractSolrTestCase
+{
+ public String getSchemaFile() { return "solr/crazy-path-to-schema.xml"; }
+ public String getSolrConfigFile() { return "solr/crazy-path-to-config.xml"; }
+
+ DirectSolrConnection direct;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ direct = new DirectSolrConnection();
+ }
+
+ // Check that a request gets back the echoParams call
+ public void testSimpleRequest() throws Exception
+ {
+ String pathAndParams = "/select?wt=xml&version=2.2&echoParams=explicit&q=*:*";
+
+ String got = direct.request( pathAndParams, null );
+
+ assertTrue( got.indexOf( "explicit" ) > 5 );
+
+
+ // It should throw an exception for unknown handler
+ try {
+ direct.request( "/path to nonexistang thingy!!", null );
+ fail( "should throw an exception" );
+ }
+ catch( Exception ex ){}
+ }
+
+
+ // Check that a request gets back the echoParams call
+ public void testInsertThenSelect() throws Exception
+ {
+ String value = "Kittens!!! \u20AC";
+ String[] cmds = new String[] {
+ "42",
+ "42"+value+"",
+ ""
+ };
+ String getIt = "/select?wt=xml&q=id:42";
+
+ // Test using the Stream body parameter
+ for( String cmd : cmds ) {
+ direct.request( "/update?"+SolrParams.STREAM_BODY+"="+cmd, null );
+ }
+ String got = direct.request( getIt, null );
+ assertTrue( got.indexOf( value ) > 0 );
+
+ // Same thing using the posted body
+ for( String cmd : cmds ) {
+ direct.request( "/update", cmd );
+ }
+ got = direct.request( getIt, null );
+ assertTrue( got.indexOf( value ) > 0 );
+ }
+}
diff --git a/src/test/test-files/solr/crazy-path-to-config.xml b/src/test/test-files/solr/crazy-path-to-config.xml
index 6c8a655c2c3..03a07739e07 100644
--- a/src/test/test-files/solr/crazy-path-to-config.xml
+++ b/src/test/test-files/solr/crazy-path-to-config.xml
@@ -62,6 +62,8 @@
implicit
+
+
diff --git a/src/webapp/src/org/apache/solr/servlet/DirectSolrConnection.java b/src/webapp/src/org/apache/solr/servlet/DirectSolrConnection.java
new file mode 100644
index 00000000000..dd554f30842
--- /dev/null
+++ b/src/webapp/src/org/apache/solr/servlet/DirectSolrConnection.java
@@ -0,0 +1,180 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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.apache.solr.servlet;
+
+import java.io.File;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.apache.solr.core.Config;
+import org.apache.solr.core.SolrConfig;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.core.SolrException;
+import org.apache.solr.request.MapSolrParams;
+import org.apache.solr.request.QueryResponseWriter;
+import org.apache.solr.request.SolrParams;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.request.SolrQueryResponse;
+import org.apache.solr.request.SolrRequestHandler;
+import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.util.ContentStream;
+import org.apache.solr.util.ContentStreamBase;
+
+/**
+ * DirectSolrConnection provides an interface to solr that is similar to
+ * the the HTTP interface, but does not require an HTTP connection.
+ *
+ * This class is designed to be as simple as possible and alow for more flexibility
+ * in how you interface to solr.
+ *
+ * @author ryan
+ * @version $Id$
+ * @since solr 1.2
+ */
+public class DirectSolrConnection
+{
+ final SolrCore core;
+ final SolrRequestParsers parser;
+
+ /**
+ * Initialize using the static singleton SolrCore.getSolrCore().
+ */
+ public DirectSolrConnection()
+ {
+ core = SolrCore.getSolrCore();
+ parser = new SolrRequestParsers( core, SolrConfig.config );
+ }
+
+ /**
+ * Initialize using an explicit SolrCore
+ */
+ public DirectSolrConnection( SolrCore c )
+ {
+ core = c;
+ parser = new SolrRequestParsers( core, SolrConfig.config );
+ }
+
+ /**
+ * This constructor is designed to make it easy for JNI embedded applications
+ * to setup the entire solr environment with a simple interface. It takes three parameters:
+ *
+ * instanceDir:
The solr instance directory. If null, it will check the standard
+ * places first (JNDI,properties,"solr" directory)
+ *
+ * dataDir:
where the index is stored.
+ *
+ * loggingPath:
Path to a java.util.logging.config.file. If the path represents
+ * an absolute path or is relative to the CWD, it will use that. Next it will try a path
+ * relative to the instanceDir. If none of these files exist, it will error.
+ */
+ public DirectSolrConnection( String instanceDir, String dataDir, String loggingPath )
+ {
+ // Set the instance directory
+ if( instanceDir != null ) {
+ if( Config.isInstanceDirInitialized() ) {
+ String dir = Config.getInstanceDir();
+ if( !dir.equals( instanceDir ) ) {
+ throw new SolrException( 500, "already initalized: "+dir );
+ }
+ }
+ Config.setInstanceDir( instanceDir );
+ }
+
+ // If a loggingPath is specified, try using that
+ if( loggingPath != null ) {
+ File loggingConfig = new File( loggingPath );
+ if( !loggingConfig.exists() ) {
+ loggingConfig = new File( new File(Config.getInstanceDir()), loggingPath );
+ }
+ if( loggingConfig.exists() ) {
+ System.setProperty("java.util.logging.config.file", loggingConfig.getAbsolutePath() );
+ }
+ else {
+ throw new SolrException( 500, "can not find logging file: "+loggingConfig );
+ }
+ }
+
+ // If the Data directory is specified, initalize SolrCore directly
+ if( dataDir != null ) {
+ core = new SolrCore( dataDir, new IndexSchema(instanceDir+"/conf/schema.xml"));
+ }
+ else {
+ core = SolrCore.getSolrCore();
+ }
+ parser = new SolrRequestParsers( core, SolrConfig.config );
+ }
+
+
+ /**
+ * For example:
+ *
+ * String json = solr.request( "/select?qt=dismax&wt=json&q=...", null );
+ * String xml = solr.request( "/update", " 0 ) {
+ path = pathAndParams.substring( 0, idx );
+ params = SolrRequestParsers.parseQueryString( pathAndParams.substring(idx+1) );
+ }
+ else {
+ path= pathAndParams;
+ params = new MapSolrParams( new HashMap() );
+ }
+
+ // Extract the handler from the path or params
+ SolrRequestHandler handler = core.getRequestHandler( path );
+ if( handler == null ) {
+ if( "/select".equals( path ) || "/select/".equalsIgnoreCase( path) ) {
+ String qt = params.get( SolrParams.QT );
+ handler = core.getRequestHandler( qt );
+ if( handler == null ) {
+ throw new SolrException( 400, "unknown handler: "+qt);
+ }
+ }
+ }
+ if( handler == null ) {
+ throw new SolrException( 400, "unknown handler: "+path );
+ }
+
+ // Make a stream for the 'body' content
+ List streams = new ArrayList( 1 );
+ if( body != null && body.length() > 0 ) {
+ streams.add( new ContentStreamBase.StringStream( body ) );
+ }
+
+ SolrQueryRequest req = parser.buildRequestFrom( params, streams );
+ SolrQueryResponse rsp = new SolrQueryResponse();
+ core.execute( handler, req, rsp );
+ if( rsp.getException() != null ) {
+ throw rsp.getException();
+ }
+
+ // Now write it out
+ QueryResponseWriter responseWriter = core.getQueryResponseWriter(req);
+ StringWriter out = new StringWriter();
+ responseWriter.write(out, req, rsp);
+ return out.toString();
+ }
+}