/*****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
****************************************************************/
package org.apache.cayenne.project.upgrade.v6;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.cayenne.ConfigurationException;
import org.apache.cayenne.configuration.PasswordEncoding;
import org.apache.cayenne.configuration.SAXNestedTagHandler;
import org.apache.cayenne.conn.DataSourceInfo;
import org.apache.cayenne.resource.Resource;
import org.apache.cayenne.util.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
/**
* @since 3.1
*/
class XMLDataSourceInfoLoader_V3_0_0_1 {
private static Logger logger = LoggerFactory.getLogger(XMLDataSourceInfoLoader_V3_0_0_1.class);
private static String passwordFromURL(URL url) {
InputStream inputStream = null;
String password = null;
try {
inputStream = url.openStream();
password = passwordFromInputStream(inputStream);
}
catch (IOException exception) {
// Log the error while trying to open the stream. A null
// password will be returned as a result.
logger.warn(exception.getMessage(), exception);
}
return password;
}
private static String passwordFromInputStream(InputStream inputStream) {
BufferedReader bufferedReader = null;
String password = null;
try {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
password = bufferedReader.readLine();
}
catch (IOException exception) {
logger.warn(exception.getMessage(), exception);
}
finally {
try {
if (bufferedReader != null) {
bufferedReader.close();
}
}
catch (Exception exception) {
}
try {
inputStream.close();
}
catch (IOException exception) {
}
}
return password;
}
DataSourceInfo load(Resource configurationSource) {
if (configurationSource == null) {
throw new NullPointerException("Null configurationSource");
}
URL configurationURL = configurationSource.getURL();
DataSourceInfo dataSourceInfo = new DataSourceInfo();
InputStream in = null;
try {
in = configurationURL.openStream();
XMLReader parser = Util.createXmlReader();
DriverHandler rootHandler = new DriverHandler(parser, dataSourceInfo);
parser.setContentHandler(rootHandler);
parser.setErrorHandler(rootHandler);
parser.parse(new InputSource(in));
}
catch (Exception e) {
throw new ConfigurationException(
"Error loading configuration from %s",
e,
configurationURL);
}
finally {
try {
if (in != null) {
in.close();
}
}
catch (IOException ioex) {
logger.info("failure closing input stream for "
+ configurationURL
+ ", ignoring", ioex);
}
}
return dataSourceInfo;
}
final class DriverHandler extends SAXNestedTagHandler {
private DataSourceInfo dataSourceDescriptor;
DriverHandler(XMLReader parser, DataSourceInfo dataSourceDescriptor) {
super(parser, null);
this.dataSourceDescriptor = dataSourceDescriptor;
}
@Override
protected ContentHandler createChildTagHandler(
String namespaceURI,
String localName,
String name,
Attributes attributes) {
if (localName.equals("driver")) {
String className = attributes.getValue("", "class");
dataSourceDescriptor.setJdbcDriver(className);
return new DataSourceChildrenHandler(parser, this);
}
return super.createChildTagHandler(namespaceURI, localName, name, attributes);
}
}
class DataSourceChildrenHandler extends SAXNestedTagHandler {
private DataSourceInfo dataSourceDescriptor;
DataSourceChildrenHandler(XMLReader parser, DriverHandler parentHandler) {
super(parser, parentHandler);
this.dataSourceDescriptor = parentHandler.dataSourceDescriptor;
}
@Override
protected ContentHandler createChildTagHandler(
String namespaceURI,
String localName,
String name,
Attributes attributes) {
if (localName.equals("login")) {
String encoderClass = attributes.getValue("encoderClass");
String encoderKey = attributes.getValue("encoderKey");
if (encoderKey == null) {
encoderKey = attributes.getValue("encoderSalt");
}
String password = attributes.getValue("password");
String passwordLocation = attributes.getValue("passwordLocation");
String passwordSource = attributes.getValue("passwordSource");
if (passwordSource == null) {
passwordSource = DataSourceInfo.PASSWORD_LOCATION_MODEL;
}
String username = attributes.getValue("userName");
dataSourceDescriptor.setPasswordEncoderClass(encoderClass);
dataSourceDescriptor.setPasswordEncoderKey(encoderKey);
dataSourceDescriptor.setPasswordLocation(passwordLocation);
dataSourceDescriptor.setPasswordSource(passwordSource);
dataSourceDescriptor.setUserName(username);
// Replace {} in passwordSource with encoderSalt -- useful for EXECUTABLE
// & URL options
if (encoderKey != null) {
passwordSource = passwordSource.replaceAll("\\{\\}", encoderKey);
}
PasswordEncoding passwordEncoder = dataSourceDescriptor
.getPasswordEncoder();
if (passwordLocation != null) {
if (passwordLocation
.equals(DataSourceInfo.PASSWORD_LOCATION_CLASSPATH)) {
ClassLoader classLoader = Thread
.currentThread()
.getContextClassLoader();
URL url = classLoader.getResource(username);
if (url != null) {
password = passwordFromURL(url);
}
else {
logger.error("Could not find resource in CLASSPATH: "
+ passwordSource);
}
}
else if (passwordLocation
.equals(DataSourceInfo.PASSWORD_LOCATION_URL)) {
try {
password = passwordFromURL(new URL(passwordSource));
}
catch (MalformedURLException exception) {
logger.warn(exception.getMessage(), exception);
}
}
else if (passwordLocation
.equals(DataSourceInfo.PASSWORD_LOCATION_EXECUTABLE)) {
if (passwordSource != null) {
try {
Process process = Runtime.getRuntime().exec(
passwordSource);
password = passwordFromInputStream(process
.getInputStream());
process.waitFor();
}
catch (IOException exception) {
logger.warn(exception.getMessage(), exception);
}
catch (InterruptedException exception) {
logger.warn(exception.getMessage(), exception);
}
}
}
}
if (password != null && passwordEncoder != null) {
dataSourceDescriptor.setPassword(passwordEncoder.decodePassword(
password,
encoderKey));
}
}
else if (localName.equals("url")) {
dataSourceDescriptor.setDataSourceUrl(attributes.getValue("value"));
}
else if (localName.equals("connectionPool")) {
String min = attributes.getValue("min");
if (min != null) {
try {
dataSourceDescriptor.setMinConnections(Integer.parseInt(min));
}
catch (NumberFormatException nfex) {
logger.info("Non-numeric 'min' attribute", nfex);
throw new ConfigurationException(
"Non-numeric 'min' attribute '%s'",
nfex,
min);
}
}
String max = attributes.getValue("max");
if (max != null) {
try {
dataSourceDescriptor.setMaxConnections(Integer.parseInt(max));
}
catch (NumberFormatException nfex) {
logger.info("Non-numeric 'max' attribute", nfex);
throw new ConfigurationException(
"Non-numeric 'max' attribute '%s'",
nfex,
max);
}
}
}
return super.createChildTagHandler(namespaceURI, localName, name, attributes);
}
}
}