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.spring; 017 018import java.util.Collections; 019import java.util.List; 020 021import javax.sql.DataSource; 022 023import com.google.common.base.Optional; 024import com.google.common.collect.Lists; 025import org.kuali.common.jdbc.model.context.JdbcContext; 026import org.kuali.common.jdbc.reset.DefaultJdbcResetConfig; 027import org.kuali.common.jdbc.service.spring.DataSourceConfig; 028import org.kuali.common.jdbc.sql.spring.DbaContextConfig; 029import org.kuali.common.jdbc.sql.spring.JdbcContextsConfig; 030import org.kuali.common.jdbc.suppliers.ResourcesSupplierFactory; 031import org.kuali.common.jdbc.suppliers.SqlSupplier; 032import org.kuali.common.jdbc.suppliers.spring.SuppliersFactoryConfig; 033import org.kuali.common.jdbc.vendor.model.DatabaseVendor; 034import org.kuali.common.util.metainf.model.PathComparator; 035import org.kuali.common.util.metainf.service.MetaInfUtils; 036import org.kuali.common.util.metainf.spring.MetaInfDataLocation; 037import org.kuali.common.util.metainf.spring.MetaInfDataType; 038import org.kuali.common.util.metainf.spring.MetaInfGroup; 039import org.kuali.rice.db.config.profile.MetaInfDataLocationProfileConfig; 040import org.kuali.rice.db.config.profile.MetaInfDataTypeProfileConfig; 041import org.kuali.rice.db.config.profile.MetaInfFilterConfig; 042import org.kuali.rice.db.config.profile.RiceClientBootstrapConfig; 043import org.kuali.rice.db.config.profile.RiceClientDemoConfig; 044import org.kuali.rice.db.config.profile.RiceServerDemoConfig; 045import org.kuali.rice.db.config.profile.RiceServerDemoFilterConfig; 046import org.kuali.rice.db.config.profile.RiceMasterConfig; 047import org.kuali.rice.db.config.profile.RiceServerBootstrapConfig; 048import org.kuali.rice.sql.project.SqlProjectConstants; 049import org.springframework.beans.factory.annotation.Autowired; 050import org.springframework.context.annotation.Bean; 051import org.springframework.context.annotation.Configuration; 052import org.springframework.context.annotation.Import; 053 054import com.google.common.collect.ImmutableList; 055 056/** 057 * Used by developers (to reset their local db), CI (to validate changes), and by the deploy process to reset the 058 * database for instances of the running application. 059 * 060 * @author Kuali Rice Team (rice.collab@kuali.org) 061 */ 062@Configuration 063@Import({ DbaContextConfig.class, SuppliersFactoryConfig.class, DefaultJdbcResetConfig.class, 064 RiceClientBootstrapConfig.class, RiceClientDemoConfig.class, RiceServerBootstrapConfig.class, RiceServerDemoConfig.class, 065 RiceServerDemoFilterConfig.class, RiceMasterConfig.class }) 066public class SourceSqlConfig implements JdbcContextsConfig { 067 068 // All paths must have the hardcoded separator to be consistent for deployment 069 private static final String PATH_SEPARATOR = "/"; 070 071 private static final String INITIAL_SQL_PATH = "initial-sql" + PATH_SEPARATOR + "2.3.0"; 072 private static final String UPGRADE_SQL_PATH = "upgrades" + PATH_SEPARATOR + "*"; 073 074 /** 075 * The DBA context. 076 */ 077 @Autowired 078 DbaContextConfig dba; 079 080 /** 081 * The factory for creating SQL resources. 082 */ 083 @Autowired 084 ResourcesSupplierFactory factory; 085 086 /** 087 * The vendor of the database to run the SQL against. 088 */ 089 @Autowired 090 DatabaseVendor vendor; 091 092 /** 093 * The data source configuration. 094 */ 095 @Autowired 096 DataSourceConfig dataSources; 097 098 /** 099 * The {@link MetaInfDataLocation} profile. 100 */ 101 @Autowired(required = false) 102 MetaInfDataLocationProfileConfig locationConfig; 103 104 /** 105 * The {@link MetaInfDataType} profile. 106 */ 107 @Autowired(required = false) 108 MetaInfDataTypeProfileConfig typeConfig; 109 110 /** 111 * The data filtering profile. 112 */ 113 @Autowired(required = false) 114 MetaInfFilterConfig serverDemoFilterConfig; 115 116 /** 117 * {@inheritDoc} 118 * 119 * <p> 120 * All of the initial data (the data included in the {@code MetaInfGroup.SCHEMA}, {@code MetaInfGroup.CONSTRAINTS}, 121 * or {@code MetaInfGroup.DATA} groups) needs to be applied before the update data (the data included in the 122 * {@code MetaInfGroup.OTHER} group). 123 * </p> 124 */ 125 @Override 126 @Bean 127 public List<JdbcContext> jdbcContexts() { 128 List<JdbcContext> jdbcContexts = Lists.newArrayList(); 129 130 List<MetaInfDataType> types = getTypes(); 131 List<MetaInfDataLocation> locations = getLocations(); 132 List<MetaInfGroup> groups = Lists.newArrayList(MetaInfGroup.SCHEMA, MetaInfGroup.DATA, MetaInfGroup.CONSTRAINTS); 133 134 jdbcContexts.add(dba.dbaBeforeContext()); 135 136 for (MetaInfDataType type : types) { 137 for (MetaInfDataLocation location : locations) { 138 for (MetaInfGroup group : groups) { 139 jdbcContexts.add(getJdbcContext(group, INITIAL_SQL_PATH, vendor.getCode(), location, type, true)); 140 } 141 142 jdbcContexts.add(getJdbcContext(MetaInfGroup.OTHER, UPGRADE_SQL_PATH, vendor.getCode(), location, type, false)); 143 } 144 } 145 146 jdbcContexts.add(dba.dbaAfterContext()); 147 148 return ImmutableList.copyOf(jdbcContexts); 149 } 150 151 /** 152 * Returns the list of {@link MetaInfDataType}s to be applied to the database, returning an empty list if no 153 * profiles are active. 154 * 155 * @return the list of {@link MetaInfDataType}s to be applied to the database (if any) 156 */ 157 protected List<MetaInfDataType> getTypes() { 158 return typeConfig != null ? typeConfig.getMetaInfDataTypes() : Lists.<MetaInfDataType> newArrayList(); 159 } 160 161 /** 162 * Returns the list of {@link MetaInfDataLocation}s to be applied to the database, returning an empty list if no 163 * profiles are active. 164 * 165 * @return the list of {@link MetaInfDataLocation}s to be applied to the database (if any) 166 */ 167 protected List<MetaInfDataLocation> getLocations() { 168 return locationConfig != null ? locationConfig.getMetaInfDataLocations() : Lists.<MetaInfDataLocation> newArrayList(); 169 } 170 171 /** 172 * Creates the JDBC context for the given {@code group}, {@code location}, and {@code type}. 173 * 174 * @param group the group of the data to create the context for 175 * @param qualifier the prefix to add to the initial resource path 176 * @param vendor the database vendor to create the context for 177 * @param location the location of the data to create the context for 178 * @param type the type of data to create the context for 179 * @param multithreaded whether or not to run the context in multiple threads 180 * 181 * @return the JDBC context 182 */ 183 protected JdbcContext getJdbcContext(MetaInfGroup group, String qualifier, String vendor, MetaInfDataLocation location, MetaInfDataType type, boolean multithreaded) { 184 DataSource dataSource = dataSources.dataSource(); 185 186 List<SqlSupplier> suppliers = Lists.newArrayList(); 187 188 PathComparator comparator = new PathComparator(); 189 190 if (isIncluded(group, location, type) && !isExcluded(group, location, type)) { 191 List<String> resources = MetaInfUtils.getPatternedClasspathResources(SqlProjectConstants.ID, 192 Optional.of(qualifier + PATH_SEPARATOR + vendor), Optional.of(location), Optional.of(type), group.name().toLowerCase()); 193 Collections.sort(resources, comparator); 194 suppliers.addAll(factory.getSuppliers(resources)); 195 } 196 197 String message = "[" + group.name().toLowerCase() + ":" + (multithreaded ? "concurrent" : "sequential") + "]"; 198 199 return new JdbcContext.Builder(dataSource, suppliers).message(message).multithreaded(multithreaded).build(); 200 } 201 202 /** 203 * Returns whether to include the data for the {@link MetaInfGroup}, {@link MetaInfDataLocation}, and 204 * {@link MetaInfDataType}. 205 * 206 * @param group the {link MetaInfGroup} to check 207 * @param location the {@link MetaInfDataLocation} to check 208 * @param type the {@link MetaInfDataType} to check 209 * 210 * @return true if the data set should be included, false otherwise 211 */ 212 protected boolean isIncluded(MetaInfGroup group, MetaInfDataLocation location, MetaInfDataType type) { 213 return serverDemoFilterConfig == null || serverDemoFilterConfig.isIncluded(group, location, type); 214 } 215 216 /** 217 * Returns whether to exclude the data for the {@link MetaInfGroup}, {@link MetaInfDataLocation}, and 218 * {@link MetaInfDataType}. 219 * 220 * @param group the {link MetaInfGroup} to check 221 * @param location the {@link MetaInfDataLocation} to check 222 * @param type the {@link MetaInfDataType} to check 223 * 224 * @return true if the data set should be excluded, false otherwise 225 */ 226 protected boolean isExcluded(MetaInfGroup group, MetaInfDataLocation location, MetaInfDataType type) { 227 return serverDemoFilterConfig != null && serverDemoFilterConfig.isExcluded(group, location, type); 228 } 229 230}