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