View Javadoc

1   /*
2    * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
3    *
4    * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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  
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  /**
41   * Spring bean definition parser for stored ID data connector.
42   */
43  public class StoredIDDataConnectorBeanDefinitionParser extends BaseDataConnectorBeanDefinitionParser {
44  
45      /** Schema type name. */
46      public static final QName TYPE_NAME = new QName(DataConnectorNamespaceHandler.NAMESPACE, "StoredId");
47  
48      /** Class logger. */
49      private final Logger log = LoggerFactory.getLogger(StoredIDDataConnectorBeanDefinitionParser.class);
50  
51      /** {@inheritDoc} */
52      protected Class getBeanClass(Element element) {
53          return StoredIDDataConnectorBeanFactory.class;
54      }
55  
56      /** {@inheritDoc} */
57      protected void doParse(String pluginId, Element pluginConfig, Map<QName, List<Element>> pluginConfigChildren,
58              BeanDefinitionBuilder pluginBuilder, ParserContext parserContext) {
59          super.doParse(pluginId, pluginConfig, pluginConfigChildren, pluginBuilder, parserContext);
60  
61          if (pluginConfig.hasAttributeNS(null, "generatedAttributeID")) {
62              pluginBuilder.addPropertyValue("generatedAttribute", pluginConfig.getAttributeNS(null,
63                      "generatedAttributeID"));
64          } else {
65              pluginBuilder.addPropertyValue("generatedAttribute", "storedId");
66          }
67          
68          pluginBuilder.addPropertyValue("sourceAttribute", pluginConfig.getAttributeNS(null, "sourceAttributeID"));
69          pluginBuilder.addPropertyValue("salt", pluginConfig.getAttributeNS(null, "salt").getBytes());
70          
71          DataSource connectionSource = processConnectionManagement(pluginId, pluginConfigChildren, pluginBuilder);
72          pluginBuilder.addPropertyValue("datasource", connectionSource);
73      }
74  
75      /**
76       * Processes the connection management configuration.
77       * 
78       * @param pluginId ID of this data connector
79       * @param pluginConfigChildren configuration elements for this connector
80       * @param pluginBuilder bean definition builder
81       * 
82       * @return data source built from configuration
83       */
84      protected DataSource processConnectionManagement(String pluginId, Map<QName, List<Element>> pluginConfigChildren,
85              BeanDefinitionBuilder pluginBuilder) {
86          List<Element> cmc = pluginConfigChildren.get(new QName(
87                  DataConnectorNamespaceHandler.NAMESPACE, "ContainerManagedConnection"));
88          if (cmc != null && cmc.get(0) != null) {
89              return buildContainerManagedConnection(pluginId, cmc.get(0));
90          } else {
91              return buildApplicationManagedConnection(pluginId, pluginConfigChildren.get(
92                      new QName(
93                              DataConnectorNamespaceHandler.NAMESPACE, "ApplicationManagedConnection")).get(0));
94          }
95      }
96  
97      /**
98       * Builds a JDBC {@link DataSource} from a ContainerManagedConnection configuration element.
99       * 
100      * @param pluginId ID of this data connector
101      * @param cmc the container managed configuration element
102      * 
103      * @return the built data source
104      */
105     protected DataSource buildContainerManagedConnection(String pluginId, Element cmc) {
106         String jndiResource = cmc.getAttributeNS(null, "resourceName");
107         jndiResource = DatatypeHelper.safeTrim(jndiResource);
108 
109         Hashtable<String, String> initCtxProps = buildProperties(XMLHelper.getChildElementsByTagNameNS(cmc,
110                 DataConnectorNamespaceHandler.NAMESPACE, "JNDIConnectionProperty"));
111         try {
112             InitialContext initCtx = new InitialContext(initCtxProps);
113             DataSource dataSource = (DataSource) initCtx.lookup(jndiResource);
114             if(dataSource == null){
115                 log.error("DataSource " + jndiResource + " did not exist in JNDI directory");
116                 throw new BeanCreationException("DataSource " + jndiResource + " did not exist in JNDI directory");
117             }
118             if (log.isDebugEnabled()) {
119                 log.debug("Retrieved data source for data connector {} from JNDI location {} using properties ",
120                         pluginId, initCtxProps);
121             }
122             return dataSource;
123         } catch (NamingException e) {
124             log.error("Unable to retrieve data source for data connector " + pluginId + " from JNDI location "
125                     + jndiResource + " using properties " + initCtxProps, e);
126             return null;
127         }
128     }
129 
130     /**
131      * Builds a JDBC {@link DataSource} from an ApplicationManagedConnection configuration element.
132      * 
133      * @param pluginId ID of this data connector
134      * @param amc the application managed configuration element
135      * 
136      * @return the built data source
137      */
138     protected DataSource buildApplicationManagedConnection(String pluginId, Element amc) {
139         ComboPooledDataSource datasource = new ComboPooledDataSource();
140 
141         String driverClass = DatatypeHelper.safeTrim(amc.getAttributeNS(null, "jdbcDriver"));
142         ClassLoader classLoader = this.getClass().getClassLoader();
143         try{
144             classLoader.loadClass(driverClass);
145         }catch(ClassNotFoundException e){
146             log.error("Unable to create relational database connector, JDBC driver can not be found on the classpath");
147             throw new BeanCreationException("Unable to create relational database connector, JDBC driver can not be found on the classpath");
148         }
149         
150         try {
151             datasource.setDriverClass(driverClass);
152             datasource.setJdbcUrl(DatatypeHelper.safeTrim(amc.getAttributeNS(null, "jdbcURL")));
153             datasource.setUser(DatatypeHelper.safeTrim(amc.getAttributeNS(null, "jdbcUserName")));
154             datasource.setPassword(DatatypeHelper.safeTrim(amc.getAttributeNS(null, "jdbcPassword")));
155 
156             if (amc.hasAttributeNS(null, "poolAcquireIncrement")) {
157                 datasource.setAcquireIncrement(Integer.parseInt(DatatypeHelper.safeTrim(amc.getAttributeNS(null,
158                         "poolAcquireIncrement"))));
159             } else {
160                 datasource.setAcquireIncrement(3);
161             }
162 
163             if (amc.hasAttributeNS(null, "poolAcquireRetryAttempts")) {
164                 datasource.setAcquireRetryAttempts(Integer.parseInt(DatatypeHelper.safeTrim(amc.getAttributeNS(null,
165                         "poolAcquireRetryAttempts"))));
166             } else {
167                 datasource.setAcquireRetryAttempts(36);
168             }
169 
170             if (amc.hasAttributeNS(null, "poolAcquireRetryDelay")) {
171                 datasource.setAcquireRetryDelay(Integer.parseInt(DatatypeHelper.safeTrim(amc.getAttributeNS(null,
172                         "poolAcquireRetryDelay"))));
173             } else {
174                 datasource.setAcquireRetryDelay(5000);
175             }
176 
177             if (amc.hasAttributeNS(null, "poolBreakAfterAcquireFailure")) {
178                 datasource.setBreakAfterAcquireFailure(XMLHelper.getAttributeValueAsBoolean(amc.getAttributeNodeNS(
179                         null, "poolBreakAfterAcquireFailure")));
180             } else {
181                 datasource.setBreakAfterAcquireFailure(true);
182             }
183 
184             if (amc.hasAttributeNS(null, "poolMinSize")) {
185                 datasource.setMinPoolSize(Integer.parseInt(DatatypeHelper.safeTrim(amc.getAttributeNS(null,
186                         "poolMinSize"))));
187             } else {
188                 datasource.setMinPoolSize(2);
189             }
190 
191             if (amc.hasAttributeNS(null, "poolMaxSize")) {
192                 datasource.setMaxPoolSize(Integer.parseInt(DatatypeHelper.safeTrim(amc.getAttributeNS(null,
193                         "poolMaxSize"))));
194             } else {
195                 datasource.setMaxPoolSize(50);
196             }
197 
198             if (amc.hasAttributeNS(null, "poolMaxIdleTime")) {
199                 datasource.setMaxIdleTime(Integer.parseInt(DatatypeHelper.safeTrim(amc.getAttributeNS(null,
200                         "poolMaxIdleTime"))));
201             } else {
202                 datasource.setMaxIdleTime(600);
203             }
204 
205             if (amc.hasAttributeNS(null, "poolIdleTestPeriod")) {
206                 datasource.setIdleConnectionTestPeriod(Integer.parseInt(DatatypeHelper.safeTrim(amc.getAttributeNS(
207                         null, "poolIdleTestPeriod"))));
208             } else {
209                 datasource.setIdleConnectionTestPeriod(180);
210             }
211 
212             log.debug("Created application managed data source for data connector {}", pluginId);
213             return datasource;
214         } catch (PropertyVetoException e) {
215             log.error("Unable to create data source for data connector {} with JDBC driver class {}", pluginId,
216                     driverClass);
217             return null;
218         }
219     }
220 
221     /**
222      * Builds a hash from PropertyType elements.
223      * 
224      * @param propertyElements properties elements
225      * 
226      * @return properties extracted from elements, key is the property name.
227      */
228     protected Hashtable<String, String> buildProperties(List<Element> propertyElements) {
229         if (propertyElements == null || propertyElements.size() < 1) {
230             return null;
231         }
232 
233         Hashtable<String, String> properties = new Hashtable<String, String>();
234 
235         String propName;
236         String propValue;
237         for (Element propertyElement : propertyElements) {
238             propName = DatatypeHelper.safeTrim(propertyElement.getAttributeNS(null, "name"));
239             propValue = DatatypeHelper.safeTrim(propertyElement.getAttributeNS(null, "value"));
240             properties.put(propName, propValue);
241         }
242 
243         return properties;
244     }
245 }