View Javadoc
1   /**
2    * Copyright 2005-2016 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.sql.spring;
17  
18  import java.util.Collections;
19  import java.util.List;
20  
21  import javax.sql.DataSource;
22  
23  import com.google.common.base.Optional;
24  import com.google.common.collect.Lists;
25  import org.kuali.common.jdbc.model.context.JdbcContext;
26  import org.kuali.common.jdbc.reset.DefaultJdbcResetConfig;
27  import org.kuali.common.jdbc.service.spring.DataSourceConfig;
28  import org.kuali.common.jdbc.sql.spring.DbaContextConfig;
29  import org.kuali.common.jdbc.sql.spring.JdbcContextsConfig;
30  import org.kuali.common.jdbc.suppliers.ResourcesSupplierFactory;
31  import org.kuali.common.jdbc.suppliers.SqlSupplier;
32  import org.kuali.common.jdbc.suppliers.spring.SuppliersFactoryConfig;
33  import org.kuali.common.jdbc.vendor.model.DatabaseVendor;
34  import org.kuali.common.util.metainf.model.PathComparator;
35  import org.kuali.common.util.metainf.service.MetaInfUtils;
36  import org.kuali.common.util.metainf.spring.MetaInfDataLocation;
37  import org.kuali.common.util.metainf.spring.MetaInfDataType;
38  import org.kuali.common.util.metainf.spring.MetaInfGroup;
39  import org.kuali.rice.db.config.profile.MetaInfDataLocationProfileConfig;
40  import org.kuali.rice.db.config.profile.MetaInfDataTypeProfileConfig;
41  import org.kuali.rice.db.config.profile.MetaInfFilterConfig;
42  import org.kuali.rice.db.config.profile.RiceClientBootstrapConfig;
43  import org.kuali.rice.db.config.profile.RiceClientDemoConfig;
44  import org.kuali.rice.db.config.profile.RiceServerDemoConfig;
45  import org.kuali.rice.db.config.profile.RiceServerDemoFilterConfig;
46  import org.kuali.rice.db.config.profile.RiceMasterConfig;
47  import org.kuali.rice.db.config.profile.RiceServerBootstrapConfig;
48  import org.kuali.rice.sql.project.SqlProjectConstants;
49  import org.springframework.beans.factory.annotation.Autowired;
50  import org.springframework.context.annotation.Bean;
51  import org.springframework.context.annotation.Configuration;
52  import org.springframework.context.annotation.Import;
53  
54  import com.google.common.collect.ImmutableList;
55  
56  /**
57   * Used by developers (to reset their local db), CI (to validate changes), and by the deploy process to reset the
58   * database for instances of the running application.
59   *
60   * @author Kuali Rice Team (rice.collab@kuali.org)
61   */
62  @Configuration
63  @Import({ DbaContextConfig.class, SuppliersFactoryConfig.class, DefaultJdbcResetConfig.class,
64            RiceClientBootstrapConfig.class, RiceClientDemoConfig.class, RiceServerBootstrapConfig.class, RiceServerDemoConfig.class,
65            RiceServerDemoFilterConfig.class, RiceMasterConfig.class })
66  public class SourceSqlConfig implements JdbcContextsConfig {
67  
68      // All paths must have the hardcoded separator to be consistent for deployment
69      private static final String PATH_SEPARATOR = "/";
70  
71      private static final String INITIAL_SQL_PATH = "initial-sql" + PATH_SEPARATOR + "2.3.0";
72      private static final String UPGRADE_SQL_PATH = "upgrades" + PATH_SEPARATOR + "*";
73  
74      /**
75       * The DBA context.
76       */
77  	@Autowired
78  	DbaContextConfig dba;
79  
80      /**
81       * The factory for creating SQL resources.
82       */
83  	@Autowired
84  	ResourcesSupplierFactory factory;
85  
86      /**
87       * The vendor of the database to run the SQL against.
88       */
89  	@Autowired
90  	DatabaseVendor vendor;
91  
92      /**
93       * The data source configuration.
94       */
95  	@Autowired
96  	DataSourceConfig dataSources;
97  
98      /**
99       * 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 }