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