001package org.kuali.common.util.metainf.service; 002 003import java.io.File; 004import java.io.IOException; 005import java.util.ArrayList; 006import java.util.Collections; 007import java.util.List; 008 009import org.apache.commons.io.FileUtils; 010import org.apache.commons.lang3.ArrayUtils; 011import org.apache.commons.lang3.StringUtils; 012import org.kuali.common.util.SimpleScanner; 013import org.kuali.common.util.Str; 014import org.kuali.common.util.metainf.model.PathComparator; 015import org.kuali.common.util.metainf.spring.MetaInfDataLocation; 016import org.kuali.common.util.metainf.spring.MetaInfDataType; 017import org.kuali.common.util.metainf.spring.MetaInfGroup; 018import org.kuali.common.util.project.KualiUtilProjectConstants; 019import org.kuali.common.util.project.ProjectUtils; 020import org.kuali.common.util.project.model.Build; 021import org.kuali.common.util.project.model.Project; 022import org.kuali.common.util.project.model.ProjectIdentifier; 023import org.springframework.core.io.ClassPathResource; 024import org.springframework.core.io.Resource; 025import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 026import org.springframework.util.ResourceUtils; 027 028import com.google.common.base.Optional; 029import com.google.common.collect.Lists; 030 031public class MetaInfUtils { 032 033 public static final String RESOURCES_FILENAME_EXTENSION = "resources"; 034 public static final String METAINF_DIRECTORY_NAME = "META-INF"; 035 036 /** 037 * @deprecated 038 */ 039 @Deprecated 040 public static final org.kuali.common.util.project.model.FeatureIdentifier FEATURE_ID = new org.kuali.common.util.project.model.FeatureIdentifier( 041 KualiUtilProjectConstants.PROJECT_ID, "metainf"); 042 043 public static final String PROPERTY_PREFIX = "metainf"; 044 045 /** 046 * <code>${project.build.outputDirectory}/META-INF/org/kuali/util/kuali-util/[group].resources</code> 047 */ 048 public static File getOutputFile(Project project, Build build, MetaInfGroup group) { 049 return getOutputFile(project, build, group.name().toLowerCase()); 050 } 051 052 /** 053 * <code>${project.build.outputDirectory}/META-INF/org/kuali/util/kuali-util/[filename].resources</code> 054 */ 055 public static File getOutputFile(Project project, Build build, String filename) { 056 return getOutputFile(project, build, Optional.<String> absent(), filename); 057 } 058 059 /** 060 * <code>${project.build.outputDirectory}/META-INF/org/kuali/util/kuali-util/[qualifier]/[group].resources</code> 061 */ 062 public static File getOutputFile(Project project, Build build, String qualifier, MetaInfGroup group) { 063 return getOutputFile(project, build, Optional.of(qualifier), group.name().toLowerCase()); 064 } 065 066 /** 067 * <code>${project.build.outputDirectory}/META-INF/org/kuali/util/kuali-util/[qualifier]/[filename].resources</code> 068 */ 069 public static File getOutputFile(Project project, Build build, String qualifier, String filename) { 070 return getOutputFile(project, build, Optional.of(qualifier), filename); 071 } 072 073 /** 074 * <code>${project.build.outputDirectory}/META-INF/org/kuali/util/kuali-util/[qualifier]/[filename].resources</code> where <code>[qualifier]</code> is optional 075 */ 076 public static File getOutputFile(Project project, Build build, Optional<String> qualifier, String filename) { 077 return getOutputFile(project, build, qualifier, Optional.<MetaInfDataLocation> absent(), Optional.<MetaInfDataType> absent(), filename); 078 } 079 080 /** 081 * <code>${project.build.outputDirectory}/META-INF/org/kuali/util/kuali-util/[qualifier]/[location]/[type]/[filename].resources</code> where <code>[qualifier]</code>, 082 * <code>[location]</code>, and <type>[type]</type> are optional 083 */ 084 public static File getOutputFile(Project project, Build build, Optional<String> qualifier, Optional<MetaInfDataLocation> location, Optional<MetaInfDataType> type, 085 String filename) { 086 StringBuilder sb = new StringBuilder(); 087 sb.append(getResourcePrefix(project)); 088 if (qualifier.isPresent()) { 089 sb.append("/"); 090 sb.append(qualifier.get()); 091 } 092 if (location.isPresent()) { 093 sb.append("/"); 094 sb.append(location.get().name().toLowerCase()); 095 } 096 if (type.isPresent()) { 097 sb.append("/"); 098 sb.append(type.get().name().toLowerCase()); 099 } 100 sb.append("/"); 101 sb.append(getFilename(filename)); 102 return new File(build.getOutputDir(), sb.toString()); 103 } 104 105 /** 106 * <code>classpath:META-INF/org/kuali/util/kuali-util/[group].resources</code> 107 */ 108 public static String getClasspathResource(ProjectIdentifier project, MetaInfGroup group) { 109 return getClasspathResource(project.getGroupId(), project.getArtifactId(), group); 110 } 111 112 /** 113 * <code>classpath:META-INF/org/kuali/util/kuali-util/[filename].resources</code> 114 */ 115 public static String getClasspathResource(ProjectIdentifier project, String filename) { 116 return getClasspathResource(project.getGroupId(), project.getArtifactId(), filename); 117 } 118 119 /** 120 * <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[group].resources</code> 121 */ 122 public static String getClasspathResource(ProjectIdentifier project, String qualifier, MetaInfGroup group) { 123 return getClasspathResource(project.getGroupId(), project.getArtifactId(), Optional.of(qualifier), group.name().toLowerCase()); 124 } 125 126 /** 127 * <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[filename].resources</code> 128 */ 129 public static String getClasspathResource(ProjectIdentifier project, String qualifier, String filename) { 130 return getClasspathResource(project.getGroupId(), project.getArtifactId(), Optional.of(qualifier), filename); 131 } 132 133 /** 134 * <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[filename].resources</code> where <code>[qualifier]</code>, <code>[location]</code>, and <type>[type]</type> 135 * are optional 136 */ 137 public static String getClasspathResource(ProjectIdentifier project, Optional<String> qualifier, Optional<MetaInfDataLocation> location, Optional<MetaInfDataType> type, 138 String filename) { 139 return getClasspathResource(project.getGroupId(), project.getArtifactId(), qualifier, location, type, filename); 140 } 141 142 /** 143 * <code>classpath:META-INF/org/kuali/util/kuali-util/[group].resources</code> 144 */ 145 public static String getClasspathResource(Project project, MetaInfGroup group) { 146 return getClasspathResource(project.getGroupId(), project.getArtifactId(), group); 147 } 148 149 /** 150 * <code>classpath:META-INF/org/kuali/util/kuali-util/[filename].resources</code> 151 */ 152 public static String getClasspathResource(Project project, String filename) { 153 return getClasspathResource(project.getGroupId(), project.getArtifactId(), filename); 154 } 155 156 /** 157 * <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[group].resources</code> 158 */ 159 public static String getClasspathResource(Project project, String qualifier, MetaInfGroup group) { 160 return getClasspathResource(project.getGroupId(), project.getArtifactId(), Optional.of(qualifier), group.name().toLowerCase()); 161 } 162 163 /** 164 * <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[filename].resources</code> 165 */ 166 public static String getClasspathResource(Project project, String qualifier, String filename) { 167 return getClasspathResource(project.getGroupId(), project.getArtifactId(), Optional.of(qualifier), filename); 168 } 169 170 /** 171 * <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[filename].resources</code> where <code>[qualifier]</code>, <code>[location]</code>, and <type>[type]</type> 172 * are optional 173 */ 174 public static String getClasspathResource(Project project, Optional<String> qualifier, Optional<MetaInfDataLocation> location, Optional<MetaInfDataType> type, String filename) { 175 return getClasspathResource(project.getGroupId(), project.getArtifactId(), qualifier, location, type, filename); 176 } 177 178 /** 179 * <code>classpath:META-INF/org/kuali/util/kuali-util/[group].resources</code> 180 */ 181 public static String getClasspathResource(String groupId, String artifactId, MetaInfGroup group) { 182 return getClasspathResource(groupId, artifactId, Optional.<String> absent(), group.name().toLowerCase()); 183 } 184 185 /** 186 * <code>classpath:META-INF/org/kuali/util/kuali-util/[filename].resources</code> 187 */ 188 public static String getClasspathResource(String groupId, String artifactId, String filename) { 189 return getClasspathResource(groupId, artifactId, Optional.<String> absent(), filename); 190 } 191 192 /** 193 * <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[filename].resources</code> where <code>[qualifier]</code> is optional 194 */ 195 public static String getClasspathResource(String groupId, String artifactId, Optional<String> qualifier, String filename) { 196 return getClasspathResource(groupId, artifactId, qualifier, Optional.<MetaInfDataLocation> absent(), Optional.<MetaInfDataType> absent(), filename); 197 } 198 199 /** 200 * <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[filename].resources</code> where <code>[qualifier]</code>, <code>[location]</code>, and <type>[type]</type> 201 * are optional 202 */ 203 public static String getClasspathResource(String groupId, String artifactId, Optional<String> qualifier, Optional<MetaInfDataLocation> location, 204 Optional<MetaInfDataType> type, String filename) { 205 StringBuilder sb = new StringBuilder(); 206 sb.append(ResourceUtils.CLASSPATH_URL_PREFIX); 207 sb.append(getResourcePrefix(groupId, artifactId)); 208 if (qualifier.isPresent()) { 209 sb.append("/"); 210 sb.append(qualifier.get()); 211 } 212 if (location.isPresent()) { 213 sb.append("/"); 214 sb.append(location.get().name().toLowerCase()); 215 } 216 if (type.isPresent()) { 217 sb.append("/"); 218 sb.append(type.get().name().toLowerCase()); 219 } 220 sb.append("/"); 221 sb.append(getFilename(filename)); 222 return sb.toString(); 223 } 224 225 /** 226 * List of <code>classpath:META-INF/org/kuali/util/kuali-util/[filename].resources</code> where <code>[filename]</code> can contain an Ant-style pattern 227 */ 228 public static List<String> getPatternedClasspathResources(ProjectIdentifier project, String filename) { 229 return getPatternedClasspathResources(project.getGroupId(), project.getArtifactId(), filename); 230 } 231 232 /** 233 * List of <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[group].resources</code> where <code>[qualifier]</code> can contain an Ant-style pattern 234 */ 235 public static List<String> getPatternedClasspathResources(ProjectIdentifier project, String qualifier, MetaInfGroup group) { 236 return getPatternedClasspathResources(project.getGroupId(), project.getArtifactId(), Optional.of(qualifier), group.name().toLowerCase()); 237 } 238 239 /** 240 * List of <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[filename].resources</code> where <code>[qualifier]</code> and <code>[filename]</code> can contain an 241 * Ant-style pattern 242 */ 243 public static List<String> getPatternedClasspathResources(ProjectIdentifier project, String qualifier, String filename) { 244 return getPatternedClasspathResources(project.getGroupId(), project.getArtifactId(), Optional.of(qualifier), filename); 245 } 246 247 /** 248 * List of <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[location]/[type]/[filename].resources</code> where <code>[qualifier]</code>, <code>[location]</code>, 249 * and <type>[type]</type> are optional and <code>[qualifier]</code> and <code>[filename]</code> can contain an Ant-style pattern 250 */ 251 public static List<String> getPatternedClasspathResources(ProjectIdentifier project, Optional<String> qualifier, Optional<MetaInfDataLocation> location, 252 Optional<MetaInfDataType> type, String filename) { 253 return getPatternedClasspathResources(project.getGroupId(), project.getArtifactId(), qualifier, location, type, filename); 254 } 255 256 /** 257 * List of <code>classpath:META-INF/org/kuali/util/kuali-util/[filename].resources</code> where <code>[filename]</code> can contain an Ant-style pattern 258 */ 259 public static List<String> getPatternedClasspathResources(Project project, String filename) { 260 return getPatternedClasspathResources(project.getGroupId(), project.getArtifactId(), filename); 261 } 262 263 /** 264 * List of <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[group].resources</code> where <code>[qualifier]</code> can contain an Ant-style pattern 265 */ 266 public static List<String> getPatternedClasspathResources(Project project, String qualifier, MetaInfGroup group) { 267 return getPatternedClasspathResources(project.getGroupId(), project.getArtifactId(), Optional.of(qualifier), group.name().toLowerCase()); 268 } 269 270 /** 271 * List of <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[filename].resources</code> where <code>[qualifier]</code> and <code>[filename]</code> can contain an 272 * Ant-style pattern 273 */ 274 public static List<String> getPatternedClasspathResources(Project project, String qualifier, String filename) { 275 return getPatternedClasspathResources(project.getGroupId(), project.getArtifactId(), Optional.of(qualifier), filename); 276 } 277 278 /** 279 * List of <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[location]/[type]/[filename].resources</code> where <code>[qualifier]</code>, <code>[location]</code>, 280 * and <type>[type]</type> are optional and <code>[qualifier]</code> and <code>[filename]</code> can contain an Ant-style pattern 281 */ 282 public static List<String> getPatternedClasspathResources(Project project, Optional<String> qualifier, Optional<MetaInfDataLocation> location, Optional<MetaInfDataType> type, 283 String filename) { 284 return getPatternedClasspathResources(project.getGroupId(), project.getArtifactId(), qualifier, location, type, filename); 285 } 286 287 /** 288 * List of <code>classpath:META-INF/org/kuali/util/kuali-util/[filename].resources</code> where <code>[filename]</code> can contain an Ant-style pattern 289 */ 290 public static List<String> getPatternedClasspathResources(String groupId, String artifactId, String filename) { 291 return getPatternedClasspathResources(groupId, artifactId, Optional.<String> absent(), filename); 292 } 293 294 /** 295 * List of <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[filename].resources</code> where <code>[qualifier]</code> is optional * and <code>[qualifier]</code> 296 * and <code>[filename]</code> can contain an Ant-style pattern 297 */ 298 public static List<String> getPatternedClasspathResources(String groupId, String artifactId, Optional<String> qualifier, String filename) { 299 return getPatternedClasspathResources(groupId, artifactId, qualifier, Optional.<MetaInfDataLocation> absent(), Optional.<MetaInfDataType> absent(), filename); 300 } 301 302 /** 303 * List of <code>classpath:META-INF/org/kuali/util/kuali-util/[qualifier]/[filename].resources</code> where <code>[qualifier]</code>, <code>[location]</code>, and 304 * <type>[type]</type> are optional and <code>[qualifier]</code> and <code>[filename]</code> can contain an Ant-style pattern 305 */ 306 public static List<String> getPatternedClasspathResources(String groupId, String artifactId, Optional<String> qualifier, Optional<MetaInfDataLocation> location, 307 Optional<MetaInfDataType> type, String filename) { 308 List<String> patterenedClasspathResources = new ArrayList<String>(); 309 String classpathResource = getClasspathResource(groupId, artifactId, qualifier, location, type, filename); 310 PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 311 try { 312 Resource[] resources = resolver.getResources(classpathResource); 313 if (ArrayUtils.isNotEmpty(resources)) { 314 for (Resource resource : resources) { 315 if (resource instanceof ClassPathResource) { 316 ClassPathResource classPathResource = (ClassPathResource) resource; 317 patterenedClasspathResources.add(ResourceUtils.CLASSPATH_URL_PREFIX + classPathResource.getPath()); 318 } 319 } 320 } 321 } catch (IOException ioe) { 322 throw new IllegalStateException("Unexpected IO error", ioe); 323 } 324 return patterenedClasspathResources; 325 } 326 327 /** 328 * Returns <code>[group].resources</code> (always lowercase) 329 */ 330 public static String getFilename(MetaInfGroup group) { 331 return getFilename(group.name().toLowerCase()); 332 } 333 334 /** 335 * Returns <code>[filename].resources</code> 336 */ 337 public static String getFilename(String filename) { 338 return filename + "." + RESOURCES_FILENAME_EXTENSION; 339 } 340 341 /** 342 * <code>META-INF/org/kuali/util</code> 343 */ 344 public static String getGroupPrefix(Project project) { 345 return getGroupPrefix(project.getGroupId()); 346 } 347 348 /** 349 * <code>META-INF/org/kuali/util</code> 350 */ 351 public static String getGroupPrefix(String groupId) { 352 return METAINF_DIRECTORY_NAME + "/" + Str.getPath(groupId); 353 } 354 355 /** 356 * <code>classpath:META-INF</code> 357 */ 358 public static String getClasspathPrefix() { 359 return ResourceUtils.CLASSPATH_URL_PREFIX + METAINF_DIRECTORY_NAME; 360 } 361 362 /** 363 * <code>META-INF/org/kuali/util/kuali-util</code> 364 */ 365 public static String getResourcePrefix(Project project) { 366 return getResourcePrefix(project.getGroupId(), project.getArtifactId()); 367 } 368 369 /** 370 * <code>META-INF/org/kuali/util/kuali-util</code> 371 */ 372 public static String getResourcePrefix(String groupId, String artifactId) { 373 return getGroupPrefix(groupId) + "/" + artifactId; 374 } 375 376 /** 377 * <code>META-INF/org/kuali/util/kuali-util</code> 378 */ 379 public static String getResourcePrefix(ProjectIdentifier project) { 380 return getResourcePrefix(project.getGroupId(), project.getArtifactId()); 381 } 382 383 /** 384 * <code>classpath:META-INF/org/kuali/util/kuali-util</code> 385 */ 386 public static String getClasspathResourcePrefix(ProjectIdentifier project) { 387 StringBuilder sb = new StringBuilder(); 388 sb.append(ResourceUtils.CLASSPATH_URL_PREFIX); 389 sb.append(getResourcePrefix(project.getGroupId(), project.getArtifactId())); 390 return sb.toString(); 391 } 392 393 /** 394 * <code>classpath:META-INF/org/kuali/util/kuali-util</code> 395 */ 396 public static String getClasspathResourcePrefix(Project project) { 397 StringBuilder sb = new StringBuilder(); 398 sb.append(ResourceUtils.CLASSPATH_URL_PREFIX); 399 sb.append(getResourcePrefix(project.getGroupId(), project.getArtifactId())); 400 return sb.toString(); 401 } 402 403 public static List<String> getQualifiers(File baseDirectory, ProjectIdentifier project, List<String> includes, List<String> excludes) { 404 String resourcePath = ProjectUtils.getResourcePath(project.getGroupId(), project.getArtifactId()); 405 File resourceDirectory = FileUtils.getFile(baseDirectory, resourcePath); 406 return getQualifiers(resourceDirectory, includes, excludes); 407 } 408 409 public static List<String> getQualifiers(File baseDirectory, Project project, List<String> includes, List<String> excludes) { 410 String resourcePath = ProjectUtils.getResourcePath(project.getGroupId(), project.getArtifactId()); 411 File resourceDirectory = FileUtils.getFile(baseDirectory, resourcePath); 412 return getQualifiers(resourceDirectory, includes, excludes); 413 } 414 415 public static List<String> getQualifiers(File baseDirectory, List<String> includes, List<String> excludes) { 416 List<String> qualifiers = Lists.newArrayList(); 417 SimpleScanner scanner = new SimpleScanner(baseDirectory, includes, excludes); 418 List<String> directories = scanner.getDirectories(); 419 Collections.sort(directories, new PathComparator()); 420 for (String directory : directories) { 421 if (qualifiers.isEmpty()) { 422 qualifiers.add(directory); 423 } else { 424 boolean matches = false; 425 for (String qualifier : qualifiers) { 426 matches |= StringUtils.startsWith(directory, qualifier); 427 } 428 if (!matches) { 429 qualifiers.add(directory); 430 } 431 } 432 } 433 return qualifiers; 434 } 435 436}