1313# See the License for the specific language governing permissions and
1414# limitations under the License.
1515################################################################################
16- from itertools import chain , groupby
17- from pdb import set_trace
18- import re
1916import json
17+ import logging
18+ import re
2019import shlex
21- import requests
22- import networkx as nx
23- from pathlib import Path
2420import subprocess
25- from subprocess import CompletedProcess
26- from urllib .request import urlretrieve
27- from datetime import datetime
2821from importlib import resources
22+ from itertools import chain , groupby
23+ from pathlib import Path
24+ from subprocess import CompletedProcess
25+ from typing import Any , Dict , List , Tuple
26+ from typing import Union
2927
28+ import networkx as nx
3029from networkx import DiGraph
3130
3231from cldk .analysis import AnalysisLevel
3332from cldk .analysis .java .treesitter import JavaSitter
3433from cldk .models .java import JGraphEdges
35- from cldk .models .java .models import JApplication , JCallable , JField , JMethodDetail , JType , JCompilationUnit , JGraphEdgesST
36- from typing import Dict , List , Tuple
37- from typing import Union
38-
34+ from cldk .models .java .enums import CRUDOperationType
35+ from cldk .models .java .models import JApplication , JCRUDOperation , JCallable , JField , JMethodDetail , JType , JCompilationUnit , JGraphEdgesST
3936from cldk .utils .exceptions .exceptions import CodeanalyzerExecutionException
4037
41- import logging
42-
4338logger = logging .getLogger (__name__ )
4439
4540
@@ -143,22 +138,22 @@ def _get_codeanalyzer_exec(self) -> List[str]:
143138 with resources .as_file (resources .files ("cldk.analysis.java.codeanalyzer.bin" ) / "codeanalyzer" ) as codeanalyzer_bin_path :
144139 codeanalyzer_exec = shlex .split (codeanalyzer_bin_path .__str__ ())
145140 else :
146-
147141 if self .analysis_backend_path :
148142 analysis_backend_path = Path (self .analysis_backend_path )
149143 logger .info (f"Using codeanalyzer jar from { analysis_backend_path } " )
150144 codeanalyzer_jar_file = next (analysis_backend_path .rglob ("codeanalyzer-*.jar" ), None )
145+ if codeanalyzer_jar_file is None :
146+ raise CodeanalyzerExecutionException ("Codeanalyzer jar not found in the provided path." )
151147 codeanalyzer_exec = shlex .split (f"java -jar { codeanalyzer_jar_file } " )
152148 else :
153- # Since the path to codeanalyzer.jar was not provided, we'll download the latest version from GitHub.
149+ # Since the path to codeanalyzer.jar we will use the default jar from the cldk/analysis/java/codeanalyzer/jar folder
154150 with resources .as_file (resources .files ("cldk.analysis.java.codeanalyzer.jar" )) as codeanalyzer_jar_path :
155- # Download the codeanalyzer jar if it doesn't exist, update if it's outdated,
156- # do nothing if it's up-to-date.
157151 codeanalyzer_jar_file = next (codeanalyzer_jar_path .rglob ("codeanalyzer-*.jar" ), None )
158152 codeanalyzer_exec = shlex .split (f"java -jar { codeanalyzer_jar_file } " )
159153 return codeanalyzer_exec
160154
161- def init_japplication (self , data : str ) -> JApplication :
155+ @staticmethod
156+ def _init_japplication (data : str ) -> JApplication :
162157 """Return JApplication giving the stringified JSON as input.
163158 Returns
164159 -------
@@ -197,7 +192,7 @@ def _init_codeanalyzer(self, analysis_level=1) -> JApplication:
197192 text = True ,
198193 check = True ,
199194 )
200- return JApplication ( ** json . loads (console_out .stdout ) )
195+ return self . _init_japplication (console_out .stdout )
201196 except Exception as e :
202197 raise CodeanalyzerExecutionException (str (e )) from e
203198 else :
@@ -217,7 +212,7 @@ def _init_codeanalyzer(self, analysis_level=1) -> JApplication:
217212 # flag is set, we'll run the analysis every time the object is created. This will happen regradless
218213 # of the existence of the analysis file.
219214 # Create the executable command for codeanalyzer.
220- codeanalyzer_args = codeanalyzer_exec + shlex .split (f"-i { Path (self .project_dir )} --analysis-level={ analysis_level } -o { self .analysis_json_path } " )
215+ codeanalyzer_args = codeanalyzer_exec + shlex .split (f"-i { Path (self .project_dir )} --analysis-level={ analysis_level } -o { self .analysis_json_path } -v " )
221216 is_run_code_analyzer = True
222217
223218 if is_run_code_analyzer :
@@ -248,12 +243,11 @@ def _codeanalyzer_single_file(self) -> JApplication:
248243 codeanalyzer_args = ["--source-analysis" , self .source_code ]
249244 codeanalyzer_cmd = codeanalyzer_exec + codeanalyzer_args
250245 try :
251- print (f"Running { ' ' .join (codeanalyzer_cmd )} " )
252246 logger .info (f"Running { ' ' .join (codeanalyzer_cmd )} " )
253247 console_out : CompletedProcess [str ] = subprocess .run (codeanalyzer_cmd , capture_output = True , text = True , check = True )
254248 if console_out .returncode != 0 :
255249 raise CodeanalyzerExecutionException (console_out .stderr )
256- return JApplication ( ** json . loads (console_out .stdout ) )
250+ return self . _init_japplication (console_out .stdout )
257251 except Exception as e :
258252 raise CodeanalyzerExecutionException (str (e )) from e
259253
@@ -870,14 +864,9 @@ def get_all_entry_point_methods(self) -> Dict[str, Dict[str, JCallable]]:
870864 Dict[str, Dict[str, JCallable]]: A dictionary of all entry point methods in the Java code.
871865 """
872866 methods = chain .from_iterable (
873- ((typename , method , callable )
874- for method , callable in methods .items () if callable .is_entrypoint )
875- for typename , methods in self .get_all_methods_in_application ().items ()
867+ ((typename , method , callable ) for method , callable in methods .items () if callable .is_entrypoint ) for typename , methods in self .get_all_methods_in_application ().items ()
876868 )
877- return {
878- typename : {method : callable for _ , method , callable in group }
879- for typename , group in groupby (methods , key = lambda x : x [0 ])
880- }
869+ return {typename : {method : callable for _ , method , callable in group } for typename , group in groupby (methods , key = lambda x : x [0 ])}
881870
882871 def get_all_entry_point_classes (self ) -> Dict [str , JType ]:
883872 """Returns a dictionary of all entry point classes in the Java code.
@@ -887,8 +876,110 @@ def get_all_entry_point_classes(self) -> Dict[str, JType]:
887876 with qualified class names as keys.
888877 """
889878
890- return {
891- typename : klass
892- for typename , klass in self .get_all_classes ().items ()
893- if klass .is_entrypoint_class
894- }
879+ return {typename : klass for typename , klass in self .get_all_classes ().items () if klass .is_entrypoint_class }
880+
881+ def get_all_crud_operations (self ) -> List [Dict [str , Union [JType , JCallable , List [JCRUDOperation ]]]]:
882+ """Returns a dictionary of all CRUD operations in the source code.
883+
884+ Raises:
885+ NotImplementedError: Raised when current AnalysisEngine does not support this function.
886+
887+ Returns:
888+ Dict[str, List[str]]: A dictionary of all CRUD operations in the source code.
889+ """
890+
891+ crud_operations = []
892+ for class_name , class_details in self .get_all_classes ().items ():
893+ for method_name , method_details in class_details .callable_declarations .items ():
894+ if len (method_details .crud_operations ) > 0 :
895+ crud_operations .append ({class_name : class_details , method_name : method_details , "crud_operations" : method_details .crud_operations })
896+ return crud_operations
897+
898+ def get_all_read_operations (self ) -> List [Dict [str , Union [JType , JCallable , List [JCRUDOperation ]]]]:
899+ """Returns a list of all read operations in the source code.
900+
901+ Raises:
902+ NotImplementedError: Raised when current AnalysisEngine does not support this function.
903+
904+ Returns:
905+ List[Dict[str, Union[str, JCallable, List[CRUDOperation]]]]:: A list of all read operations in the source code.
906+ """
907+ crud_read_operations = []
908+ for class_name , class_details in self .get_all_classes ().items ():
909+ for method_name , method_details in class_details .callable_declarations .items ():
910+ if len (method_details .crud_operations ) > 0 :
911+ crud_read_operations .append (
912+ {
913+ class_name : class_details ,
914+ method_name : method_details ,
915+ "crud_operations" : [crud_op for crud_op in method_details .crud_operations if crud_op .operation_type == CRUDOperationType .READ ],
916+ }
917+ )
918+ return crud_read_operations
919+
920+ def get_all_create_operations (self ) -> List [Dict [str , Union [JType , JCallable , List [JCRUDOperation ]]]]:
921+ """Returns a list of all create operations in the source code.
922+
923+ Raises:
924+ NotImplementedError: Raised when current AnalysisEngine does not support this function.
925+
926+ Returns:
927+ List[Dict[str, Union[str, JCallable, List[CRUDOperation]]]]: A list of all create operations in the source code.
928+ """
929+ crud_create_operations = []
930+ for class_name , class_details in self .get_all_classes ().items ():
931+ for method_name , method_details in class_details .callable_declarations .items ():
932+ if len (method_details .crud_operations ) > 0 :
933+ crud_create_operations .append (
934+ {
935+ class_name : class_details ,
936+ method_name : method_details ,
937+ "crud_operations" : [crud_op for crud_op in method_details .crud_operations if crud_op .operation_type == CRUDOperationType .CREATE ],
938+ }
939+ )
940+ return crud_create_operations
941+
942+ def get_all_update_operations (self ) -> List [Dict [str , Union [JType , JCallable , List [JCRUDOperation ]]]]:
943+ """Returns a list of all update operations in the source code.
944+
945+ Raises:
946+ NotImplementedError: Raised when current AnalysisEngine does not support this function.
947+
948+ Returns:
949+ List[Dict[str, Union[str, JCallable, List[CRUDOperation]]]]: A list of all update operations in the source code.
950+ """
951+ crud_update_operations = []
952+ for class_name , class_details in self .get_all_classes ().items ():
953+ for method_name , method_details in class_details .callable_declarations .items ():
954+ if len (method_details .crud_operations ) > 0 :
955+ crud_update_operations .append (
956+ {
957+ class_name : class_details ,
958+ method_name : method_details ,
959+ "crud_operations" : [crud_op for crud_op in method_details .crud_operations if crud_op .operation_type == CRUDOperationType .UPDATE ],
960+ }
961+ )
962+
963+ return crud_update_operations
964+
965+ def get_all_delete_operations (self ) -> List [Dict [str , Union [JType , JCallable , List [JCRUDOperation ]]]]:
966+ """Returns a list of all delete operations in the source code.
967+
968+ Raises:
969+ NotImplementedError: Raised when current AnalysisEngine does not support this function.
970+
971+ Returns:
972+ List[Dict[str, Union[str, JCallable, List[CRUDOperation]]]]: A list of all delete operations in the source code.
973+ """
974+ crud_delete_operations = []
975+ for class_name , class_details in self .get_all_classes ().items ():
976+ for method_name , method_details in class_details .callable_declarations .items ():
977+ if len (method_details .crud_operations ) > 0 :
978+ crud_delete_operations .append (
979+ {
980+ class_name : class_details ,
981+ method_name : method_details ,
982+ "crud_operations" : [crud_op for crud_op in method_details .crud_operations if crud_op .operation_type == CRUDOperationType .DELETE ],
983+ }
984+ )
985+ return crud_delete_operations
0 commit comments