package org.opensource.clearpool.configuration; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.sql.Driver; import java.sql.SQLException; import java.util.Properties; import java.util.regex.Pattern; import javax.sql.CommonDataSource; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.opensource.clearpool.datasource.JDBCDataSource; import org.opensource.clearpool.exception.ConnectionPoolException; import org.opensource.clearpool.exception.ConnectionPoolXMLParseException; import org.opensource.clearpool.logging.PoolLogger; import org.opensource.clearpool.logging.PoolLoggerFactory; import org.opensource.clearpool.security.Secret; import org.opensource.clearpool.security.SecretAES; import org.opensource.clearpool.util.JdbcUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * This class used to parse JDBC. * * @author xionghui * @date 16.08.2014 * @version 1.0 */ public class JDBCConfiguration { private static final PoolLogger LOGGER = PoolLoggerFactory.getLogger(JDBCConfiguration.class); private final static String CLASS = "class"; private final static String URL = "url"; private final static String USER = "user"; private final static String PASSWORD = "password"; private final static String SECURITY_CLASS = "security-class"; private final static String FILE_PATH = "file-path"; private final static String STATUS = "status"; private final static String ENCRYPT = "encrypt"; private final static String DECRYPT = "decrypt"; public static CommonDataSource parse(Element element, Document document, String path) { String clazz = null; String url = null; String user = null; String password = null; String securityClass = null; String filePath = null; NodeList children = element.getChildNodes(); for (int i = 0, size = children.getLength(); i < size; i++) { Node childNode = children.item(i); if (childNode instanceof Element) { Element child = (Element) childNode; String nodeName = child.getNodeName(); String nodeValue = child.getTextContent(); if (CLASS.equals(nodeName)) { clazz = nodeValue.trim(); } else if (URL.equals(nodeName)) { url = nodeValue.trim(); } else if (USER.equals(nodeName)) { user = nodeValue; checkUserPattern(user); } else if (PASSWORD.equals(nodeName)) { password = nodeValue; } else if (SECURITY_CLASS.equals(nodeName)) { securityClass = nodeValue.trim(); } else if (FILE_PATH.equals(nodeName)) { filePath = nodeValue.trim(); } else if (STATUS.equals(nodeName)) { String status = nodeValue.trim(); password = handlerPassword(securityClass, filePath, status, password, child, document); } } } return getDataSource(clazz, url, user, password); } /** * Check if the pattern of user is valid. */ private static void checkUserPattern(String value) { // note:the regex has a blank String regex = "[\\w" + " " + "]*"; boolean right = Pattern.matches(regex, value); if (!right) { throw new ConnectionPoolXMLParseException(value + " of " + USER + " is illegal"); } } /** * Get dataSource by JDBC. */ public static CommonDataSource getDataSource(String clazz, String url, String user, String password) { if (url == null) { throw new ConnectionPoolException(JDBCConfiguration.URL + " is null"); } Driver driver; try { if (clazz == null) { clazz = JdbcUtil.getDriverClassName(url); } driver = JdbcUtil.createDriver(clazz); } catch (SQLException e) { LOGGER.error("getDataSource error: ", e); throw new ConnectionPoolException(e); } Properties connectProperties = new Properties(); if (user != null) { connectProperties.put("user", user); } if (password != null) { connectProperties.put("password", password); } return new JDBCDataSource(clazz, url, driver, connectProperties); } /** * Handle the password */ private static String handlerPassword(String securityClass, String filePath, String status, String password, Element element, Document document) { if (password == null) { throw new ConnectionPoolException(PASSWORD + " shouldn't be null when we are using STATUS"); } try { Secret handler; if (securityClass == null) { handler = new SecretAES(); } else { Class<?> clzz = Class.forName(securityClass); handler = (Secret) clzz.newInstance(); } if (ENCRYPT.equals(status)) { String cipher = handler.encrypt(password); element.setTextContent(DECRYPT); Element parent = (Element) element.getParentNode(); Element pwdElem = (Element) parent.getElementsByTagName(PASSWORD).item(0); pwdElem.setTextContent(cipher); if (filePath == null) { throw new ConnectionPoolXMLParseException(FILE_PATH + " shouldn't be null"); } saveXML(document, filePath); } else { password = handler.decrypt(password); } } catch (Exception e) { LOGGER.error("handlerPassword error: ", e); throw new ConnectionPoolException(e.getMessage()); } return password; } /** * Save the configuration. * * @param document * @param filePath * @throws Exception */ private static void saveXML(Document document, String filePath) throws Exception { TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); String encoding = XMLConfiguration.getEncoding(); transformer.setOutputProperty(OutputKeys.ENCODING, encoding); Source domSource = new DOMSource(document); Writer writer = getResourceAsWriter(encoding, filePath); Result result = new StreamResult(writer); // save it transformer.transform(domSource, result); } /** * Get writer by path and {@link XMLConfiguration#encoding}. * * @param encoding * @param filePath * @return * @throws FileNotFoundException * @throws UnsupportedEncodingException */ private static Writer getResourceAsWriter(String encoding, String filePath) throws FileNotFoundException, UnsupportedEncodingException { OutputStream outStream = new FileOutputStream(filePath); Writer writer = new OutputStreamWriter(outStream, encoding); return writer; } }