001package org.kuali.common.util.metainf.spring; 002 003import java.io.File; 004import java.util.ArrayList; 005import java.util.Comparator; 006import java.util.HashMap; 007import java.util.List; 008import java.util.Map; 009 010import org.kuali.common.util.metainf.model.MetaInfContext; 011import org.kuali.common.util.metainf.model.MetaInfResource; 012import org.kuali.common.util.metainf.model.MetaInfResourceFilenameComparator; 013import org.kuali.common.util.metainf.model.MetaInfResourceLocationComparator; 014import org.kuali.common.util.metainf.service.MetaInfUtils; 015import org.kuali.common.util.nullify.NullUtils; 016import org.kuali.common.util.project.ProjectUtils; 017import org.kuali.common.util.project.model.Build; 018import org.kuali.common.util.project.model.Project; 019import org.kuali.common.util.project.spring.AutowiredProjectConfig; 020import org.kuali.common.util.spring.SpringUtils; 021import org.kuali.common.util.spring.env.EnvironmentService; 022import org.kuali.common.util.spring.service.SpringServiceConfig; 023import org.springframework.beans.factory.annotation.Autowired; 024import org.springframework.context.annotation.Bean; 025import org.springframework.context.annotation.Configuration; 026import org.springframework.context.annotation.Import; 027 028/** 029 * TODO Should not be a class called {@code RiceSqlConfig} down here in kuali-util. Create a rice-util and move this there? Main issue preventing this from living in the rice-xml 030 * module itself is that it gets tricky having software used very early in the build lifecycle reside in the same project that makes use of it. 031 */ 032@Configuration 033@Import({ AutowiredProjectConfig.class, MetaInfExecutableConfig.class, SpringServiceConfig.class }) 034public class RiceSqlConfig implements MetaInfContextsConfig { 035 036 private static final boolean DEFAULT_GENERATE_RELATIVE_PATHS = true; 037 private static final String RELATIVE_KEY = MetaInfUtils.PROPERTY_PREFIX + ".sql.relative"; 038 private static final String PREFIX = "sql"; 039 private static final String DEFAULT_VENDORS = "mysql,oracle"; 040 private static final String VENDORS_KEY = MetaInfUtils.PROPERTY_PREFIX + ".db.vendors"; 041 private static final String IMPEX_ARTIFACT_ID = "rice-impex-master"; 042 043 @Autowired 044 EnvironmentService env; 045 046 @Autowired 047 Project project; 048 049 @Autowired 050 Build build; 051 052 @Override 053 @Bean 054 public List<MetaInfContext> metaInfContexts() { 055 List<String> vendors = SpringUtils.getNoneSensitiveListFromCSV(env, VENDORS_KEY, DEFAULT_VENDORS); 056 List<MetaInfContext> contexts = new ArrayList<MetaInfContext>(); 057 for (String vendor : vendors) { 058 for (MetaInfGroup group : MetaInfGroup.values()) { 059 MetaInfContext context = getMetaInfContext(group, vendor); 060 contexts.add(context); 061 } 062 } 063 return contexts; 064 } 065 066 protected MetaInfContext getMetaInfContext(MetaInfGroup group, String vendor) { 067 Map<MetaInfGroup, String> defaultIncludes = getDefaultIncludes(project, IMPEX_ARTIFACT_ID, vendor); 068 Map<MetaInfGroup, String> defaultExcludes = getDefaultExcludes(defaultIncludes); 069 boolean relativePaths = env.getBoolean(RELATIVE_KEY, DEFAULT_GENERATE_RELATIVE_PATHS); 070 File outputFile = MetaInfUtils.getOutputFile(project, build, vendor, group); 071 String includesKey = MetaInfConfigUtils.getIncludesKey(group, PREFIX) + "." + vendor; 072 String excludesKey = MetaInfConfigUtils.getExcludesKey(group, PREFIX) + "." + vendor; 073 List<String> includes = SpringUtils.getNoneSensitiveListFromCSV(env, includesKey, defaultIncludes.get(group)); 074 List<String> excludes = SpringUtils.getNoneSensitiveListFromCSV(env, excludesKey, defaultExcludes.get(group)); 075 File scanDir = build.getOutputDir(); 076 String encoding = build.getEncoding(); 077 Comparator<MetaInfResource> comparator = getComparator(group); 078 return new MetaInfContext.Builder(outputFile, encoding, scanDir).comparator(comparator).includes(includes).excludes(excludes).relativePaths(relativePaths).build(); 079 } 080 081 protected Comparator<MetaInfResource> getComparator(MetaInfGroup group) { 082 if (MetaInfGroup.OTHER.equals(group)) { 083 // The upgrades folder for Rice has a nested directory structure - [server|client]:[bootstrap|demo|test]. 084 // At the moment, the sorting of SQL located inside the "upgrades" folder for Rice ignores the directory structure and just sorts by filename. 085 // The idea is that the "initial-db" folder inside Rice will soon have a structure similar to the "upgrades" folder. 086 // This should enable "additive" dataset generation instead of "subtractive". 087 // Once the "initial-db" structure is in place, this specialized comparator should be removed. 088 // All SQL resources would then be sorted by the fully qualified location. 089 return new MetaInfResourceFilenameComparator(); 090 } else { 091 return new MetaInfResourceLocationComparator(); 092 } 093 } 094 095 protected Map<MetaInfGroup, String> getDefaultIncludes(Project project, String impexArtifactId, String vendor) { 096 String resourcePath = ProjectUtils.getResourcePath(project.getGroupId(), project.getArtifactId()); 097 Map<MetaInfGroup, String> map = new HashMap<MetaInfGroup, String>(); 098 map.put(MetaInfGroup.SCHEMA, resourcePath + "/initial-db/sql/" + vendor + "/" + impexArtifactId + ".sql"); 099 map.put(MetaInfGroup.DATA, resourcePath + "/initial-db/sql/" + vendor + "/*.sql"); 100 map.put(MetaInfGroup.CONSTRAINTS, resourcePath + "/initial-db/sql/" + vendor + "/" + impexArtifactId + "-constraints.sql"); 101 map.put(MetaInfGroup.OTHER, resourcePath + "/upgrades/**/" + vendor + "/**/*.sql"); 102 return map; 103 } 104 105 protected Map<MetaInfGroup, String> getDefaultExcludes(Map<MetaInfGroup, String> defaultIncludes) { 106 Map<MetaInfGroup, String> map = new HashMap<MetaInfGroup, String>(); 107 // The schema includes is specific to one exact file, no need to exclude anything 108 map.put(MetaInfGroup.SCHEMA, NullUtils.NONE); 109 // Exclude the schema + constraints SQL 110 map.put(MetaInfGroup.DATA, defaultIncludes.get(MetaInfGroup.SCHEMA) + "," + defaultIncludes.get(MetaInfGroup.CONSTRAINTS)); 111 // The constraint includes is specific to one exact file, no need to exclude anything 112 map.put(MetaInfGroup.CONSTRAINTS, NullUtils.NONE); 113 // No need to exclude any of the "upgrades" SQL 114 map.put(MetaInfGroup.OTHER, NullUtils.NONE); 115 return map; 116 } 117 118}