1 package org.apache.maven.surefire.booter;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.DataInputStream;
23 import java.io.IOException;
24
25 import static java.lang.String.format;
26 import static java.nio.charset.StandardCharsets.ISO_8859_1;
27 import static java.nio.charset.StandardCharsets.US_ASCII;
28 import static java.util.Objects.requireNonNull;
29 import static org.apache.maven.surefire.util.internal.StringUtils.encodeStringForForkCommunication;
30
31
32
33
34
35
36
37
38 public enum MasterProcessCommand
39 {
40 RUN_CLASS( 0, String.class ),
41 TEST_SET_FINISHED( 1, Void.class ),
42 SKIP_SINCE_NEXT_TEST( 2, Void.class ),
43 SHUTDOWN( 3, String.class ),
44
45
46 NOOP( 4, Void.class ),
47 BYE_ACK( 5, Void.class );
48
49 private final int id;
50
51 private final Class<?> dataType;
52
53 MasterProcessCommand( int id, Class<?> dataType )
54 {
55 this.id = id;
56 this.dataType = requireNonNull( dataType, "dataType cannot be null" );
57 }
58
59 public int getId()
60 {
61 return id;
62 }
63
64 public Class<?> getDataType()
65 {
66 return dataType;
67 }
68
69 public boolean hasDataType()
70 {
71 return dataType != Void.class;
72 }
73
74 @SuppressWarnings( "checkstyle:magicnumber" )
75 public byte[] encode( String data )
76 {
77 if ( !hasDataType() )
78 {
79 throw new IllegalArgumentException( "cannot use data without data type" );
80 }
81
82 if ( getDataType() != String.class )
83 {
84 throw new IllegalArgumentException( "Data type can be only " + String.class );
85 }
86
87 final byte[] dataBytes = fromDataType( data );
88 final int len = dataBytes.length;
89
90 final byte[] encoded = new byte[8 + len];
91
92 final int command = getId();
93 setCommandAndDataLength( command, len, encoded );
94 System.arraycopy( dataBytes, 0, encoded, 8, len );
95
96 return encoded;
97 }
98
99 @SuppressWarnings( "checkstyle:magicnumber" )
100 public byte[] encode()
101 {
102 if ( getDataType() != Void.class )
103 {
104 throw new IllegalArgumentException( "Data type can be only " + getDataType() );
105 }
106 byte[] encoded = new byte[8];
107 int command = getId();
108 setCommandAndDataLength( command, 0, encoded );
109 return encoded;
110 }
111
112 public static Command decode( DataInputStream is )
113 throws IOException
114 {
115 MasterProcessCommand command = resolve( is.readInt() );
116 if ( command == null )
117 {
118 return null;
119 }
120 else
121 {
122 int dataLength = is.readInt();
123 if ( dataLength > 0 )
124 {
125 byte[] buffer = new byte[ dataLength ];
126 is.readFully( buffer );
127
128 if ( command.getDataType() == Void.class )
129 {
130 throw new IOException( format( "Command %s unexpectedly read Void data with length %d.",
131 command, dataLength ) );
132 }
133
134 String data = command.toDataTypeAsString( buffer );
135 return new Command( command, data );
136 }
137 else
138 {
139 return new Command( command );
140 }
141 }
142 }
143
144 String toDataTypeAsString( byte... data )
145 {
146 switch ( this )
147 {
148 case RUN_CLASS:
149 return new String( data, ISO_8859_1 );
150 case SHUTDOWN:
151 return new String( data, US_ASCII );
152 default:
153 return null;
154 }
155 }
156
157 byte[] fromDataType( String data )
158 {
159 switch ( this )
160 {
161 case RUN_CLASS:
162 return encodeStringForForkCommunication( data );
163 case SHUTDOWN:
164 return data.getBytes( US_ASCII );
165 default:
166 return new byte[0];
167 }
168 }
169
170 static MasterProcessCommand resolve( int id )
171 {
172 for ( MasterProcessCommand command : values() )
173 {
174 if ( id == command.id )
175 {
176 return command;
177 }
178 }
179 return null;
180 }
181
182 @SuppressWarnings( "checkstyle:magicnumber" )
183 static void setCommandAndDataLength( int command, int dataLength, byte... encoded )
184 {
185 encoded[0] = (byte) ( command >>> 24 );
186 encoded[1] = (byte) ( command >>> 16 );
187 encoded[2] = (byte) ( command >>> 8 );
188 encoded[3] = (byte) command;
189 encoded[4] = (byte) ( dataLength >>> 24 );
190 encoded[5] = (byte) ( dataLength >>> 16 );
191 encoded[6] = (byte) ( dataLength >>> 8 );
192 encoded[7] = (byte) dataLength;
193 }
194 }