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