You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2020/03/07 21:11:31 UTC
[maven-surefire] branch maven2surefire-jvm-communication updated:
StreamFeeder (impl class of extension) moved to the right module and added
a new test,
and moved the logic from MasterProcessCommand to the StreamFeeder
This is an automated email from the ASF dual-hosted git repository.
tibordigana pushed a commit to branch maven2surefire-jvm-communication
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git
The following commit(s) were added to refs/heads/maven2surefire-jvm-communication by this push:
new 5bbe758 StreamFeeder (impl class of extension) moved to the right module and added a new test, and moved the logic from MasterProcessCommand to the StreamFeeder
5bbe758 is described below
commit 5bbe758baf303b1f898c2f37bcd75024598b4268
Author: tibordigana <ti...@apache.org>
AuthorDate: Sat Mar 7 22:11:22 2020 +0100
StreamFeeder (impl class of extension) moved to the right module and added a new test, and moved the logic from MasterProcessCommand to the StreamFeeder
---
.../surefire/extensions/LegacyForkChannel.java | 3 +-
.../plugin/surefire/extensions/StreamFeeder.java | 203 +++++++++++++++++++++
.../surefire/extensions/SurefireForkChannel.java | 3 +-
.../TestLessInputStreamBuilderTest.java | 6 +-
.../TestProvidingInputStreamTest.java | 7 +-
.../surefire/extensions/StreamFeederTest.java | 162 ++++++++++++++++
.../org/apache/maven/surefire/JUnit4SuiteTest.java | 6 +-
.../surefire/booter/MasterProcessCommand.java | 93 +---------
.../spi/LegacyMasterProcessChannelDecoder.java | 27 ++-
.../maven/surefire/booter/CommandReaderTest.java | 4 +-
.../spi/LegacyMasterProcessChannelDecoderTest.java | 54 ++----
.../surefire/extensions/util/StreamFeeder.java | 94 ----------
.../extensions}/CommandlineExecutorTest.java | 37 +---
.../surefire/extensions}/JUnit4SuiteTest.java | 2 +-
14 files changed, 430 insertions(+), 271 deletions(-)
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkChannel.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkChannel.java
index 89cda94..a554edf 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkChannel.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/LegacyForkChannel.java
@@ -26,7 +26,6 @@ import org.apache.maven.surefire.extensions.CommandReader;
import org.apache.maven.surefire.extensions.EventHandler;
import org.apache.maven.surefire.extensions.ForkChannel;
import org.apache.maven.surefire.extensions.util.CountdownCloseable;
-import org.apache.maven.surefire.extensions.util.StreamFeeder;
import javax.annotation.Nonnull;
import java.nio.channels.ReadableByteChannel;
@@ -71,7 +70,7 @@ final class LegacyForkChannel extends ForkChannel
public CloseableDaemonThread bindCommandReader( @Nonnull CommandReader commands,
WritableByteChannel stdIn )
{
- return new StreamFeeder( "std-in-fork-" + getForkChannelId(), stdIn, commands );
+ return new StreamFeeder( "std-in-fork-" + getForkChannelId(), stdIn, commands, logger );
}
@Override
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/StreamFeeder.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/StreamFeeder.java
new file mode 100644
index 0000000..604ca33
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/StreamFeeder.java
@@ -0,0 +1,203 @@
+package org.apache.maven.plugin.surefire.extensions;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.booter.Command;
+import org.apache.maven.surefire.booter.MasterProcessCommand;
+import org.apache.maven.surefire.extensions.CloseableDaemonThread;
+import org.apache.maven.surefire.extensions.CommandReader;
+import org.apache.maven.surefire.util.internal.ImmutableMap;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.NonWritableChannelException;
+import java.nio.channels.WritableByteChannel;
+import java.util.HashMap;
+import java.util.Map;
+
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.BYE_ACK;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.MAGIC_NUMBER;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.NOOP;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.RUN_CLASS;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.SHUTDOWN;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.SKIP_SINCE_NEXT_TEST;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.TEST_SET_FINISHED;
+
+/**
+ * Commands which are sent from plugin to the forked jvm.
+ * <br>
+ * <br>
+ * magic number : opcode [: opcode specific data]*
+ * <br>
+ * or data encoded with Base64
+ * <br>
+ * magic number : opcode [: Base64(opcode specific data)]*
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 3.0.0-M5
+ */
+public class StreamFeeder extends CloseableDaemonThread
+{
+ private static final Map<MasterProcessCommand, String> COMMAND_OPCODES = opcodesToStrings();
+
+ private final WritableByteChannel channel;
+ private final CommandReader commandReader;
+ private final ConsoleLogger logger;
+
+ private volatile boolean disabled;
+ private volatile Throwable exception;
+
+ public StreamFeeder( @Nonnull String threadName, @Nonnull WritableByteChannel channel,
+ @Nonnull CommandReader commandReader, @Nonnull ConsoleLogger logger )
+ {
+ super( threadName );
+ this.channel = channel;
+ this.commandReader = commandReader;
+ this.logger = logger;
+ }
+
+ @Override
+ @SuppressWarnings( "checkstyle:innerassignment" )
+ public void run()
+ {
+ try ( WritableByteChannel c = channel )
+ {
+ for ( Command cmd; ( cmd = commandReader.readNextCommand() ) != null; )
+ {
+ if ( !disabled )
+ {
+ MasterProcessCommand cmdType = cmd.getCommandType();
+ byte[] data = cmdType.hasDataType() ? encode( cmdType, cmd.getData() ) : encode( cmdType );
+ c.write( ByteBuffer.wrap( data ) );
+ }
+ }
+ }
+ catch ( ClosedChannelException e )
+ {
+ // closed externally
+ }
+ catch ( IOException | NonWritableChannelException e )
+ {
+ exception = e.getCause() == null ? e : e.getCause();
+ }
+ catch ( IllegalArgumentException e )
+ {
+ logger.error( e.getLocalizedMessage() );
+ }
+ }
+
+ public void disable()
+ {
+ disabled = true;
+ }
+
+ public Throwable getException()
+ {
+ return exception;
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ channel.close();
+ }
+
+ /**
+ * Public method for testing purposes.
+ *
+ * @param cmdType command type
+ * @param data data to encode
+ * @return command with data encoded to bytes
+ */
+ public static byte[] encode( MasterProcessCommand cmdType, String data )
+ {
+ if ( !cmdType.hasDataType() )
+ {
+ throw new IllegalArgumentException( "cannot use data without data type" );
+ }
+
+ if ( cmdType.getDataType() != String.class )
+ {
+ throw new IllegalArgumentException( "Data type can be only " + String.class );
+ }
+
+ return encode( COMMAND_OPCODES.get( cmdType ), data )
+ .toString()
+ .getBytes( US_ASCII );
+ }
+
+ /**
+ * Public method for testing purposes.
+ *
+ * @param cmdType command type
+ * @return command without data encoded to bytes
+ */
+ public static byte[] encode( MasterProcessCommand cmdType )
+ {
+ if ( cmdType.getDataType() != Void.class )
+ {
+ throw new IllegalArgumentException( "Data type can be only " + cmdType.getDataType() );
+ }
+
+ return encode( COMMAND_OPCODES.get( cmdType ), null )
+ .toString()
+ .getBytes( US_ASCII );
+ }
+
+ /**
+ * Encodes opcode and data.
+ *
+ * @param operation opcode
+ * @param data data
+ * @return encoded command
+ */
+ private static StringBuilder encode( String operation, String data )
+ {
+ StringBuilder s = new StringBuilder( 128 )
+ .append( ':' )
+ .append( MAGIC_NUMBER )
+ .append( ':' )
+ .append( operation );
+
+ if ( data != null )
+ {
+ s.append( ':' )
+ .append( data );
+ }
+
+ return s.append( ':' );
+ }
+
+ private static Map<MasterProcessCommand, String> opcodesToStrings()
+ {
+ Map<MasterProcessCommand, String> opcodes = new HashMap<>();
+ opcodes.put( RUN_CLASS, "run-testclass" );
+ opcodes.put( TEST_SET_FINISHED, "testset-finished" );
+ opcodes.put( SKIP_SINCE_NEXT_TEST, "skip-since-next-test" );
+ opcodes.put( SHUTDOWN, "shutdown" );
+ opcodes.put( NOOP, "noop" );
+ opcodes.put( BYE_ACK, "bye-ack" );
+ return new ImmutableMap<>( opcodes );
+ }
+}
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkChannel.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkChannel.java
index 65a38f0..0aa790c 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkChannel.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/SurefireForkChannel.java
@@ -26,7 +26,6 @@ import org.apache.maven.surefire.extensions.CommandReader;
import org.apache.maven.surefire.extensions.EventHandler;
import org.apache.maven.surefire.extensions.ForkChannel;
import org.apache.maven.surefire.extensions.util.CountdownCloseable;
-import org.apache.maven.surefire.extensions.util.StreamFeeder;
import javax.annotation.Nonnull;
import java.io.IOException;
@@ -117,7 +116,7 @@ final class SurefireForkChannel extends ForkChannel
public CloseableDaemonThread bindCommandReader( @Nonnull CommandReader commands,
WritableByteChannel stdIn )
{
- return new StreamFeeder( "commands-fork-" + getForkChannelId(), channel, commands );
+ return new StreamFeeder( "commands-fork-" + getForkChannelId(), channel, commands, logger );
}
@Override
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java
index 5e4f766..2aab4c2 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestLessInputStreamBuilderTest.java
@@ -33,12 +33,12 @@ import java.util.Iterator;
import java.util.NoSuchElementException;
import static java.nio.channels.Channels.newChannel;
-import static org.apache.maven.plugin.surefire.booterclient.lazytestprovider
- .TestLessInputStream.TestLessInputStreamBuilder;
+import static org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream.TestLessInputStreamBuilder;
import static org.apache.maven.surefire.booter.Command.SKIP_SINCE_NEXT_TEST;
import static org.apache.maven.surefire.booter.MasterProcessCommand.SHUTDOWN;
import static org.apache.maven.surefire.booter.Shutdown.EXIT;
import static org.apache.maven.surefire.booter.Shutdown.KILL;
+import static org.apache.maven.plugin.surefire.extensions.StreamFeeder.encode;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
@@ -155,7 +155,7 @@ public class TestLessInputStreamBuilderTest
if ( cmd != null )
{
MasterProcessCommand cmdType = cmd.getCommandType();
- buffer = cmdType.hasDataType() ? cmdType.encode( cmd.getData() ) : cmdType.encode();
+ buffer = cmdType.hasDataType() ? encode( cmdType, cmd.getData() ) : encode( cmdType );
}
}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStreamTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStreamTest.java
index a7f3b8d..1d348ce 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStreamTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStreamTest.java
@@ -21,6 +21,7 @@ package org.apache.maven.plugin.surefire.booterclient.lazytestprovider;
import org.apache.maven.surefire.booter.Command;
import org.apache.maven.surefire.booter.spi.LegacyMasterProcessChannelDecoder;
+import org.apache.maven.plugin.surefire.extensions.StreamFeeder;
import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
import org.junit.Test;
@@ -106,11 +107,11 @@ public class TestProvidingInputStreamTest
Command cmd = is.readNextCommand();
assertThat( cmd.getData(), is( nullValue() ) );
- String stream = new String( cmd.getCommandType().encode(), US_ASCII );
+ String stream = new String( StreamFeeder.encode( cmd.getCommandType() ), US_ASCII );
cmd = is.readNextCommand();
assertThat( cmd.getData(), is( nullValue() ) );
- stream += new String( cmd.getCommandType().encode(), US_ASCII );
+ stream += new String( StreamFeeder.encode( cmd.getCommandType() ), US_ASCII );
assertThat( stream,
is( ":maven-surefire-command:testset-finished::maven-surefire-command:testset-finished:" ) );
@@ -161,7 +162,7 @@ public class TestProvidingInputStreamTest
{
idx = 0;
Command cmd = pluginIs.readNextCommand();
- buffer = cmd == null ? null : cmd.getCommandType().encode();
+ buffer = cmd == null ? null : StreamFeeder.encode( cmd.getCommandType() );
}
if ( buffer != null )
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/StreamFeederTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/StreamFeederTest.java
new file mode 100644
index 0000000..7da6745
--- /dev/null
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/StreamFeederTest.java
@@ -0,0 +1,162 @@
+package org.apache.maven.plugin.surefire.extensions;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.booter.Command;
+import org.apache.maven.surefire.extensions.CommandReader;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.util.Iterator;
+
+import static java.util.Arrays.asList;
+import static org.apache.maven.surefire.booter.Command.TEST_SET_FINISHED;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.NOOP;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.RUN_CLASS;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link StreamFeeder}.
+ */
+public class StreamFeederTest
+{
+ private final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ private final WritableByteChannel channel = mock( WritableByteChannel.class );
+ private final CommandReader commandReader = mock( CommandReader.class );
+ private StreamFeeder streamFeeder;
+
+ @Before
+ public void setup() throws IOException
+ {
+ final Iterator<Command> it = asList( new Command( RUN_CLASS, "pkg.ATest" ), TEST_SET_FINISHED ).iterator();
+ when( commandReader.readNextCommand() )
+ .thenAnswer( new Answer<Command>()
+ {
+ @Override
+ public Command answer( InvocationOnMock invocation )
+ {
+ return it.hasNext() ? it.next() : null;
+ }
+ } );
+ }
+
+ @After
+ public void close() throws IOException
+ {
+ if ( streamFeeder != null )
+ {
+ streamFeeder.disable();
+ streamFeeder.close();
+ }
+ }
+
+ @Test
+ public void shouldEncodeCommandToStream() throws Exception
+ {
+ when( channel.write( any( ByteBuffer.class ) ) )
+ .thenAnswer( new Answer<Object>()
+ {
+ @Override
+ public Object answer( InvocationOnMock invocation ) throws IOException
+ {
+ ByteBuffer bb = invocation.getArgument( 0 );
+ bb.flip();
+ out.write( bb.array() );
+ return 0;
+ }
+ } );
+
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ streamFeeder = new StreamFeeder( "t", channel, commandReader, logger );
+ streamFeeder.start();
+
+ streamFeeder.join();
+ String commands = out.toString();
+
+ assertThat( commands )
+ .isEqualTo( ":maven-surefire-command:run-testclass:pkg.ATest::maven-surefire-command:testset-finished:" );
+
+ verify( channel, times( 1 ) )
+ .close();
+
+ assertThat( streamFeeder.getException() )
+ .isNull();
+
+ verifyZeroInteractions( logger );
+ }
+
+ @Test
+ public void shouldFailThread() throws Exception
+ {
+ when( channel.write( any( ByteBuffer.class ) ) )
+ .thenAnswer( new Answer<Object>()
+ {
+ @Override
+ public Object answer( InvocationOnMock invocation ) throws IOException
+ {
+ throw new IOException();
+ }
+ } );
+
+ ConsoleLogger logger = mock( ConsoleLogger.class );
+ streamFeeder = new StreamFeeder( "t", channel, commandReader, logger );
+ streamFeeder.start();
+
+ streamFeeder.join();
+
+ assertThat( out.size() )
+ .isZero();
+
+ verify( channel, times( 1 ) )
+ .close();
+
+ assertThat( streamFeeder.getException() )
+ .isNotNull()
+ .isInstanceOf( IOException.class );
+
+ verifyZeroInteractions( logger );
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailWithoutData()
+ {
+ StreamFeeder.encode( RUN_CLASS );
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailWithData()
+ {
+ StreamFeeder.encode( NOOP, "" );
+ }
+}
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
index 92b7a42..a232544 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
@@ -40,7 +40,10 @@ import org.apache.maven.plugin.surefire.booterclient.ModularClasspathForkConfigu
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStreamBuilderTest;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvidingInputStreamTest;
import org.apache.maven.plugin.surefire.booterclient.output.ForkClientTest;
+import org.apache.maven.plugin.surefire.extensions.ConsoleOutputReporterTest;
import org.apache.maven.plugin.surefire.extensions.ForkedProcessEventNotifierTest;
+import org.apache.maven.plugin.surefire.extensions.StatelessReporterTest;
+import org.apache.maven.plugin.surefire.extensions.StreamFeederTest;
import org.apache.maven.plugin.surefire.report.DefaultReporterFactoryTest;
import org.apache.maven.plugin.surefire.report.StatelessXmlReporterTest;
import org.apache.maven.plugin.surefire.report.TestSetStatsTest;
@@ -50,9 +53,7 @@ import org.apache.maven.plugin.surefire.util.DependenciesScannerTest;
import org.apache.maven.plugin.surefire.util.DirectoryScannerTest;
import org.apache.maven.plugin.surefire.util.ScannerUtilTest;
import org.apache.maven.plugin.surefire.util.SpecificFileFilterTest;
-import org.apache.maven.plugin.surefire.extensions.ConsoleOutputReporterTest;
import org.apache.maven.surefire.extensions.ForkChannelTest;
-import org.apache.maven.plugin.surefire.extensions.StatelessReporterTest;
import org.apache.maven.surefire.extensions.StatelessTestsetInfoReporterTest;
import org.apache.maven.surefire.report.FileReporterTest;
import org.apache.maven.surefire.report.RunStatisticsTest;
@@ -106,6 +107,7 @@ public class JUnit4SuiteTest extends TestCase
suite.addTest( new JUnit4TestAdapter( CommonReflectorTest.class ) );
suite.addTest( new JUnit4TestAdapter( ForkStarterTest.class ) );
suite.addTest( new JUnit4TestAdapter( ForkChannelTest.class ) );
+ suite.addTest( new JUnit4TestAdapter( StreamFeederTest.class ) );
return suite;
}
}
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
index 55e604d..b6ae644 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/MasterProcessCommand.java
@@ -19,45 +19,31 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import javax.annotation.Nonnull;
-
-import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.util.Objects.requireNonNull;
/**
* Commands which are sent from plugin to the forked jvm.
- * Support and methods related to the commands.
- * <br>
- * <br>
- * magic number : opcode [: opcode specific data]*
- * <br>
- * or data encoded with Base64
- * <br>
- * magic number : opcode [: Base64(opcode specific data)]*
*
* @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
* @since 2.19
*/
public enum MasterProcessCommand
{
- RUN_CLASS( "run-testclass", String.class ),
- TEST_SET_FINISHED( "testset-finished", Void.class ),
- SKIP_SINCE_NEXT_TEST( "skip-since-next-test", Void.class ),
- SHUTDOWN( "shutdown", String.class ),
+ RUN_CLASS( String.class ),
+ TEST_SET_FINISHED( Void.class ),
+ SKIP_SINCE_NEXT_TEST( Void.class ),
+ SHUTDOWN( String.class ),
/** To tell a forked process that the master process is still alive. Repeated after 10 seconds. */
- NOOP( "noop", Void.class ),
- BYE_ACK( "bye-ack", Void.class );
+ NOOP( Void.class ),
+ BYE_ACK( Void.class );
public static final String MAGIC_NUMBER = "maven-surefire-command";
- private final String opcodeName;
-
private final Class<?> dataType;
- MasterProcessCommand( String opcodeName, Class<?> dataType )
+ MasterProcessCommand( Class<?> dataType )
{
- this.opcodeName = opcodeName;
this.dataType = requireNonNull( dataType, "dataType cannot be null" );
}
@@ -70,69 +56,4 @@ public enum MasterProcessCommand
{
return dataType != Void.class;
}
-
- public static MasterProcessCommand byOpcode( @Nonnull String opcode )
- {
- for ( MasterProcessCommand cmd : values() )
- {
- if ( cmd.opcodeName.equals( requireNonNull( opcode ) ) )
- {
- return cmd;
- }
- }
- return null;
- }
-
- public byte[] encode( String data )
- {
- if ( !hasDataType() )
- {
- throw new IllegalArgumentException( "cannot use data without data type" );
- }
-
- if ( getDataType() != String.class )
- {
- throw new IllegalArgumentException( "Data type can be only " + String.class );
- }
-
- return encode( opcodeName, data )
- .toString()
- .getBytes( US_ASCII );
- }
-
- public byte[] encode()
- {
- if ( getDataType() != Void.class )
- {
- throw new IllegalArgumentException( "Data type can be only " + getDataType() );
- }
-
- return encode( opcodeName, null )
- .toString()
- .getBytes( US_ASCII );
- }
-
- /**
- * Encodes opcode and data.
- *
- * @param operation opcode
- * @param data data
- * @return encoded command
- */
- private static StringBuilder encode( String operation, String data )
- {
- StringBuilder s = new StringBuilder( 128 )
- .append( ':' )
- .append( MAGIC_NUMBER )
- .append( ':' )
- .append( operation );
-
- if ( data != null )
- {
- s.append( ':' )
- .append( data );
- }
-
- return s.append( ':' );
- }
}
diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java
index 9ac1ca5..e8d3efb 100644
--- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java
+++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoder.java
@@ -23,6 +23,7 @@ import org.apache.maven.surefire.booter.Command;
import org.apache.maven.surefire.booter.DumpErrorSingleton;
import org.apache.maven.surefire.booter.MasterProcessCommand;
import org.apache.maven.surefire.providerapi.MasterProcessChannelDecoder;
+import org.apache.maven.surefire.util.internal.ImmutableMap;
import javax.annotation.Nonnull;
import java.io.EOFException;
@@ -30,9 +31,17 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.BYE_ACK;
import static org.apache.maven.surefire.booter.MasterProcessCommand.MAGIC_NUMBER;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.NOOP;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.RUN_CLASS;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.SHUTDOWN;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.SKIP_SINCE_NEXT_TEST;
+import static org.apache.maven.surefire.booter.MasterProcessCommand.TEST_SET_FINISHED;
/**
* magic number : opcode [: opcode specific data]*
@@ -43,6 +52,8 @@ import static org.apache.maven.surefire.booter.MasterProcessCommand.MAGIC_NUMBER
*/
public class LegacyMasterProcessChannelDecoder implements MasterProcessChannelDecoder
{
+ private static final Map<String, MasterProcessCommand> COMMAND_OPCODES = stringsToOpcodes();
+
private final ReadableByteChannel channel;
public LegacyMasterProcessChannelDecoder( @Nonnull ReadableByteChannel channel )
@@ -108,7 +119,7 @@ public class LegacyMasterProcessChannelDecoder implements MasterProcessChannelDe
if ( completion == FrameCompletion.COMPLETE )
{
- MasterProcessCommand cmd = MasterProcessCommand.byOpcode( tokens.get( 1 ) );
+ MasterProcessCommand cmd = COMMAND_OPCODES.get( tokens.get( 1 ) );
if ( tokens.size() == 2 )
{
return new Command( cmd );
@@ -137,7 +148,7 @@ public class LegacyMasterProcessChannelDecoder implements MasterProcessChannelDe
if ( tokens.size() >= 2 )
{
String opcode = tokens.get( 1 );
- MasterProcessCommand cmd = MasterProcessCommand.byOpcode( opcode );
+ MasterProcessCommand cmd = COMMAND_OPCODES.get( opcode );
if ( cmd == null )
{
return FrameCompletion.MALFORMED;
@@ -164,4 +175,16 @@ public class LegacyMasterProcessChannelDecoder implements MasterProcessChannelDe
COMPLETE,
MALFORMED
}
+
+ private static Map<String, MasterProcessCommand> stringsToOpcodes()
+ {
+ Map<String, MasterProcessCommand> opcodes = new HashMap<>();
+ opcodes.put( "run-testclass", RUN_CLASS );
+ opcodes.put( "testset-finished", TEST_SET_FINISHED );
+ opcodes.put( "skip-since-next-test", SKIP_SINCE_NEXT_TEST );
+ opcodes.put( "shutdown", SHUTDOWN );
+ opcodes.put( "noop", NOOP );
+ opcodes.put( "bye-ack", BYE_ACK );
+ return new ImmutableMap<>( opcodes );
+ }
}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
index 30a2c28..edaae08 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/CommandReaderTest.java
@@ -248,7 +248,7 @@ public class CommandReaderTest
private void addTestToPipeline( String cls )
{
- for ( byte cmdByte : MasterProcessCommand.RUN_CLASS.encode( cls ) )
+ for ( byte cmdByte : ( ":maven-surefire-command:run-testclass:" + cls + ":" ).getBytes() )
{
blockingStream.add( cmdByte );
}
@@ -256,7 +256,7 @@ public class CommandReaderTest
private void addEndOfPipeline()
{
- for ( byte cmdByte : MasterProcessCommand.TEST_SET_FINISHED.encode() )
+ for ( byte cmdByte : ":maven-surefire-command:testset-finished:".getBytes() )
{
blockingStream.add( cmdByte );
}
diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoderTest.java
index b17e4c5..029b7ba 100644
--- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoderTest.java
+++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/LegacyMasterProcessChannelDecoderTest.java
@@ -52,11 +52,8 @@ public class LegacyMasterProcessChannelDecoderTest
public void testDecoderRunClass() throws IOException
{
assertEquals( String.class, RUN_CLASS.getDataType() );
- byte[] encoded = RUN_CLASS.encode( "pkg.Test" );
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:run-testclass:pkg.Test:" );
- byte[] line = addNL( encoded, '\n' );
- InputStream is = new ByteArrayInputStream( line );
+ byte[] encoded = ":maven-surefire-command:run-testclass:pkg.Test:\n".getBytes();
+ InputStream is = new ByteArrayInputStream( encoded );
LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( newChannel( is ) );
Command command = decoder.decode();
assertThat( command.getCommandType() ).isSameAs( RUN_CLASS );
@@ -69,9 +66,7 @@ public class LegacyMasterProcessChannelDecoderTest
Command command = Command.TEST_SET_FINISHED;
assertThat( command.getCommandType() ).isSameAs( TEST_SET_FINISHED );
assertEquals( Void.class, TEST_SET_FINISHED.getDataType() );
- byte[] encoded = TEST_SET_FINISHED.encode();
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:testset-finished:" );
+ byte[] encoded = ":maven-surefire-command:testset-finished:".getBytes();
ByteArrayInputStream is = new ByteArrayInputStream( encoded );
LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( newChannel( is ) );
command = decoder.decode();
@@ -85,9 +80,7 @@ public class LegacyMasterProcessChannelDecoderTest
Command command = Command.SKIP_SINCE_NEXT_TEST;
assertThat( command.getCommandType() ).isSameAs( SKIP_SINCE_NEXT_TEST );
assertEquals( Void.class, SKIP_SINCE_NEXT_TEST.getDataType() );
- byte[] encoded = SKIP_SINCE_NEXT_TEST.encode();
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:skip-since-next-test:" );
+ byte[] encoded = ":maven-surefire-command:skip-since-next-test:".getBytes();
ByteArrayInputStream is = new ByteArrayInputStream( encoded );
LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( newChannel( is ) );
command = decoder.decode();
@@ -100,9 +93,7 @@ public class LegacyMasterProcessChannelDecoderTest
{
Shutdown shutdownType = EXIT;
assertEquals( String.class, SHUTDOWN.getDataType() );
- byte[] encoded = SHUTDOWN.encode( shutdownType.name() );
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:shutdown:" + shutdownType + ":" );
+ byte[] encoded = ( ":maven-surefire-command:shutdown:" + shutdownType + ":" ).getBytes();
ByteArrayInputStream is = new ByteArrayInputStream( encoded );
LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( newChannel( is ) );
Command command = decoder.decode();
@@ -115,9 +106,7 @@ public class LegacyMasterProcessChannelDecoderTest
{
Shutdown shutdownType = KILL;
assertEquals( String.class, SHUTDOWN.getDataType() );
- byte[] encoded = SHUTDOWN.encode( shutdownType.name() );
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:shutdown:" + shutdownType + ":" );
+ byte[] encoded = ( ":maven-surefire-command:shutdown:" + shutdownType + ":" ).getBytes();
ByteArrayInputStream is = new ByteArrayInputStream( encoded );
LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( newChannel( is ) );
Command command = decoder.decode();
@@ -130,9 +119,7 @@ public class LegacyMasterProcessChannelDecoderTest
{
Shutdown shutdownType = DEFAULT;
assertEquals( String.class, SHUTDOWN.getDataType() );
- byte[] encoded = SHUTDOWN.encode( shutdownType.name() );
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:shutdown:" + shutdownType + ":" );
+ byte[] encoded = ( ":maven-surefire-command:shutdown:" + shutdownType + ":" ).getBytes();
ByteArrayInputStream is = new ByteArrayInputStream( encoded );
LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( newChannel( is ) );
Command command = decoder.decode();
@@ -145,9 +132,7 @@ public class LegacyMasterProcessChannelDecoderTest
{
assertThat( NOOP ).isSameAs( Command.NOOP.getCommandType() );
assertEquals( Void.class, NOOP.getDataType() );
- byte[] encoded = NOOP.encode();
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:noop:" );
+ byte[] encoded = ":maven-surefire-command:noop:".getBytes();
ByteArrayInputStream is = new ByteArrayInputStream( encoded );
LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( newChannel( is ) );
Command command = decoder.decode();
@@ -160,9 +145,7 @@ public class LegacyMasterProcessChannelDecoderTest
{
assertThat( BYE_ACK ).isSameAs( Command.BYE_ACK.getCommandType() );
assertEquals( Void.class, BYE_ACK.getDataType() );
- byte[] encoded = BYE_ACK.encode();
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:bye-ack:" );
+ byte[] encoded = ":maven-surefire-command:bye-ack:".getBytes();
byte[] streamContent = ( "<something>" + new String( encoded ) + "<damaged>" ).getBytes();
ByteArrayInputStream is = new ByteArrayInputStream( streamContent );
LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( newChannel( is ) );
@@ -176,9 +159,7 @@ public class LegacyMasterProcessChannelDecoderTest
{
assertThat( BYE_ACK ).isSameAs( Command.BYE_ACK.getCommandType() );
assertEquals( Void.class, BYE_ACK.getDataType() );
- byte[] encoded = BYE_ACK.encode();
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:bye-ack:" );
+ byte[] encoded = ":maven-surefire-command:bye-ack:".getBytes();
byte[] streamContent = ( ":<damaged>:" + new String( encoded ) ).getBytes();
ByteArrayInputStream is = new ByteArrayInputStream( streamContent );
LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( newChannel( is ) );
@@ -192,9 +173,7 @@ public class LegacyMasterProcessChannelDecoderTest
{
assertThat( BYE_ACK ).isSameAs( Command.BYE_ACK.getCommandType() );
assertEquals( Void.class, BYE_ACK.getDataType() );
- byte[] encoded = BYE_ACK.encode();
- assertThat( new String( encoded ) )
- .isEqualTo( ":maven-surefire-command:bye-ack:" );
+ byte[] encoded = ":maven-surefire-command:bye-ack:".getBytes();
ByteArrayInputStream is = new ByteArrayInputStream( encoded );
LegacyMasterProcessChannelDecoder decoder = new LegacyMasterProcessChannelDecoder( newChannel( is ) );
Command command = decoder.decode();
@@ -261,15 +240,4 @@ public class LegacyMasterProcessChannelDecoderTest
assertThat( command.getCommandType() ).isSameAs( NOOP );
assertNull( command.getData() );
}
-
- private static byte[] addNL( byte[] encoded, char... newLines )
- {
- byte[] line = new byte[encoded.length + newLines.length];
- System.arraycopy( encoded, 0, line, 0, encoded.length );
- for ( int i = encoded.length, j = 0; i < line.length; i++, j++ )
- {
- line[i] = (byte) newLines[j];
- }
- return line;
- }
}
diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/StreamFeeder.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/StreamFeeder.java
deleted file mode 100644
index 78e5ce0..0000000
--- a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/util/StreamFeeder.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package org.apache.maven.surefire.extensions.util;
-
-/*
- * 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.
- */
-
-import org.apache.maven.surefire.booter.Command;
-import org.apache.maven.surefire.booter.MasterProcessCommand;
-import org.apache.maven.surefire.extensions.CloseableDaemonThread;
-import org.apache.maven.surefire.extensions.CommandReader;
-
-import javax.annotation.Nonnull;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.ClosedChannelException;
-import java.nio.channels.NonWritableChannelException;
-import java.nio.channels.WritableByteChannel;
-
-/**
- *
- */
-public class StreamFeeder extends CloseableDaemonThread
-{
- private final WritableByteChannel channel;
- private final CommandReader commandReader;
-
- private volatile boolean disabled;
- private volatile Throwable exception;
-
- public StreamFeeder( @Nonnull String threadName, @Nonnull WritableByteChannel channel,
- @Nonnull CommandReader commandReader )
- {
- super( threadName );
- this.channel = channel;
- this.commandReader = commandReader;
- }
-
- @Override
- @SuppressWarnings( "checkstyle:innerassignment" )
- public void run()
- {
- try ( WritableByteChannel c = channel )
- {
- for ( Command cmd; ( cmd = commandReader.readNextCommand() ) != null; )
- {
- if ( !disabled )
- {
- MasterProcessCommand cmdType = cmd.getCommandType();
- byte[] data = cmdType.hasDataType() ? cmdType.encode( cmd.getData() ) : cmdType.encode();
- c.write( ByteBuffer.wrap( data ) );
- }
- }
- }
- catch ( ClosedChannelException e )
- {
- // closed externally
- }
- catch ( IOException | NonWritableChannelException e )
- {
- exception = e.getCause() == null ? e : e.getCause();
- }
- }
-
- public void disable()
- {
- disabled = true;
- }
-
- public Throwable getException()
- {
- return exception;
- }
-
- @Override
- public void close() throws IOException
- {
- channel.close();
- }
-}
diff --git a/surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/CommandlineExecutorTest.java b/surefire-extensions-api/src/test/java/org/apache/maven/plugin/surefire/extensions/CommandlineExecutorTest.java
similarity index 80%
rename from surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/CommandlineExecutorTest.java
rename to surefire-extensions-api/src/test/java/org/apache/maven/plugin/surefire/extensions/CommandlineExecutorTest.java
index 15f8ab8..92ee1e3 100644
--- a/surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/CommandlineExecutorTest.java
+++ b/surefire-extensions-api/src/test/java/org/apache/maven/plugin/surefire/extensions/CommandlineExecutorTest.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.extensions.util;
+package org.apache.maven.plugin.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,9 +19,11 @@ package org.apache.maven.surefire.extensions.util;
* under the License.
*/
-import org.apache.maven.surefire.booter.Command;
-import org.apache.maven.surefire.extensions.CommandReader;
import org.apache.maven.surefire.extensions.EventHandler;
+import org.apache.maven.surefire.extensions.util.CommandlineExecutor;
+import org.apache.maven.surefire.extensions.util.CommandlineStreams;
+import org.apache.maven.surefire.extensions.util.CountdownCloseable;
+import org.apache.maven.surefire.extensions.util.LineConsumerThread;
import org.apache.maven.surefire.shared.utils.cli.Commandline;
import org.junit.After;
import org.junit.Before;
@@ -45,7 +47,7 @@ public class CommandlineExecutorTest
private CommandlineExecutor exec;
private CommandlineStreams streams;
private String baseDir;
- LineConsumerThread out;
+ private LineConsumerThread out;
@Before
public void setUp() throws Exception
@@ -92,34 +94,7 @@ public class CommandlineExecutorTest
streams = exec.execute();
@SuppressWarnings( "unchecked" )
EventHandler<String> consumer = mock( EventHandler.class );
- CommandReader commandReader = new CommandReader()
- {
- @Override
- public Command readNextCommand()
- {
- return null;
- }
-
- @Override
- public void close()
- {
-
- }
-
- @Override
- public boolean isClosed()
- {
- return false;
- }
-
- @Override
- public void tryFlush()
- {
- }
- };
- StreamFeeder in = new StreamFeeder( "std-in-fork-1", streams.getStdInChannel(), commandReader );
- in.start();
out = new LineConsumerThread( "std-out-fork-1", streams.getStdOutChannel(), consumer, countdownCloseable );
out.start();
exec.awaitExit();
diff --git a/surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/JUnit4SuiteTest.java b/surefire-extensions-api/src/test/java/org/apache/maven/plugin/surefire/extensions/JUnit4SuiteTest.java
similarity index 95%
rename from surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/JUnit4SuiteTest.java
rename to surefire-extensions-api/src/test/java/org/apache/maven/plugin/surefire/extensions/JUnit4SuiteTest.java
index df9cca1..a8464a4 100644
--- a/surefire-extensions-api/src/test/java/org/apache/maven/surefire/extensions/util/JUnit4SuiteTest.java
+++ b/surefire-extensions-api/src/test/java/org/apache/maven/plugin/surefire/extensions/JUnit4SuiteTest.java
@@ -1,4 +1,4 @@
-package org.apache.maven.surefire.extensions.util;
+package org.apache.maven.plugin.surefire.extensions;
/*
* Licensed to the Apache Software Foundation (ASF) under one