3838import org .apache .commons .cli .CommandLine ;
3939import org .apache .commons .cli .Option ;
4040import org .apache .commons .cli .Options ;
41- import org .apache .solr .client .solrj .io .Lang ;
4241import org .apache .solr .client .solrj .io .SolrClientCache ;
4342import org .apache .solr .client .solrj .io .Tuple ;
4443import org .apache .solr .client .solrj .io .comp .StreamComparator ;
4544import org .apache .solr .client .solrj .io .stream .PushBackStream ;
4645import org .apache .solr .client .solrj .io .stream .SolrStream ;
4746import org .apache .solr .client .solrj .io .stream .StreamContext ;
4847import org .apache .solr .client .solrj .io .stream .TupleStream ;
48+ import org .apache .solr .client .solrj .io .stream .expr .DefaultStreamFactory ;
4949import org .apache .solr .client .solrj .io .stream .expr .Explanation ;
5050import org .apache .solr .client .solrj .io .stream .expr .Expressible ;
5151import org .apache .solr .client .solrj .io .stream .expr .StreamExpression ;
52- import org .apache .solr .client .solrj .io .stream .expr .StreamExpressionParser ;
5352import org .apache .solr .client .solrj .io .stream .expr .StreamFactory ;
53+ import org .apache .solr .client .solrj .jetty .HttpJettySolrClient ;
5454import org .apache .solr .common .SolrException ;
5555import org .apache .solr .common .params .ModifiableSolrParams ;
56+ import org .apache .solr .common .util .IOUtils ;
5657import org .apache .solr .handler .CatStream ;
5758
5859/** Supports stream command in the bin/solr script. */
@@ -62,8 +63,6 @@ public StreamTool(ToolRuntime runtime) {
6263 super (runtime );
6364 }
6465
65- private final SolrClientCache solrClientCache = new SolrClientCache ();
66-
6766 @ Override
6867 public String getName () {
6968 return "stream" ;
@@ -166,14 +165,30 @@ public void runImpl(CommandLine cli) throws Exception {
166165 }
167166 }
168167
169- PushBackStream pushBackStream ;
170- if (execution .equalsIgnoreCase ("local" )) {
171- pushBackStream = doLocalMode (cli , expr );
172- } else {
173- pushBackStream = doRemoteMode (cli , expr );
168+ // Validate inputs before opening any connection to Solr.
169+ boolean local = execution .equalsIgnoreCase ("local" );
170+ if (!local ) {
171+ if (!cli .hasOption (COLLECTION_OPTION )) {
172+ throw new IllegalStateException (
173+ "You must provide --name COLLECTION with --execution remote parameter." );
174+ }
175+ if (expr .toLowerCase (Locale .ROOT ).contains ("stdin(" )) {
176+ throw new IllegalStateException (
177+ "The stdin() expression is only usable with --execution local." );
178+ }
174179 }
175180
181+ // a stream needs a context
182+ StreamContext streamContext = createStreamContext (cli );
183+ // create the stream
184+ PushBackStream pushBackStream = null ;
176185 try {
186+ if (local ) {
187+ pushBackStream = doLocalMode (expr , streamContext .getStreamFactory ());
188+ } else {
189+ pushBackStream = doRemoteMode (expr , cli );
190+ }
191+ pushBackStream .setStreamContext (streamContext );
177192 pushBackStream .open ();
178193
179194 if (outputHeaders == null ) {
@@ -226,36 +241,60 @@ public void runImpl(CommandLine cli) throws Exception {
226241 }
227242 }
228243 } finally {
229- pushBackStream .close ();
230- solrClientCache .close ();
244+ if (pushBackStream != null ) {
245+ pushBackStream .close ();
246+ }
247+ streamContext .getSolrClientCache ().close ();
231248 }
232249
233250 echoIfVerbose ("StreamTool -- Done." );
234251 }
235252
253+ private StreamContext createStreamContext (CommandLine cli ) throws Exception {
254+ var jettyClientBuilder = new HttpJettySolrClient .Builder ();
255+ String credentials = cli .getOptionValue (CommonCLIOptions .CREDENTIALS_OPTION );
256+ jettyClientBuilder .withOptionalBasicAuthCredentials (credentials );
257+ HttpJettySolrClient client = jettyClientBuilder .build ();
258+
259+ // subclass so we can ensure our client is closed when the cache is closed
260+ var solrClientCache =
261+ new SolrClientCache (client ) {
262+ @ Override
263+ public synchronized void close () {
264+ super .close ();
265+ client .close ();
266+ }
267+ };
268+
269+ try {
270+ var solrConnection = CLIUtils .getSolrConnection (cli );
271+ echoIfVerbose ("Connecting to Solr at " + solrConnection );
272+
273+ StreamContext streamContext = new StreamContext ();
274+ streamContext .setSolrClientCache (solrClientCache );
275+
276+ StreamFactory streamFactory = new DefaultStreamFactory ();
277+ streamFactory .withDefaultSolrConnection (solrConnection );
278+ streamContext .setStreamFactory (streamFactory );
279+ return streamContext ;
280+ } catch (Exception e ) {
281+ IOUtils .closeQuietly (solrClientCache );
282+ throw e ;
283+ }
284+ }
285+
236286 /**
237287 * Runs a streaming expression in the local process of the CLI.
238288 *
239289 * <p>Running locally means that parallelization support or those expressions requiring access to
240290 * internal Solr capabilities will not function.
241291 *
242- * @param cli The CLI invoking the call
243- * @param expr The streaming expression to be parsed and in the context of the CLI process
292+ * @param expr The streaming expression to be parsed and run in the context of the CLI process
293+ * @param streamFactory The factory used to construct the streaming expression
244294 * @return A connection to the streaming expression that receives Tuples as they are emitted
245295 * locally.
246296 */
247- private PushBackStream doLocalMode (CommandLine cli , String expr ) throws Exception {
248- var solrConnection = CLIUtils .getSolrConnection (cli );
249- echoIfVerbose ("Connecting to Solr at " + solrConnection .toString ());
250- solrClientCache .setBasicAuthCredentials (
251- cli .getOptionValue (CommonCLIOptions .CREDENTIALS_OPTION ));
252- solrClientCache .getCloudSolrClient (solrConnection );
253-
254- TupleStream stream ;
255- PushBackStream pushBackStream ;
256-
257- StreamExpression streamExpression = StreamExpressionParser .parse (expr );
258- StreamFactory streamFactory = new StreamFactory ();
297+ private PushBackStream doLocalMode (String expr , StreamFactory streamFactory ) throws Exception {
259298
260299 // stdin is ONLY available in the local mode, not in the remote mode as it
261300 // requires access to System.in
@@ -265,23 +304,7 @@ private PushBackStream doLocalMode(CommandLine cli, String expr) throws Exceptio
265304 // logic about where to read data from.
266305 streamFactory .withFunctionName ("cat" , LocalCatStream .class );
267306
268- streamFactory .withDefaultSolrConnection (solrConnection );
269-
270- Lang .register (streamFactory );
271-
272- assert streamExpression != null ;
273- stream = streamFactory .constructStream (streamExpression );
274-
275- pushBackStream = new PushBackStream (stream );
276-
277- // Now we can run the stream and return the results.
278- StreamContext streamContext = new StreamContext ();
279- streamContext .setSolrClientCache (solrClientCache );
280-
281- // Output the headers
282- pushBackStream .setStreamContext (streamContext );
283-
284- return pushBackStream ;
307+ return new PushBackStream (streamFactory .constructStream (expr ));
285308 }
286309
287310 /**
@@ -291,35 +314,18 @@ private PushBackStream doLocalMode(CommandLine cli, String expr) throws Exceptio
291314 * <p>Running remotely allows you to use all the standard Streaming Expression capabilities as the
292315 * expression is running in a Solr environment.
293316 *
294- * @param cli The CLI invoking the call
295317 * @param expr The streaming expression to be parsed and run remotely
318+ * @param cli The CLI invoking the call
296319 * @return A connection to the streaming expression that receives Tuples as they are emitted from
297320 * Solr /stream.
298321 */
299- private PushBackStream doRemoteMode (CommandLine cli , String expr ) throws Exception {
322+ private PushBackStream doRemoteMode (String expr , CommandLine cli ) throws Exception {
300323
301324 String solrUrl = CLIUtils .normalizeSolrUrl (cli );
302- if (!cli .hasOption (COLLECTION_OPTION )) {
303- throw new IllegalStateException (
304- "You must provide --name COLLECTION with --execution remote parameter." );
305- }
306325 String collection = cli .getOptionValue (COLLECTION_OPTION );
307326
308- if (expr .toLowerCase (Locale .ROOT ).contains ("stdin(" )) {
309- throw new IllegalStateException (
310- "The stdin() expression is only usable with --worker local set up." );
311- }
312-
313- final SolrStream solrStream =
314- new SolrStream (solrUrl + "/solr/" + collection , params ("qt" , "/stream" , "expr" , expr ));
315-
316- String credentials = cli .getOptionValue (CommonCLIOptions .CREDENTIALS_OPTION );
317- if (credentials != null ) {
318- String username = credentials .split (":" )[0 ];
319- String password = credentials .split (":" )[1 ];
320- solrStream .setCredentials (username , password );
321- }
322- return new PushBackStream (solrStream );
327+ return new PushBackStream (
328+ new SolrStream (solrUrl + "/solr/" + collection , params ("qt" , "/stream" , "expr" , expr )));
323329 }
324330
325331 private static ModifiableSolrParams params (String ... params ) {
0 commit comments