1919import io .serverlessworkflow .api .types .EndpointUri ;
2020import io .serverlessworkflow .api .types .ExternalResource ;
2121import io .serverlessworkflow .api .types .UriTemplate ;
22+ import io .serverlessworkflow .impl .TaskContext ;
23+ import io .serverlessworkflow .impl .WorkflowApplication ;
2224import io .serverlessworkflow .impl .WorkflowContext ;
23- import io .serverlessworkflow .impl .expressions .ExpressionFactory ;
25+ import io .serverlessworkflow .impl .WorkflowModel ;
26+ import io .serverlessworkflow .impl .WorkflowValueResolver ;
27+ import io .serverlessworkflow .impl .expressions .ExpressionDescriptor ;
2428import java .net .MalformedURLException ;
2529import java .net .URI ;
2630import java .nio .file .Path ;
31+ import java .time .Instant ;
32+ import java .util .Map ;
2733import java .util .Optional ;
34+ import java .util .ServiceLoader ;
35+ import java .util .concurrent .atomic .AtomicReference ;
36+ import java .util .concurrent .locks .Lock ;
37+ import java .util .concurrent .locks .ReentrantLock ;
38+ import java .util .function .Function ;
2839
2940public class DefaultResourceLoader implements ResourceLoader {
3041
3142 private final Optional <Path > workflowPath ;
43+ private final WorkflowApplication application ;
3244
33- protected DefaultResourceLoader (Path workflowPath ) {
34- this .workflowPath = Optional .ofNullable (workflowPath );
35- }
45+ private final AtomicReference <URITemplateResolver > templateResolver =
46+ new AtomicReference <URITemplateResolver >();
3647
37- @ Override
38- public StaticResource loadStatic (ExternalResource resource ) {
39- return processEndpoint (resource .getEndpoint ());
40- }
48+ private Map <ExternalResourceHandler , CachedResource > resourceCache = new LRUCache <>(100 );
49+ private Lock cacheLock = new ReentrantLock ();
4150
42- @ Override
43- public DynamicResource loadDynamic (
44- WorkflowContext workflow , ExternalResource resource , ExpressionFactory factory ) {
45- throw new UnsupportedOperationException ("Dynamic loading of resources is not suppported" );
51+ protected DefaultResourceLoader (WorkflowApplication application , Path workflowPath ) {
52+ this .application = application ;
53+ this .workflowPath = Optional .ofNullable (workflowPath );
4654 }
4755
48- private StaticResource buildFromString (String uri ) {
49- return fileResource (uri );
56+ private URITemplateResolver templateResolver () {
57+ URITemplateResolver result = templateResolver .get ();
58+ if (result == null ) {
59+ result =
60+ ServiceLoader .load (URITemplateResolver .class )
61+ .findFirst ()
62+ .orElseThrow (
63+ () ->
64+ new IllegalStateException (
65+ "Need an uri template resolver to resolve uri template" ));
66+ templateResolver .set (result );
67+ }
68+ return result ;
5069 }
5170
52- private StaticResource fileResource (String pathStr ) {
71+ private ExternalResourceHandler fileResource (String pathStr ) {
5372 Path path = Path .of (pathStr );
5473 if (path .isAbsolute ()) {
5574 return new FileResource (path );
5675 } else {
5776 return workflowPath
58- .<StaticResource >map (p -> new FileResource (p .resolve (path )))
77+ .<ExternalResourceHandler >map (p -> new FileResource (p .resolve (path )))
5978 .orElseGet (() -> new ClasspathResource (pathStr ));
6079 }
6180 }
6281
63- private StaticResource buildFromURI (URI uri ) {
82+ private ExternalResourceHandler buildFromURI (URI uri ) {
6483 String scheme = uri .getScheme ();
6584 if (scheme == null || scheme .equalsIgnoreCase ("file" )) {
6685 return fileResource (uri .getPath ());
@@ -75,31 +94,79 @@ private StaticResource buildFromURI(URI uri) {
7594 }
7695 }
7796
78- private StaticResource processEndpoint (Endpoint endpoint ) {
97+ @ Override
98+ public <T > T load (
99+ ExternalResource resource ,
100+ Function <ExternalResourceHandler , T > function ,
101+ WorkflowContext workflowContext ,
102+ TaskContext taskContext ,
103+ WorkflowModel model ) {
104+ ExternalResourceHandler resourceHandler =
105+ buildFromURI (
106+ uriSupplier (resource .getEndpoint ())
107+ .apply (
108+ workflowContext ,
109+ taskContext ,
110+ model == null ? application .modelFactory ().fromNull () : model ));
111+ try {
112+ CachedResource <T > cachedResource ;
113+ cacheLock .lock ();
114+ cachedResource = resourceCache .get (resourceHandler );
115+ cacheLock .unlock ();
116+ if (cachedResource == null || resourceHandler .shouldReload (cachedResource .lastReload ())) {
117+ cachedResource = new CachedResource (Instant .now (), function .apply (resourceHandler ));
118+ cacheLock .lock ();
119+ resourceCache .put (resourceHandler , cachedResource );
120+ }
121+ return cachedResource .content ();
122+ } finally {
123+ cacheLock .unlock ();
124+ }
125+ }
126+
127+ @ Override
128+ public WorkflowValueResolver <URI > uriSupplier (Endpoint endpoint ) {
79129 if (endpoint .getEndpointConfiguration () != null ) {
80130 EndpointUri uri = endpoint .getEndpointConfiguration ().getUri ();
81131 if (uri .getLiteralEndpointURI () != null ) {
82- return getURI (uri .getLiteralEndpointURI ());
132+ return getURISupplier (uri .getLiteralEndpointURI ());
83133 } else if (uri .getExpressionEndpointURI () != null ) {
84- throw new UnsupportedOperationException (
85- "Expression not supported for loading a static resource" );
134+ return new ExpressionURISupplier (
135+ application
136+ .expressionFactory ()
137+ .resolveString (ExpressionDescriptor .from (uri .getExpressionEndpointURI ())));
86138 }
87139 } else if (endpoint .getRuntimeExpression () != null ) {
88- throw new UnsupportedOperationException (
89- "Expression not supported for loading a static resource" );
140+ return new ExpressionURISupplier (
141+ application
142+ .expressionFactory ()
143+ .resolveString (ExpressionDescriptor .from (endpoint .getRuntimeExpression ())));
90144 } else if (endpoint .getUriTemplate () != null ) {
91- return getURI (endpoint .getUriTemplate ());
145+ return getURISupplier (endpoint .getUriTemplate ());
92146 }
93147 throw new IllegalArgumentException ("Invalid endpoint definition " + endpoint );
94148 }
95149
96- private StaticResource getURI (UriTemplate template ) {
150+ private WorkflowValueResolver < URI > getURISupplier (UriTemplate template ) {
97151 if (template .getLiteralUri () != null ) {
98- return buildFromURI ( template .getLiteralUri () );
152+ return ( w , t , n ) -> template .getLiteralUri ();
99153 } else if (template .getLiteralUriTemplate () != null ) {
100- return buildFromString (template .getLiteralUriTemplate ());
101- } else {
102- throw new IllegalStateException ("Invalid endpoint definition" + template );
154+ return (w , t , n ) ->
155+ templateResolver ().resolveTemplates (template .getLiteralUriTemplate (), w , t , n );
156+ }
157+ throw new IllegalArgumentException ("Invalid uritemplate definition " + template );
158+ }
159+
160+ private class ExpressionURISupplier implements WorkflowValueResolver <URI > {
161+ private WorkflowValueResolver <String > expr ;
162+
163+ public ExpressionURISupplier (WorkflowValueResolver <String > expr ) {
164+ this .expr = expr ;
165+ }
166+
167+ @ Override
168+ public URI apply (WorkflowContext workflow , TaskContext task , WorkflowModel node ) {
169+ return URI .create (expr .apply (workflow , task , node ));
103170 }
104171 }
105172}
0 commit comments