|
7 | 7 | [](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) |
8 | 8 | [](https://spring.io/projects/spring-boot) |
9 | 9 | [](https://www.python.org/downloads/) |
10 | | - |
| 10 | + |
11 | 11 |
|
12 | 12 | <hr> |
13 | 13 |
|
|
17 | 17 | - [Introduction](#-introduction) |
18 | 18 | - [Features & Architecture](#-features--architecture) |
19 | 19 | - [Core Components](#core-components) |
| 20 | + - [Architecture Diagram](#architecture-diagram) |
20 | 21 | - [Security](#security) |
21 | 22 | - [Cache](#cache) |
22 | 23 | - [Installation and Setup](#-installation-and-setup) |
@@ -76,64 +77,86 @@ Spring Boot Python Executor provides a flexible architecture for executing Pytho |
76 | 77 | - Result resolution for capturing Python output |
77 | 78 | - **PythonProcessor**: Connects resolvers and executors |
78 | 79 |
|
| 80 | +### Architecture Diagram |
| 81 | + |
| 82 | +If you are willing to use AOP based script processing, |
| 83 | +your Python code will move from Python annotation to a configured PythonProcessor implementation object |
| 84 | + |
79 | 85 | ```mermaid |
80 | 86 | --- |
81 | | -title: Basic Python script flow |
| 87 | +title: Python annotations flow |
82 | 88 | --- |
83 | 89 |
|
84 | 90 | classDiagram |
85 | | - PythonBefore --> PythonProcessor: Annotation @PythonBefore forwards the script to the PythonProcessor implementation |
86 | | - PythonAfter --> PythonProcessor: Annotation @PythonAfter forwards the script to the PythonProcessor implementation |
87 | | - PythonProcessor --> PythonFileHandler: Firstly, the script is checked whether it's a .py file or String script |
88 | | - PythonProcessor <-- PythonFileHandler: If it's a file, the content is read as a String value and returned |
89 | | - PythonProcessor --> PythonResolverHolder: Secondly, the script may be transformed by multiple PythonResolver implementations. You can configure declared implementations by using spring.python.resolver.declared property |
90 | | - PythonProcessor <-- PythonResolverHolder: Returns resolved script from multiple PythonResolvers |
91 | | - PythonProcessor --> PythonExecutor: Finally, the script is executed by PythonExecutor implementation. You can choose needed implementation by configuring the property named spring.python.executor.type |
92 | | - PythonProcessor <-- PythonExecutor: The method returns null, because of annotation usage, but if you would like to get specific result object you need to call process(...) function manually |
93 | | - |
94 | | - class PythonBefore { |
95 | | - +String value() |
96 | | - +String script() |
97 | | - +String[] activeProfiles() |
98 | | - } |
99 | | - |
100 | | - class PythonAfter { |
101 | | - +String value() |
102 | | - +String script() |
103 | | - +String[] activeProfiles() |
104 | | - } |
105 | | - |
106 | | - class PythonProcessor { |
107 | | - <<interface>> |
108 | | - +R process(String script, Class<? extends R> resultClass, Map<String, Object> arguments) |
109 | | - } |
110 | | - |
111 | | - class PythonFileHandler { |
112 | | - <<interface>> |
113 | | - +boolean isPythonFile(String path) |
114 | | - +void writeScriptBodyToFile(String path, String script) |
115 | | - +void writeScriptBodyToFile(Path path, String script) |
116 | | - +String readScriptBodyFromFile(String path) |
117 | | - +String readScriptBodyFromFile(Path path) |
118 | | - +String readScriptBodyFromFile(String path, UnaryOperator<String> mapper) |
119 | | - +String readScriptBodyFromFile(Path path, UnaryOperator<String> mapper) |
120 | | - +Path getScriptPath(String path) |
121 | | - } |
122 | | - |
123 | | - class PythonResolverHolder { |
124 | | - <<interface>> |
125 | | - +Iterator<PythonResolver> iterator() |
126 | | - +void forEach(Consumer<? super PythonResolver> action) |
127 | | - +Spliterator<PythonResolver> spliterator() |
128 | | - +Stream<PythonResolver> stream() |
129 | | - +String resolveAll(String script, Map<String, Object> arguments); |
130 | | - +List<PythonResolver> getResolvers(); |
131 | | - } |
132 | | - |
133 | | - class PythonExecutor { |
134 | | - <<interface>> |
135 | | - +R execute(String script, Class<? extends R> resultClass) |
136 | | - } |
| 91 | + PythonBefores --> PythonAnnotationEvaluator |
| 92 | + PythonBefore --> PythonAnnotationEvaluator |
| 93 | + PythonAfters --> PythonAnnotationEvaluator |
| 94 | + PythonAfter --> PythonAnnotationEvaluator |
| 95 | + PythonAnnotationEvaluator --> PythonAnnotationValueCompounder |
| 96 | + PythonAnnotationEvaluator <-- PythonAnnotationValueCompounder |
| 97 | + PythonAnnotationEvaluator --> ProfileChecker |
| 98 | + PythonAnnotationEvaluator <-- ProfileChecker |
| 99 | + PythonAnnotationEvaluator --> PythonArgumentsExtractor |
| 100 | + PythonAnnotationEvaluator <-- PythonArgumentsExtractor |
| 101 | + PythonAnnotationEvaluator --> PythonProcessor |
| 102 | + PythonAnnotationValueCompounder --> PythonAnnotationValueExtractor |
| 103 | + PythonAnnotationValueCompounder <-- PythonAnnotationValueExtractor |
| 104 | + PythonAnnotationValueExtractor --> PythonMethodExtractor |
| 105 | + PythonAnnotationValueExtractor <-- PythonMethodExtractor |
| 106 | + PythonArgumentsExtractor --> PythonMethodExtractor |
| 107 | + PythonArgumentsExtractor <-- PythonMethodExtractor |
| 108 | + |
| 109 | + |
| 110 | +``` |
| 111 | + |
| 112 | +Also, you can use only PythonProcessor object to execute Python code: |
| 113 | +```mermaid |
| 114 | +--- |
| 115 | +title: PythonProcessor flow |
| 116 | +--- |
| 117 | +
|
| 118 | +classDiagram |
| 119 | + PythonProcessor --> PythonFileHandler: Firstly, the script is checked whether it's a .py file or String script |
| 120 | + PythonProcessor <-- PythonFileHandler: If it's a file, the content is read as a String value and returned |
| 121 | + PythonProcessor --> PythonResolverHolder: Secondly, the script may be transformed by multiple PythonResolver implementations. You can configure declared implementations by using spring.python.resolver.declared property |
| 122 | + PythonProcessor <-- PythonResolverHolder: Returns resolved script from multiple PythonResolvers |
| 123 | + PythonProcessor --> PythonExecutor: Finally, the script is executed by PythonExecutor implementation. You can choose needed implementation by configuring the property named spring.python.executor.type |
| 124 | + PythonProcessor <-- PythonExecutor: The method returns null, because of annotation usage, but if you would like to get specific result object you need to call process(...) function manually |
| 125 | + |
| 126 | + class PythonProcessor { |
| 127 | + <<interface>> |
| 128 | + +void process(String script) |
| 129 | + +void process(String script, Map<String, Object> arguments) |
| 130 | + +R process(String script, Class<? extends R> resultClass) |
| 131 | + +R process(String script, Class<? extends R> resultClass, Map<String, Object> arguments) |
| 132 | + } |
| 133 | + |
| 134 | + class PythonFileHandler { |
| 135 | + <<interface>> |
| 136 | + +boolean isPythonFile(String path) |
| 137 | + +void writeScriptBodyToFile(String path, String script) |
| 138 | + +void writeScriptBodyToFile(Path path, String script) |
| 139 | + +String readScriptBodyFromFile(String path) |
| 140 | + +String readScriptBodyFromFile(Path path) |
| 141 | + +String readScriptBodyFromFile(String path, UnaryOperator<String> mapper) |
| 142 | + +String readScriptBodyFromFile(Path path, UnaryOperator<String> mapper) |
| 143 | + +Path getScriptPath(String path) |
| 144 | + } |
| 145 | + |
| 146 | + class PythonResolverHolder { |
| 147 | + <<interface>> |
| 148 | + +Iterator<PythonResolver> iterator() |
| 149 | + +void forEach(Consumer<? super PythonResolver> action) |
| 150 | + +Spliterator<PythonResolver> spliterator() |
| 151 | + +Stream<PythonResolver> stream() |
| 152 | + +String resolveAll(String script, Map<String, Object> arguments); |
| 153 | + +List<PythonResolver> getResolvers(); |
| 154 | + } |
| 155 | + |
| 156 | + class PythonExecutor { |
| 157 | + <<interface>> |
| 158 | + +R execute(String script, Class<? extends R> resultClass) |
| 159 | + } |
137 | 160 | ``` |
138 | 161 |
|
139 | 162 | ### Security |
|
0 commit comments