1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package edu.internet2.middleware.shibboleth.common.config.attribute.resolver.dataConnector;
18
19 import java.beans.PropertyVetoException;
20 import java.util.Hashtable;
21 import java.util.List;
22 import java.util.Map;
23
24 import javax.naming.InitialContext;
25 import javax.naming.NamingException;
26 import javax.sql.DataSource;
27 import javax.xml.namespace.QName;
28
29 import org.opensaml.xml.util.DatatypeHelper;
30 import org.opensaml.xml.util.XMLHelper;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import org.springframework.beans.factory.BeanCreationException;
34 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
35 import org.springframework.beans.factory.xml.ParserContext;
36 import org.w3c.dom.Element;
37
38 import com.mchange.v2.c3p0.ComboPooledDataSource;
39
40 import edu.internet2.middleware.shibboleth.common.config.SpringConfigurationUtils;
41
42
43
44
45 public class StoredIDDataConnectorBeanDefinitionParser extends BaseDataConnectorBeanDefinitionParser {
46
47
48 public static final QName TYPE_NAME = new QName(DataConnectorNamespaceHandler.NAMESPACE, "StoredId");
49
50
51 private final Logger log = LoggerFactory.getLogger(StoredIDDataConnectorBeanDefinitionParser.class);
52
53
54 protected Class getBeanClass(Element element) {
55 return StoredIDDataConnectorBeanFactory.class;
56 }
57
58
59 protected void doParse(String pluginId, Element pluginConfig, Map<QName, List<Element>> pluginConfigChildren,
60 BeanDefinitionBuilder pluginBuilder, ParserContext parserContext) {
61 super.doParse(pluginId, pluginConfig, pluginConfigChildren, pluginBuilder, parserContext);
62
63 processConnectionManagement(pluginId, pluginConfig, pluginConfigChildren, pluginBuilder, parserContext);
64
65 long queryTimeout = 5 * 1000;
66 if (pluginConfig.hasAttributeNS(null, "queryTimeout")) {
67 queryTimeout = SpringConfigurationUtils.parseDurationToMillis(
68 "queryTimeout on relational database connector " + pluginId, pluginConfig.getAttributeNS(null,
69 "queryTimeout"), 0);
70 }
71 log.debug("Data connector {} SQL query timeout: {}ms", queryTimeout);
72 pluginBuilder.addPropertyValue("queryTimeout", queryTimeout);
73
74 String generatedAttributeId = "storedId";
75 if (pluginConfig.hasAttributeNS(null, "generatedAttributeID")) {
76 generatedAttributeId = DatatypeHelper.safeTrimOrNullString(pluginConfig.getAttributeNS(null,
77 "generatedAttributeID"));
78 }
79 pluginBuilder.addPropertyValue("generatedAttribute", generatedAttributeId);
80 log.debug("Data connector {} generated attribute ID: {}", pluginId, generatedAttributeId);
81
82 String sourceAttribute = DatatypeHelper.safeTrimOrNullString(pluginConfig.getAttributeNS(null,
83 "sourceAttributeID"));
84 log.debug("Data connector {} source attribute ID: {}", pluginId, sourceAttribute);
85 pluginBuilder.addPropertyValue("sourceAttribute", sourceAttribute);
86
87 String salt = DatatypeHelper.safeTrimOrNullString(pluginConfig.getAttributeNS(null, "salt"));
88 log.debug("Data connector {} salt: {}", pluginId, salt);
89 pluginBuilder.addPropertyValue("salt", salt.getBytes());
90 }
91
92
93
94
95
96
97
98
99
100
101 protected void processConnectionManagement(String pluginId, Element pluginConfig,
102 Map<QName, List<Element>> pluginConfigChildren, BeanDefinitionBuilder pluginBuilder,
103 ParserContext parserContext) {
104 DataSource datasource;
105
106 List<Element> cmc = pluginConfigChildren.get(new QName(DataConnectorNamespaceHandler.NAMESPACE,
107 "ContainerManagedConnection"));
108 if (cmc != null && cmc.get(0) != null) {
109 datasource = buildContainerManagedConnection(pluginId, cmc.get(0));
110 } else {
111 datasource = buildApplicationManagedConnection(pluginId, pluginConfigChildren.get(
112 new QName(DataConnectorNamespaceHandler.NAMESPACE, "ApplicationManagedConnection")).get(0));
113 }
114
115 pluginBuilder.addPropertyValue("datasource", datasource);
116 }
117
118
119
120
121
122
123
124
125
126 protected DataSource buildContainerManagedConnection(String pluginId, Element cmc) {
127 String jndiResource = cmc.getAttributeNS(null, "resourceName");
128 jndiResource = DatatypeHelper.safeTrim(jndiResource);
129
130 Hashtable<String, String> initCtxProps = buildProperties(XMLHelper.getChildElementsByTagNameNS(cmc,
131 DataConnectorNamespaceHandler.NAMESPACE, "JNDIConnectionProperty"));
132 try {
133 InitialContext initCtx = new InitialContext(initCtxProps);
134 DataSource dataSource = (DataSource) initCtx.lookup(jndiResource);
135 if (dataSource == null) {
136 log.error("DataSource " + jndiResource + " did not exist in JNDI directory");
137 throw new BeanCreationException("DataSource " + jndiResource + " did not exist in JNDI directory");
138 }
139 if (log.isDebugEnabled()) {
140 log.debug("Retrieved data source for data connector {} from JNDI location {} using properties ",
141 pluginId, initCtxProps);
142 }
143 return dataSource;
144 } catch (NamingException e) {
145 log.error("Unable to retrieve data source for data connector " + pluginId + " from JNDI location "
146 + jndiResource + " using properties " + initCtxProps, e);
147 return null;
148 }
149 }
150
151
152
153
154
155
156
157
158
159 protected DataSource buildApplicationManagedConnection(String pluginId, Element amc) {
160 ComboPooledDataSource datasource = new ComboPooledDataSource();
161
162 String driverClass = DatatypeHelper.safeTrim(amc.getAttributeNS(null, "jdbcDriver"));
163 ClassLoader classLoader = this.getClass().getClassLoader();
164 try {
165 classLoader.loadClass(driverClass);
166 } catch (ClassNotFoundException e) {
167 log.error("Unable to create relational database connector, JDBC driver can not be found on the classpath");
168 throw new BeanCreationException(
169 "Unable to create relational database connector, JDBC driver can not be found on the classpath");
170 }
171
172 try {
173 datasource.setDriverClass(driverClass);
174 datasource.setJdbcUrl(DatatypeHelper.safeTrim(amc.getAttributeNS(null, "jdbcURL")));
175 datasource.setUser(DatatypeHelper.safeTrim(amc.getAttributeNS(null, "jdbcUserName")));
176 datasource.setPassword(DatatypeHelper.safeTrim(amc.getAttributeNS(null, "jdbcPassword")));
177
178 if (amc.hasAttributeNS(null, "poolAcquireIncrement")) {
179 datasource.setAcquireIncrement(Integer.parseInt(DatatypeHelper.safeTrim(amc.getAttributeNS(null,
180 "poolAcquireIncrement"))));
181 } else {
182 datasource.setAcquireIncrement(3);
183 }
184
185 if (amc.hasAttributeNS(null, "poolAcquireRetryAttempts")) {
186 datasource.setAcquireRetryAttempts(Integer.parseInt(DatatypeHelper.safeTrim(amc.getAttributeNS(null,
187 "poolAcquireRetryAttempts"))));
188 } else {
189 datasource.setAcquireRetryAttempts(36);
190 }
191
192 if (amc.hasAttributeNS(null, "poolAcquireRetryDelay")) {
193 datasource.setAcquireRetryDelay(Integer.parseInt(DatatypeHelper.safeTrim(amc.getAttributeNS(null,
194 "poolAcquireRetryDelay"))));
195 } else {
196 datasource.setAcquireRetryDelay(5000);
197 }
198
199 if (amc.hasAttributeNS(null, "poolBreakAfterAcquireFailure")) {
200 datasource.setBreakAfterAcquireFailure(XMLHelper.getAttributeValueAsBoolean(amc.getAttributeNodeNS(
201 null, "poolBreakAfterAcquireFailure")));
202 } else {
203 datasource.setBreakAfterAcquireFailure(true);
204 }
205
206 if (amc.hasAttributeNS(null, "poolMinSize")) {
207 datasource.setMinPoolSize(Integer.parseInt(DatatypeHelper.safeTrim(amc.getAttributeNS(null,
208 "poolMinSize"))));
209 } else {
210 datasource.setMinPoolSize(2);
211 }
212
213 if (amc.hasAttributeNS(null, "poolMaxSize")) {
214 datasource.setMaxPoolSize(Integer.parseInt(DatatypeHelper.safeTrim(amc.getAttributeNS(null,
215 "poolMaxSize"))));
216 } else {
217 datasource.setMaxPoolSize(50);
218 }
219
220 if (amc.hasAttributeNS(null, "poolMaxIdleTime")) {
221 datasource.setMaxIdleTime(Integer.parseInt(DatatypeHelper.safeTrim(amc.getAttributeNS(null,
222 "poolMaxIdleTime"))));
223 } else {
224 datasource.setMaxIdleTime(600);
225 }
226
227 if (amc.hasAttributeNS(null, "poolIdleTestPeriod")) {
228 datasource.setIdleConnectionTestPeriod(Integer.parseInt(DatatypeHelper.safeTrim(amc.getAttributeNS(
229 null, "poolIdleTestPeriod"))));
230 } else {
231 datasource.setIdleConnectionTestPeriod(180);
232 }
233
234 datasource.setMaxStatementsPerConnection(10);
235
236 log.debug("Created application managed data source for data connector {}", pluginId);
237 return datasource;
238 } catch (PropertyVetoException e) {
239 log.error("Unable to create data source for data connector {} with JDBC driver class {}", pluginId,
240 driverClass);
241 return null;
242 }
243 }
244
245
246
247
248
249
250
251
252 protected Hashtable<String, String> buildProperties(List<Element> propertyElements) {
253 if (propertyElements == null || propertyElements.size() < 1) {
254 return null;
255 }
256
257 Hashtable<String, String> properties = new Hashtable<String, String>();
258
259 String propName;
260 String propValue;
261 for (Element propertyElement : propertyElements) {
262 propName = DatatypeHelper.safeTrim(propertyElement.getAttributeNS(null, "name"));
263 propValue = DatatypeHelper.safeTrim(propertyElement.getAttributeNS(null, "value"));
264 properties.put(propName, propValue);
265 }
266
267 return properties;
268 }
269 }