001/** 002 * Copyright 2005-2016 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.rice.sql.config.spring; 017 018import com.google.common.base.Optional; 019import com.google.common.collect.ImmutableList; 020import com.google.common.collect.Lists; 021import com.google.common.collect.Maps; 022import org.apache.commons.lang3.StringUtils; 023import org.kuali.common.util.metainf.model.MetaInfContext; 024import org.kuali.common.util.metainf.model.MetaInfResource; 025import org.kuali.common.util.metainf.model.MetaInfResourceLocationComparator; 026import org.kuali.common.util.metainf.service.MetaInfUtils; 027import org.kuali.common.util.metainf.spring.MetaInfConfigUtils; 028import org.kuali.common.util.metainf.spring.MetaInfContextsConfig; 029import org.kuali.common.util.metainf.spring.MetaInfDataLocation; 030import org.kuali.common.util.metainf.spring.MetaInfDataType; 031import org.kuali.common.util.metainf.spring.MetaInfExecutableConfig; 032import org.kuali.common.util.metainf.spring.MetaInfGroup; 033import org.kuali.common.util.nullify.NullUtils; 034import org.kuali.common.util.project.ProjectUtils; 035import org.kuali.common.util.project.model.Build; 036import org.kuali.common.util.project.model.Project; 037import org.kuali.common.util.project.spring.AutowiredProjectConfig; 038import org.kuali.common.util.spring.SpringUtils; 039import org.kuali.common.util.spring.env.EnvironmentService; 040import org.kuali.common.util.spring.service.SpringServiceConfig; 041import org.springframework.beans.factory.annotation.Autowired; 042import org.springframework.context.annotation.Bean; 043import org.springframework.context.annotation.Configuration; 044import org.springframework.context.annotation.Import; 045 046import java.io.File; 047import java.util.Comparator; 048import java.util.List; 049import java.util.Map; 050 051/** 052 * Defines the configuration for creating the sql property files that define how the database is created. 053 * 054 * @author Kuali Rice Team (rice.collab@kuali.org) 055 */ 056@Configuration 057@Import({AutowiredProjectConfig.class, MetaInfExecutableConfig.class, SpringServiceConfig.class}) 058public class RiceSqlConfig implements MetaInfContextsConfig { 059 060 private static final Boolean DEFAULT_GENERATE_RELATIVE_PATHS = Boolean.TRUE; 061 private static final String RELATIVE_KEY = MetaInfUtils.PROPERTY_PREFIX + ".sql.relative"; 062 private static final String PREFIX = "sql"; 063 private static final String DEFAULT_VENDORS = "mysql,oracle"; 064 private static final String VENDORS_KEY = MetaInfUtils.PROPERTY_PREFIX + ".db.vendors"; 065 066 // All paths must have the hardcoded separator to be consistent for deployment 067 private static final String PATH_SEPARATOR = "/"; 068 069 private static final String INITIAL_SQL_PATH = "initial-sql" + PATH_SEPARATOR + "2.3.0"; 070 private static final String UPGRADE_SQL_PATH = "upgrades" + PATH_SEPARATOR + "*"; 071 private static final String SCHEMA_SQL_PATH = "rice-" + MetaInfGroup.SCHEMA.name().toLowerCase() + ".sql"; 072 private static final String CONSTRAINTS_SQL_PATH = "rice-" + MetaInfGroup.CONSTRAINTS.name().toLowerCase() + ".sql"; 073 private static final String ALL_SQL_PATH = "*.sql"; 074 075 /** 076 * The Spring environment. 077 */ 078 @Autowired 079 EnvironmentService env; 080 081 /** 082 * The Rice Maven project. 083 */ 084 @Autowired 085 Project project; 086 087 /** 088 * The build information. 089 */ 090 @Autowired 091 Build build; 092 093 /** 094 * {@inheritDoc} 095 * 096 * <p> 097 * All of the initial data (the data included in the {@code MetaInfGroup.SCHEMA}, {@code MetaInfGroup.CONSTRAINTS}, 098 * or {@code MetaInfGroup.DATA} groups) needs to be added before the update data (the data included in the 099 * {@code MetaInfGroup.OTHER} group). 100 * </p> 101 */ 102 @Override 103 @Bean 104 public List<MetaInfContext> metaInfContexts() { 105 List<MetaInfContext> metaInfContexts = Lists.newArrayList(); 106 107 List<MetaInfDataType> types = Lists.newArrayList(MetaInfDataType.BOOTSTRAP, MetaInfDataType.DEMO, MetaInfDataType.TEST); 108 List<String> vendors = SpringUtils.getNoneSensitiveListFromCSV(env, VENDORS_KEY, DEFAULT_VENDORS); 109 List<MetaInfGroup> groups = Lists.newArrayList(MetaInfGroup.SCHEMA, MetaInfGroup.DATA, MetaInfGroup.CONSTRAINTS); 110 111 for (MetaInfDataType type : types) { 112 for (MetaInfDataLocation location : MetaInfDataLocation.values()) { 113 for (String vendor : vendors) { 114 for (MetaInfGroup group : groups) { 115 List<MetaInfContext> contexts = getMetaInfContexts(group, INITIAL_SQL_PATH, vendor, 116 location, type); 117 metaInfContexts.addAll(contexts); 118 } 119 } 120 } 121 } 122 123 for (MetaInfDataType type : types) { 124 for (MetaInfDataLocation location : MetaInfDataLocation.values()) { 125 for (String vendor : vendors) { 126 List<MetaInfContext> contexts = getMetaInfContexts(MetaInfGroup.OTHER, UPGRADE_SQL_PATH, vendor, 127 location, type); 128 metaInfContexts.addAll(contexts); 129 } 130 } 131 } 132 133 return ImmutableList.copyOf(metaInfContexts); 134 } 135 136 /** 137 * Creates a list of META-INF contexts for the given {@code group}, {@code qualifier}, {@code vendor}, 138 * {@code location}, and {@code type}. 139 * 140 * @param group the group of the data to create the context for 141 * @param qualifier the prefix to add to the initial resource path 142 * @param vendor the database vendor to create the context for 143 * @param location the location of the data to create the context for 144 * @param type the type of data to create the context for 145 * 146 * @return a list of META-INF contexts 147 */ 148 protected List<MetaInfContext> getMetaInfContexts(MetaInfGroup group, String qualifier, String vendor, MetaInfDataLocation location, MetaInfDataType type) { 149 List<MetaInfContext> metaInfContexts = Lists.newArrayList(); 150 151 File scanDir = build.getOutputDir(); 152 String encoding = build.getEncoding(); 153 154 Comparator<MetaInfResource> comparator = new MetaInfResourceLocationComparator(); 155 156 String includesKey = MetaInfConfigUtils.getIncludesKey(group, PREFIX) + "." + vendor; 157 String excludesKey = MetaInfConfigUtils.getExcludesKey(group, PREFIX) + "." + vendor; 158 159 Boolean relativePaths = env.getBoolean(RELATIVE_KEY, DEFAULT_GENERATE_RELATIVE_PATHS); 160 161 List<String> pathQualifiers = MetaInfUtils.getQualifiers(scanDir, project, Lists.newArrayList(qualifier), Lists.<String> newArrayList()); 162 163 for (String pathQualifier : pathQualifiers) { 164 File outputFile = MetaInfUtils.getOutputFile(project, build, Optional.of(pathQualifier + PATH_SEPARATOR + vendor), 165 Optional.of(location), Optional.of(type), group.name().toLowerCase()); 166 167 Map<MetaInfGroup, String> defaultIncludes = getDefaultIncludes(pathQualifier, vendor, location, type); 168 Map<MetaInfGroup, String> defaultExcludes = getDefaultExcludes(defaultIncludes); 169 List<String> includes = SpringUtils.getNoneSensitiveListFromCSV(env, includesKey, defaultIncludes.get(group)); 170 List<String> excludes = SpringUtils.getNoneSensitiveListFromCSV(env, excludesKey, defaultExcludes.get(group)); 171 172 MetaInfContext context = MetaInfContext.builder(outputFile, encoding, scanDir).comparator(comparator) 173 .includes(includes).excludes(excludes).relativePaths(relativePaths.booleanValue()).build(); 174 metaInfContexts.add(context); 175 } 176 177 return metaInfContexts; 178 } 179 180 /** 181 * Generates the default mapping of included paths from the given {@code qualifier}, {@code vendor}, and 182 * {@code type}. 183 * 184 * @param qualifier the prefix to add to the initial resource path 185 * @param vendor the database vendor to include 186 * @param location the location of the data to include 187 * @param type the type of data to include 188 * 189 * @return the map of included paths 190 */ 191 protected Map<MetaInfGroup, String> getDefaultIncludes(String qualifier, String vendor, MetaInfDataLocation location, MetaInfDataType type) { 192 Map<MetaInfGroup, String> defaultIncludes = Maps.newEnumMap(MetaInfGroup.class); 193 194 String resourcePath = ProjectUtils.getResourcePath(project.getGroupId(), project.getArtifactId()); 195 List<String> paths = Lists.newArrayList(resourcePath, qualifier, vendor, location.name().toLowerCase(), type.name().toLowerCase()); 196 String value = StringUtils.join(paths, PATH_SEPARATOR); 197 198 defaultIncludes.put(MetaInfGroup.SCHEMA, value + PATH_SEPARATOR + SCHEMA_SQL_PATH); 199 defaultIncludes.put(MetaInfGroup.DATA, value + PATH_SEPARATOR + ALL_SQL_PATH); 200 defaultIncludes.put(MetaInfGroup.CONSTRAINTS, value + PATH_SEPARATOR + CONSTRAINTS_SQL_PATH); 201 defaultIncludes.put(MetaInfGroup.OTHER, value + PATH_SEPARATOR + ALL_SQL_PATH); 202 203 return defaultIncludes; 204 } 205 206 /** 207 * Generates the default mapping of excluded paths from the {@code defaultIncludes} map. 208 * 209 * <p> 210 * Generally, nothing is excluded, but there is a special case with {@code MetaInfGroup.DATA} where it does not 211 * include either the {@code MetaInfGroup.SCHEMA} or {@code MetaInfGroup.CONSTRAINTS}. 212 * </p> 213 * 214 * @param defaultIncludes the map of included paths 215 * 216 * @return the map of excluded paths 217 */ 218 protected Map<MetaInfGroup, String> getDefaultExcludes(Map<MetaInfGroup, String> defaultIncludes) { 219 Map<MetaInfGroup, String> defaultExcludes = Maps.newEnumMap(MetaInfGroup.class); 220 221 List<String> dataExcludes = Lists.newArrayList(defaultIncludes.get(MetaInfGroup.SCHEMA), defaultIncludes.get(MetaInfGroup.CONSTRAINTS)); 222 223 defaultExcludes.put(MetaInfGroup.SCHEMA, NullUtils.NONE); 224 defaultExcludes.put(MetaInfGroup.DATA, StringUtils.join(dataExcludes, ",")); 225 defaultExcludes.put(MetaInfGroup.CONSTRAINTS, NullUtils.NONE); 226 defaultExcludes.put(MetaInfGroup.OTHER, NullUtils.NONE); 227 228 return defaultExcludes; 229 } 230 231}