18
18
package org .apache .seatunnel .api .table .factory ;
19
19
20
20
import org .apache .seatunnel .api .common .CommonOptions ;
21
+ import org .apache .seatunnel .api .common .PluginIdentifier ;
21
22
import org .apache .seatunnel .api .configuration .ReadonlyConfig ;
22
23
import org .apache .seatunnel .api .configuration .util .ConfigValidator ;
23
24
import org .apache .seatunnel .api .configuration .util .OptionRule ;
36
37
import org .apache .seatunnel .api .table .connector .TableSource ;
37
38
import org .apache .seatunnel .api .table .type .SeaTunnelDataType ;
38
39
import org .apache .seatunnel .api .transform .SeaTunnelTransform ;
40
+ import org .apache .seatunnel .common .utils .ExceptionUtils ;
39
41
40
42
import org .slf4j .Logger ;
41
43
import org .slf4j .LoggerFactory ;
42
44
43
45
import lombok .NonNull ;
46
+ import lombok .extern .slf4j .Slf4j ;
44
47
import scala .Tuple2 ;
45
48
46
49
import java .io .Serializable ;
51
54
import java .util .Optional ;
52
55
import java .util .ServiceConfigurationError ;
53
56
import java .util .ServiceLoader ;
57
+ import java .util .function .Consumer ;
58
+ import java .util .function .Function ;
54
59
import java .util .stream .Collectors ;
55
60
61
+ import static org .apache .seatunnel .api .common .CommonOptions .PLUGIN_NAME ;
62
+
56
63
/**
57
64
* Use SPI to create {@link TableSourceFactory}, {@link TableSinkFactory} and {@link
58
65
* CatalogFactory}.
59
66
*/
67
+ @ Slf4j
60
68
public final class FactoryUtil {
61
69
62
70
private static final Logger LOG = LoggerFactory .getLogger (FactoryUtil .class );
@@ -65,31 +73,60 @@ public final class FactoryUtil {
65
73
66
74
public static <T , SplitT extends SourceSplit , StateT extends Serializable >
67
75
Tuple2 <SeaTunnelSource <T , SplitT , StateT >, List <CatalogTable >> createAndPrepareSource (
68
- ReadonlyConfig options , ClassLoader classLoader , String factoryIdentifier ) {
69
- return restoreAndPrepareSource (options , classLoader , factoryIdentifier , null );
76
+ ReadonlyConfig options ,
77
+ ClassLoader classLoader ,
78
+ String factoryIdentifier ,
79
+ Function <PluginIdentifier , SeaTunnelSource > fallbackCreateSource ,
80
+ TableSourceFactory factory ) {
81
+ return restoreAndPrepareSource (
82
+ options , classLoader , factoryIdentifier , null , fallbackCreateSource , factory );
70
83
}
71
84
72
85
public static <T , SplitT extends SourceSplit , StateT extends Serializable >
73
86
Tuple2 <SeaTunnelSource <T , SplitT , StateT >, List <CatalogTable >> restoreAndPrepareSource (
74
87
ReadonlyConfig options ,
75
88
ClassLoader classLoader ,
76
89
String factoryIdentifier ,
77
- ChangeStreamTableSourceCheckpoint checkpoint ) {
90
+ ChangeStreamTableSourceCheckpoint checkpoint ,
91
+ Function <PluginIdentifier , SeaTunnelSource > fallbackCreateSource ,
92
+ TableSourceFactory factory ) {
78
93
79
94
try {
80
- final TableSourceFactory factory =
81
- discoverFactory (classLoader , TableSourceFactory .class , factoryIdentifier );
95
+
82
96
SeaTunnelSource <T , SplitT , StateT > source ;
83
- if (factory instanceof ChangeStreamTableSourceFactory && checkpoint != null ) {
84
- ChangeStreamTableSourceFactory changeStreamTableSourceFactory =
85
- (ChangeStreamTableSourceFactory ) factory ;
86
- ChangeStreamTableSourceState <Serializable , SourceSplit > state =
87
- changeStreamTableSourceFactory .deserializeTableSourceState (checkpoint );
97
+ final String factoryId = options .get (PLUGIN_NAME );
98
+
99
+ boolean fallback =
100
+ isFallback (
101
+ classLoader ,
102
+ TableSourceFactory .class ,
103
+ factoryId ,
104
+ (sourceFactory ) -> sourceFactory .createSource (null ));
105
+
106
+ if (fallback ) {
88
107
source =
89
- restoreAndPrepareSource (
90
- changeStreamTableSourceFactory , options , classLoader , state );
108
+ fallbackCreateSource .apply (
109
+ PluginIdentifier .of ("seatunnel" , "source" , factoryId ));
110
+ source .prepare (options .toConfig ());
111
+
91
112
} else {
92
- source = createAndPrepareSource (factory , options , classLoader );
113
+ if (factory == null ) {
114
+ factory =
115
+ discoverFactory (
116
+ classLoader , TableSourceFactory .class , factoryIdentifier );
117
+ }
118
+
119
+ if (factory instanceof ChangeStreamTableSourceFactory && checkpoint != null ) {
120
+ ChangeStreamTableSourceFactory changeStreamTableSourceFactory =
121
+ (ChangeStreamTableSourceFactory ) factory ;
122
+ ChangeStreamTableSourceState <Serializable , SourceSplit > state =
123
+ changeStreamTableSourceFactory .deserializeTableSourceState (checkpoint );
124
+ source =
125
+ restoreAndPrepareSource (
126
+ changeStreamTableSourceFactory , options , classLoader , state );
127
+ } else {
128
+ source = createAndPrepareSource (factory , options , classLoader );
129
+ }
93
130
}
94
131
List <CatalogTable > catalogTables ;
95
132
try {
@@ -115,6 +152,7 @@ Tuple2<SeaTunnelSource<T, SplitT, StateT>, List<CatalogTable>> restoreAndPrepare
115
152
catalogTables .add (catalogTable );
116
153
}
117
154
return new Tuple2 <>(source , catalogTables );
155
+
118
156
} catch (Throwable t ) {
119
157
throw new FactoryException (
120
158
String .format (
@@ -150,25 +188,50 @@ SeaTunnelSink<IN, StateT, CommitInfoT, AggregatedCommitInfoT> createAndPrepareSi
150
188
CatalogTable catalogTable ,
151
189
ReadonlyConfig config ,
152
190
ClassLoader classLoader ,
153
- String factoryIdentifier ) {
191
+ String factoryIdentifier ,
192
+ Function <PluginIdentifier , SeaTunnelSink > fallbackCreateSink ,
193
+ TableSinkFactory <IN , StateT , CommitInfoT , AggregatedCommitInfoT >
194
+ tableSinkFactory ) {
154
195
try {
155
- TableSinkFactory <IN , StateT , CommitInfoT , AggregatedCommitInfoT > factory =
156
- discoverFactory (classLoader , TableSinkFactory .class , factoryIdentifier );
196
+ final String factoryId = config .get (PLUGIN_NAME );
197
+
198
+ boolean fallback =
199
+ isFallback (
200
+ classLoader ,
201
+ TableSinkFactory .class ,
202
+ factoryId ,
203
+ (sinkFactory ) -> sinkFactory .createSink (null ));
204
+
205
+ if (fallback ) {
206
+ SeaTunnelSink sink =
207
+ fallbackCreateSink .apply (
208
+ PluginIdentifier .of ("seatunnel" , "sink" , factoryId ));
209
+ sink .prepare (config .toConfig ());
210
+ sink .setTypeInfo (catalogTable .getSeaTunnelRowType ());
211
+
212
+ return sink ;
213
+ }
214
+
215
+ if (tableSinkFactory == null ) {
216
+ tableSinkFactory =
217
+ discoverFactory (classLoader , TableSinkFactory .class , factoryIdentifier );
218
+ }
219
+
157
220
TableSinkFactoryContext context =
158
221
TableSinkFactoryContext .replacePlaceholderAndCreate (
159
222
catalogTable ,
160
223
config ,
161
224
classLoader ,
162
- factory .excludeTablePlaceholderReplaceKeys ());
163
- ConfigValidator .of (context .getOptions ()).validate (factory .optionRule ());
225
+ tableSinkFactory .excludeTablePlaceholderReplaceKeys ());
226
+ ConfigValidator .of (context .getOptions ()).validate (tableSinkFactory .optionRule ());
164
227
165
228
LOG .info (
166
229
"Create sink '{}' with upstream input catalog-table[database: {}, schema: {}, table: {}]" ,
167
230
factoryIdentifier ,
168
231
catalogTable .getTablePath ().getDatabaseName (),
169
232
catalogTable .getTablePath ().getSchemaName (),
170
233
catalogTable .getTablePath ().getTableName ());
171
- return factory .createSink (context ).createSink ();
234
+ return tableSinkFactory .createSink (context ).createSink ();
172
235
} catch (Throwable t ) {
173
236
throw new FactoryException (
174
237
String .format (
@@ -351,4 +414,26 @@ public static SeaTunnelTransform<?> createAndPrepareMultiTableTransform(
351
414
ConfigValidator .of (context .getOptions ()).validate (factory .optionRule ());
352
415
return factory .createTransform (context ).createTransform ();
353
416
}
417
+
418
+ private static <T extends Factory > boolean isFallback (
419
+ ClassLoader classLoader ,
420
+ Class <T > factoryClass ,
421
+ String factoryId ,
422
+ Consumer <T > virtualCreator ) {
423
+ Optional <T > factory = discoverOptionalFactory (classLoader , factoryClass , factoryId );
424
+ if (!factory .isPresent ()) {
425
+ return true ;
426
+ }
427
+ try {
428
+ virtualCreator .accept (factory .get ());
429
+ } catch (Exception e ) {
430
+ if (e instanceof UnsupportedOperationException
431
+ && "The Factory has not been implemented and the deprecated Plugin will be used."
432
+ .equals (e .getMessage ())) {
433
+ return true ;
434
+ }
435
+ log .debug (ExceptionUtils .getMessage (e ));
436
+ }
437
+ return false ;
438
+ }
354
439
}
0 commit comments