11"""
2- Copyright (c) 2017, 2019 , Oracle Corporation and/or its affiliates. All rights reserved.
2+ Copyright (c) 2017, 2020 , Oracle Corporation and/or its affiliates. All rights reserved.
33Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
44"""
55import copy
66import os
77from java .io import ByteArrayOutputStream
88from java .io import File
9+ from java .io import FileInputStream
910from java .io import FileNotFoundException
1011from java .io import IOException
1112from java .lang import IllegalStateException
1213from java .security import NoSuchAlgorithmException
1314from java .util .jar import JarFile
15+ from java .util .jar import Manifest
1416from java .util .zip import ZipException
1517from sets import Set
1618from wlsdeploy .aliases .location_context import LocationContext
@@ -164,7 +166,7 @@ def __add_applications(self):
164166
165167 if deployer_utils .is_path_into_archive (app_source_path ):
166168 if self .archive_helper is not None :
167- self .archive_helper . extract_file (app_source_path )
169+ self .__extract_source_path_from_archive (app_source_path , APPLICATION , application_name )
168170 else :
169171 ex = exception_helper .create_deploy_exception ('WLSDPLY-09303' , application_name )
170172 self .logger .throwing (ex , class_name = self ._class_name , method_name = _method_name )
@@ -567,14 +569,23 @@ def __build_app_deploy_strategy(self, location, model_apps, existing_apps, exist
567569 self .model_context .replace_tokens (APPLICATION , app , param , app_dict )
568570
569571 if app in existing_apps :
572+ # Compare the hashes of the domain's existing apps to the model's apps.
573+ # If they match, remove them from the list to be deployed.
574+ # If they are different, stop and un-deploy the app, and leave it in the list.
575+
570576 existing_app_ref = dictionary_utils .get_dictionary_element (existing_app_refs , app )
571577 plan_path = dictionary_utils .get_element (existing_app_ref , 'planPath' )
572578 src_path = dictionary_utils .get_element (existing_app_ref , 'sourcePath' )
573579
574- model_src_hash = \
575- self .__get_hash (dictionary_utils .get_element (app_dict , SOURCE_PATH ))
576- model_plan_hash = \
577- self .__get_hash (dictionary_utils .get_element (app_dict , PLAN_PATH ))
580+ model_src_path = dictionary_utils .get_element (app_dict , SOURCE_PATH )
581+
582+ if (model_src_path is not None ) and deployer_utils .is_path_into_archive (model_src_path ) \
583+ and self .archive_helper .contains_path (model_src_path ):
584+ model_src_hash = - 1 # don't calculate hash, just ensure that hashes will not match
585+ else :
586+ model_src_hash = self .__get_hash (model_src_path )
587+
588+ model_plan_hash = self .__get_hash (dictionary_utils .get_element (app_dict , PLAN_PATH ))
578589
579590 existing_src_hash = self .__get_file_hash (src_path )
580591 existing_plan_hash = self .__get_file_hash (plan_path )
@@ -603,6 +614,10 @@ def __get_file_hash(self, filename):
603614 try :
604615 if filename is None :
605616 return None
617+
618+ if File (filename ).isDirectory (): # can't calculate for exploded apps, libraries, etc.
619+ return None
620+
606621 hash_value = FileUtils .computeHash (filename )
607622 except (IOException , NoSuchAlgorithmException ), e :
608623 ex = exception_helper .create_deploy_exception ('WLSDPLY-09309' , filename , e .getLocalizedMessage (), error = e )
@@ -734,7 +749,8 @@ def __deploy_model_applications(self, model_apps, app_location, deployed_applist
734749 options = _get_deploy_options (model_apps , app_name , library_module = 'false' )
735750 for uses_path_tokens_attribute_name in uses_path_tokens_attribute_names :
736751 if uses_path_tokens_attribute_name in app_dict :
737- self .__extract_file_from_archive (app_dict [uses_path_tokens_attribute_name ])
752+ self .__extract_source_path_from_archive (app_dict [uses_path_tokens_attribute_name ],
753+ APPLICATION , app_name )
738754
739755 location .add_name_token (token_name , app_name )
740756 resource_group_template_name , resource_group_name , partition_name = \
@@ -823,6 +839,31 @@ def __extract_file_from_archive(self, path):
823839 self .archive_helper .extract_file (path )
824840 return
825841
842+ def __extract_source_path_from_archive (self , source_path , model_type , model_name ):
843+ """
844+ Extract contents from the archive set for the specified source path.
845+ The contents may be a single file, or a directory with exploded content.
846+ :param source_path: the path to be extracted (previously checked to be under wlsdeploy)
847+ :param model_type: the model type (Application, etc.), used for logging
848+ :param model_name: the element name (my-app, etc.), used for logging
849+ """
850+ _method_name = '__extract_source_path_from_archive'
851+
852+ # source path may be may be a single file (jar, war, etc.)
853+ if self .archive_helper .contains_file (source_path ):
854+ self .archive_helper .extract_file (source_path )
855+
856+ # source path may be exploded directory in archive
857+ elif self .archive_helper .contains_path (source_path ):
858+ self .archive_helper .extract_directory (source_path )
859+
860+ else :
861+ ex = exception_helper .create_deploy_exception ('WLSDPLY-09330' , model_type , model_name , source_path )
862+ self .logger .throwing (ex , class_name = self ._class_name , method_name = _method_name )
863+ raise ex
864+
865+ return
866+
826867 def __get_deployable_library_versioned_name (self , source_path , model_name ):
827868 """
828869 Get the proper name of the deployable library that WLST requires in the target domain. This method is
@@ -840,49 +881,28 @@ def __get_deployable_library_versioned_name(self, source_path, model_name):
840881
841882 old_name_tuple = deployer_utils .get_library_name_components (model_name , self .wlst_mode )
842883 try :
884+ versioned_name = old_name_tuple [self ._EXTENSION_INDEX ]
843885 source_path = self .model_context .replace_token_string (source_path )
844- archive = JarFile (source_path )
845- manifest_object = archive .getManifest ()
846- tokens = []
847- if manifest_object is not None :
848- bao = ByteArrayOutputStream ()
849- manifest_object .write (bao )
850- manifest = bao .toString ('UTF-8' )
851- tokens = manifest .split ()
852-
853- if 'Extension-Name:' in tokens :
854- extension_index = tokens .index ('Extension-Name:' )
855- if len (tokens ) > extension_index :
856- versioned_name = tokens [extension_index + 1 ]
857- else :
858- ex = exception_helper .create_deploy_exception ('WLSDPLY-09321' , model_name , source_path , tokens )
859- self .logger .throwing (ex , class_name = self ._class_name , method_name = _method_name )
860- raise ex
861- else :
862- versioned_name = old_name_tuple [self ._EXTENSION_INDEX ]
886+ manifest = self .__get_manifest (source_path )
887+ if manifest is not None :
888+ attributes = manifest .getMainAttributes ()
889+
890+ extension_name = attributes .getValue ("Extension-Name" )
891+ if not string_utils .is_empty (extension_name ):
892+ versioned_name = extension_name
863893
864- if 'Specification-Version:' in tokens :
865- spec_index = tokens .index ('Specification-Version:' )
866- if len (tokens ) > spec_index :
867- versioned_name += '#' + tokens [spec_index + 1 ]
894+ specification_version = attributes .getValue ("Specification-Version" )
895+ if not string_utils .is_empty (specification_version ):
896+ versioned_name += '#' + specification_version
868897
869898 # Cannot specify an impl version without a spec version
870- if 'Implementation-Version:' in tokens :
871- impl_index = tokens .index ('Implementation-Version:' )
872- if len (tokens ) > impl_index :
873- versioned_name += '@' + tokens [impl_index + 1 ]
874- else :
875- ex = exception_helper .create_deploy_exception ('WLSDPLY-09322' , model_name ,
876- source_path , tokens )
877- self .logger .throwing (ex , class_name = self ._class_name , method_name = _method_name )
878- raise ex
879- else :
880- ex = exception_helper .create_deploy_exception ('WLSDPLY-09323' , model_name , source_path , tokens )
881- self .logger .throwing (ex , class_name = self ._class_name , method_name = _method_name )
882- raise ex
899+ implementation_version = attributes .getValue ("Implementation-Version" )
900+ if not string_utils .is_empty (implementation_version ):
901+ versioned_name += '@' + implementation_version
902+
903+ self .logger .info ('WLSDPLY-09324' , model_name , versioned_name ,
904+ class_name = self ._class_name , method_name = _method_name )
883905
884- self .logger .info ('WLSDPLY-09324' , model_name , versioned_name ,
885- class_name = self ._class_name , method_name = _method_name )
886906 except (IOException , FileNotFoundException , ZipException , IllegalStateException ), e :
887907 ex = exception_helper .create_deploy_exception ('WLSDPLY-09325' , model_name , source_path , str (e ), error = e )
888908 self .logger .throwing (ex , class_name = self ._class_name , method_name = _method_name )
@@ -912,8 +932,8 @@ def __get_deployable_application_versioned_name(self, source_path, model_name):
912932
913933 try :
914934 source_path = self .model_context .replace_token_string (source_path )
915- archive = JarFile (source_path )
916- manifest = archive . getManifest ()
935+ manifest = self . __get_manifest (source_path )
936+
917937 if manifest is not None :
918938 attributes = manifest .getMainAttributes ()
919939 application_version = attributes .getValue (self ._APP_VERSION_MANIFEST_KEY )
@@ -930,6 +950,37 @@ def __get_deployable_application_versioned_name(self, source_path, model_name):
930950 self .logger .exiting (class_name = self ._class_name , method_name = _method_name , result = versioned_name )
931951 return versioned_name
932952
953+ def __get_manifest (self , source_path ):
954+ """
955+ Returns the manifest object for the specified path.
956+ The source path may be a jar, or an exploded path.
957+ :param source_path: the source path to be checked
958+ :return: the manifest, or None if it is not present
959+ :raises: IOException: if there are problems reading an existing manifest
960+ """
961+ source_path_file = File (source_path )
962+ manifest = None
963+
964+ if source_path_file .isDirectory ():
965+ manifest_file = File (source_path_file , "META-INF/MANIFEST.MF" )
966+ if manifest_file .exists ():
967+ stream = None
968+ try :
969+ stream = FileInputStream (manifest_file )
970+ manifest = Manifest (stream )
971+ finally :
972+ if stream is not None :
973+ try :
974+ stream .close ()
975+ except IOException :
976+ # nothing to report
977+ pass
978+ else :
979+ archive = JarFile (source_path )
980+ manifest = archive .getManifest ()
981+
982+ return manifest
983+
933984 def __get_deployment_ordering (self , apps ):
934985 _method_name = '__get_deployment_ordering'
935986 name_sorted_keys = apps .keys ()
0 commit comments