001/** 002 * '$RCSfile$' 003 * '$Author: crawl $' 004 * '$Date: 2012-11-26 22:21:34 +0000 (Mon, 26 Nov 2012) $' 005 * '$Revision: 31119 $' 006 * 007 * For Details: 008 * http://www.kepler-project.org 009 * 010 * Copyright (c) 2010 The Regents of the 011 * University of California. All rights reserved. Permission is hereby granted, 012 * without written agreement and without license or royalty fees, to use, copy, 013 * modify, and distribute this software and its documentation for any purpose, 014 * provided that the above copyright notice and the following two paragraphs 015 * appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF 016 * CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, 017 * OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS 018 * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE 019 * POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY 020 * DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE 022 * SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 023 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 024 * ENHANCEMENTS, OR MODIFICATIONS. 025 */ 026package org.kepler.kar; 027 028import java.util.LinkedHashMap; 029import java.util.List; 030import java.util.StringTokenizer; 031import java.util.Vector; 032 033import org.kepler.build.modules.Module; 034import org.kepler.build.modules.ModuleTree; 035import org.kepler.build.modules.OSRegistryTxt; 036import org.kepler.build.util.Version; 037import org.kepler.configuration.ConfigurationManager; 038import org.kepler.configuration.ConfigurationManagerException; 039import org.kepler.configuration.ConfigurationProperty; 040import org.kepler.configuration.NamespaceException; 041 042 043/** 044 * @author Aaron Schultz 045 */ 046public class ModuleDependencyUtil { 047 048 /** 049 * Return a Vector<String> that contains the module dependencies found in 050 * the given formatted String list (of the type created by 051 * generateDependencyString(Vector<String>). This method can be reversed 052 * using generateDependencyString(Vector<String>). 053 * 054 * @param depStr 055 * @return 056 */ 057 public static Vector<String> parseDependencyString(String depStr) { 058 Vector<String> dependencies = new Vector<String>(); 059 if (depStr == null || depStr.trim().equals("")) { 060 return dependencies; 061 } 062 StringTokenizer st = new StringTokenizer(depStr, KARFile.DEP_SEPARATOR); 063 while (st.hasMoreTokens()) { 064 String dep = st.nextToken(); 065 if (!dependencies.contains(dep)) { 066 dependencies.add(dep); 067 } 068 } 069 return dependencies; 070 } 071 072 /** 073 * Return a delimited string containing the given list of module 074 * dependencies. This method can be reversed using 075 * parseDependencyString(String). 076 * 077 * @param dependencies 078 * @return String formatted list of Module dependencies. 079 */ 080 public static String generateDependencyString(Vector<String> dependencies) { 081 String dependencyStr = ""; 082 for (String dep : dependencies) { 083 dependencyStr += dep + KARFile.DEP_SEPARATOR; 084 } 085 // remove end separator 086 if (dependencyStr.endsWith(KARFile.DEP_SEPARATOR)) { 087 dependencyStr = dependencyStr.substring(0, dependencyStr.length() 088 - KARFile.DEP_SEPARATOR.length()); 089 } 090 return dependencyStr; 091 } 092 093 /** 094 * @return currently active modules list as 095 * delimited string 096 */ 097 public static String buildModuleDependenciesString() { 098 String dependenciesStr = ""; 099 Vector<String> dependencies = new Vector<String>(); 100 101 ModuleTree moduleTree = ModuleTree.instance(); 102 for( Module m : moduleTree ){ 103 dependencies.add(m.toString()); 104 } 105 for (String dependency : dependencies) { 106 dependenciesStr += dependency + KARFile.DEP_SEPARATOR; 107 } 108 if (dependenciesStr.endsWith(KARFile.DEP_SEPARATOR)) { 109 // remove the last semicolon 110 dependenciesStr = dependenciesStr.substring(0, dependenciesStr 111 .length() 112 - KARFile.DEP_SEPARATOR.length()); 113 } 114 return dependenciesStr; 115 } 116 117 /** 118 * 119 * @param moduleDependencies 120 * @return 121 */ 122 public static boolean checkIfModuleDependenciesSatisfied(Vector<String> moduleDependencies) { 123 124 //first fetch KAR compliance level 125 ConfigurationManager cman = ConfigurationManager.getInstance(); 126 ConfigurationProperty coreProperty = cman.getProperty(KARFile.KARFILE_CONFIG_PROP_MODULE); 127 ConfigurationProperty KARComplianceProp = coreProperty.getProperty(KARFile.KAR_COMPLIANCE_PROPERTY_NAME); 128 // user has a core configuration.xml from before KARComplianceProp existed, need to add it 129 // if KARPreferencesTab.initializeTab hasn't already done so. 130 if (KARComplianceProp == null){ 131 KARComplianceProp = new ConfigurationProperty(KARFile.KARFILE_CONFIG_PROP_MODULE, KARFile.KAR_COMPLIANCE_PROPERTY_NAME, KARFile.KAR_COMPLIANCE_DEFAULT); 132 try { 133 coreProperty.addProperty(KARComplianceProp); 134 } catch (NamespaceException e) { 135 // TODO Auto-generated catch block 136 e.printStackTrace(); 137 } catch (ConfigurationManagerException e) { 138 // TODO Auto-generated catch block 139 e.printStackTrace(); 140 } 141 } 142 String KARCompliance = KARComplianceProp.getValue(); 143 144 145 int moduleDepsSize = moduleDependencies.size(); 146 int currentModuleListSize = ModuleTree.instance().getModuleList().size(); 147 148 if (moduleDepsSize == 0){ 149 return true; 150 } 151 152 //if strict, and different mod dep lengths, we can just return false 153 if (KARCompliance.equals(KARFile.KAR_COMPLIANCE_STRICT) && 154 moduleDepsSize != currentModuleListSize){ 155 return false; 156 } 157 158 159 boolean allDependenciesSatisfied = true; 160 for (String dep : moduleDependencies) { 161 // NOTE after r26418 ignoring dependencies that are incompatible 162 // with OS. See http://bugzilla.ecoinformatics.org/show_bug.cgi?id=5232 163 // for suggestions for a better solution. 164 if( !OSRegistryTxt.isCompatibleWithCurrentOS(Module.make(dep)) ){ 165 continue; 166 } 167 boolean depIsInModuleConfiguration = false; 168 for (Module m : ModuleTree.instance()) { 169 170 //TODO augment if additional compliance levels added 171 if (KARCompliance.equals(KARFile.KAR_COMPLIANCE_STRICT)){ 172 if (m.toString().trim().equals(dep.trim())) { 173 //System.out.println("KARFile areAllModuleDependenciesSatisfied() KARCompliance is:"+KARCompliance + 174 // " "+m.toString().trim() + " equals:"+dep.trim()); 175 depIsInModuleConfiguration = true; 176 break; 177 } 178 } 179 else if (KARCompliance.equals(KARFile.KAR_COMPLIANCE_RELAXED)){ 180 181 // fix for http://bugzilla.ecoinformatics.org/show_bug.cgi?id=5419. 182 // deal with special situation introduced in kepler 2.2: ptolemy-kepler-* > ptolemy-* 183 // e.g. we should consider ptolemy-kepler-2.2 newer than ptolemy-8.0. Except if user 184 // is running from trunk, in which case module is called ptolemy, and we assume it's most recent 185 if (m.getStemName().trim().contains(Module.PTOLEMY) && Version.stem(dep).contains(Module.PTOLEMY)) { 186 187 // this section is for letting trunk users slide, and for letting old unversioned 188 // kars be opened. 189 try{ 190 Version moduleVersion = Version.fromVersionString(m.getName()); 191 Version depVersion = Version.fromVersionString(dep); 192 if (!moduleVersion.hasMajor() || !moduleVersion.hasMinor() || !moduleVersion.hasMicro() 193 || !depVersion.hasMajor() || !depVersion.hasMinor() || !depVersion.hasMicro()){ 194 //module or dep might not have version info, just be ok with this 195 //System.out.println("ModuleDependencyUtil.checkIfModuleDependenciesSatisfied KARCompliance is:"+KARCompliance + 196 // " "+m.getName() +" or dep:"+ dep + " does not specify proper version info, will just let this slide - ok."); 197 depIsInModuleConfiguration = true; 198 break; 199 } 200 } 201 catch(IllegalArgumentException e){ 202 //module or dep might not have version info, just be ok with this 203 //System.out.println("caught exception. ModuleDependencyUtil.checkIfModuleDependenciesSatisfied KARCompliance is:"+KARCompliance + 204 // " "+m.getName() +" or dep:"+ dep + " does not specify proper version info, will just let this slide - ok."); 205 depIsInModuleConfiguration = true; 206 break; 207 } 208 209 // this section is for official release users 210 if (m.getStemName().trim().contains(Module.PTOLEMY_KEPLER) 211 && !Version.stem(dep).contains(Module.PTOLEMY_KEPLER)){ 212 //System.out.println("ModuleDependencyUtil.checkIfModuleDependenciesSatisfied KARCompliance is:"+KARCompliance + 213 // " "+m.getName() + " >= " + dep + " - ok."); 214 depIsInModuleConfiguration = true; 215 break; 216 } 217 else if (!m.getStemName().trim().contains(Module.PTOLEMY_KEPLER) 218 && Version.stem(dep).contains(Module.PTOLEMY_KEPLER)){ 219 //System.out.println("ModuleDependencyUtil.checkIfModuleDependenciesSatisfied KARCompliance is:"+KARCompliance + 220 // " "+m.getName() + " < "+ dep + " so THIS DEP NOT SATISFIED! - fail."); 221 depIsInModuleConfiguration = false; 222 break; 223 } 224 } 225 226 227 if (m.getStemName().trim().equals(Version.stem(dep))) { 228 try{ 229 Version moduleVersion = Version.fromVersionString(m.getName()); 230 Version depVersion = Version.fromVersionString(dep); 231 if (moduleVersion.hasMajor() && moduleVersion.hasMinor() && moduleVersion.hasMicro() 232 && depVersion.hasMajor() && depVersion.hasMinor() && depVersion.hasMicro()){ 233 234 if (moduleVersion.getMajor() > depVersion.getMajor() || 235 (moduleVersion.getMajor() == depVersion.getMajor() 236 && moduleVersion.getMinor() > depVersion.getMinor()) || 237 (moduleVersion.getMajor() == depVersion.getMajor() 238 && moduleVersion.getMinor() == depVersion.getMinor() 239 && moduleVersion.getMicro() > depVersion.getMicro()) || 240 (moduleVersion.getMajor() == depVersion.getMajor() 241 && moduleVersion.getMinor() == depVersion.getMinor() 242 && moduleVersion.getMicro() == depVersion.getMicro())){ 243 244 //System.out.println("KARFile areAllModuleDependenciesSatisfied() KARCompliance is:"+KARCompliance + 245 // " "+m.getName() + " >= " + dep + " - ok."); 246 depIsInModuleConfiguration = true; 247 break; 248 } 249 else{ 250 //System.out.println("ModuleDependencyUtil.checkIfModuleDependenciesSatisfied KARCompliance is:"+KARCompliance + 251 // " "+m.getName() + " < "+ dep + " so THIS DEP NOT SATISFIED! - fail."); 252 depIsInModuleConfiguration = false; 253 break; 254 } 255 } 256 else{ 257 //module or dep might not have version info, just be ok with this 258 //System.out.println("KARFile areAllModuleDependenciesSatisfied() KARCompliance is:"+KARCompliance + 259 // " "+m.getName() +" or dep:"+ dep + " does not specificy proper version info, will just let this slide - ok."); 260 depIsInModuleConfiguration = true; 261 break; 262 } 263 } 264 catch(IllegalArgumentException e){ 265 //module or dep might not have version info, just be ok with this 266 //System.out.println("caught exception. KARFile areAllModuleDependenciesSatisfied() KARCompliance is:"+KARCompliance + 267 // " "+m.getName() +" or dep:"+ dep + " does not specificy proper version info, will just let this slide - ok."); 268 depIsInModuleConfiguration = true; 269 break; 270 } 271 } 272 } 273 } 274 if (!depIsInModuleConfiguration) { 275 // Specified module dependency was not found in the 276 // current set of modules 277 //System.out.println("KARFile module dependency not found:" + dep); 278 allDependenciesSatisfied = false; 279 } 280 } 281 282 //System.out.println("ModuleDependencyUtil.checkIfModuleDependenciesSatisfied. returning allDependenciesSatisfied:"+allDependenciesSatisfied); 283 return allDependenciesSatisfied; 284 } 285 286 /** 287 * Check if versions of dependencies are all complete, defined as having specified a Major, 288 * Minor, and Micro number. 289 * @param dependencies 290 * @return 291 */ 292 public static boolean isDependencyVersioningInfoComplete(List<String> dependencies) { 293 294 for (String dependency : dependencies) { 295 Version v = null; 296 try{ 297 v = Version.fromVersionString(dependency); 298 if (!v.hasMajor() || !v.hasMinor() || !v.hasMicro()){ 299 //System.out.println("ModuleDependencyUtil isDependencyVersioningInfoComplete dependency:" 300 // +dependency+ " missing full version info. Returning false"); 301 return false; 302 } 303 } 304 catch(IllegalArgumentException iae){ 305 //System.out.println("ModuleDependencyUtil isDependencyVersioningInfoComplete dependency:" 306 // +dependency+ " missing full version info. Returning false"); 307 return false; 308 } 309 } 310 311 //System.out.println("ModuleDependencyUtil.isDependencyVersioningInfoComplete Returning true"); 312 return true; 313 } 314 315 /** 316 * Check dependencies against currently running modules to see if they're satisfied. 317 * Return a LinkedHashMap of any unsatisfied dependencies and their versions 318 * @param dependencies 319 * @return 320 */ 321 public static LinkedHashMap<String, Version> getUnsatisfiedDependencies(List<String> dependencies){ 322 323 LinkedHashMap<String, Version> unsatisfiedDependencies = new LinkedHashMap<String, Version>(); 324 ModuleTree moduleTree = ModuleTree.instance(); 325 326 for (String dependency : dependencies) { 327 Version v = null; 328 try{ 329 v = Version.fromVersionString(dependency); 330 } 331 catch(IllegalArgumentException iae){ 332 } 333 334 if (!moduleTree.contains(dependency)) { 335 //System.out.println("ModuleDependencyUtil getUnsatisfiedDependencies adding unsat dependency:"+dependency); 336 unsatisfiedDependencies.put(dependency, v); 337 } 338 else{ 339 //System.out.println("ModuleDependencyUtil getUnsatisfiedDependencies moduleTree.contains("+dependency+") no need to add this as unsat dep"); 340 } 341 } 342 343 return unsatisfiedDependencies; 344 } 345 346}