/*
* 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.jackrabbit.core.config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import javax.naming.Context;
/**
* This class contains list of definitions for {@code DataSource} instances.
*/
public class DataSourceConfig {
public static final String DRIVER = "driver";
public static final String URL = "url";
public static final String USER = "user";
public static final String PASSWORD = "password";
public static final String DB_TYPE = "databaseType";
public static final String VALIDATION_QUERY = "validationQuery";
public static final String MAX_POOL_SIZE = "maxPoolSize";
private final List<DataSourceDefinition> defs = new ArrayList<DataSourceDefinition>();
/**
* Adds a DataSourceDefinition from the given properties.
*
* @param props the properties (key and values must be strings)
* @throws ConfigurationException on error
*/
public void addDataSourceDefinition(String name, Properties props) throws ConfigurationException {
DataSourceDefinition def = new DataSourceDefinition(name, props);
for (DataSourceDefinition existing : defs) {
if (existing.getLogicalName().equals(def.getLogicalName())) {
throw new ConfigurationException("Duplicate logicalName for a DataSource: "
+ def.getLogicalName());
}
}
defs.add(def);
}
/**
* @return the unmodifiable list of the current {@link DataSourceDefinition}s
*/
public List<DataSourceDefinition> getDefinitions() {
return Collections.unmodifiableList(defs);
}
/**
* The definition of a DataSource.
*/
public static final class DataSourceDefinition {
private static final List<String> allPropNames =
Arrays.asList(DRIVER, URL, USER, PASSWORD, DB_TYPE, VALIDATION_QUERY, MAX_POOL_SIZE);
private static final List<String> allJndiPropNames =
Arrays.asList(DRIVER, URL, USER, PASSWORD, DB_TYPE);
private final String logicalName;
private final String driver;
private final String url;
private final String user;
private final String password;
private final String dbType;
private final String validationQuery;
private final int maxPoolSize;
/**
* Creates a DataSourceDefinition from the given properties and
* throws a {@link ConfigurationException} when the set of properties does not
* satisfy some validity constraints.
*
* @param name the logical name of the data source
* @param props the properties (string keys and values)
* @throws ConfigurationException on error
*/
public DataSourceDefinition(String name, Properties props) throws ConfigurationException {
this.logicalName = name;
this.driver = (String) props.getProperty(DRIVER);
this.url = (String) props.getProperty(URL);
this.user = (String) props.getProperty(USER);
this.password = (String) props.getProperty(PASSWORD);
this.dbType = (String) props.getProperty(DB_TYPE);
this.validationQuery = (String) props.getProperty(VALIDATION_QUERY);
try {
this.maxPoolSize = Integer.parseInt((String) props.getProperty(MAX_POOL_SIZE, "-1"));
} catch (NumberFormatException e) {
throw new ConfigurationException("failed to parse " + MAX_POOL_SIZE
+ " property for DataSource " + logicalName);
}
verify(props);
}
private void verify(Properties props) throws ConfigurationException {
// Check required properties
if (logicalName == null || "".equals(logicalName.trim())) {
throw new ConfigurationException("DataSource logical name must not be null or empty");
}
if (driver == null || "".equals(driver)) {
throw new ConfigurationException("DataSource driver must not be null or empty");
}
if (url == null || "".equals(url)) {
throw new ConfigurationException("DataSource URL must not be null or empty");
}
if (dbType == null || "".equals(dbType)) {
throw new ConfigurationException("DataSource databaseType must not be null or empty");
}
// Check unknown properties
for (Object propName : props.keySet()) {
if (!allPropNames.contains((String) propName)) {
throw new ConfigurationException("Unknown DataSource property: " + propName);
}
}
// Check JNDI config:
if (isJndiConfig()) {
for (Object propName : props.keySet()) {
if (!allJndiPropNames.contains((String) propName)) {
throw new ConfigurationException("Property " + propName
+ " is not allowed for a DataSource obtained through JNDI"
+ ", DataSource logicalName = " + logicalName);
}
}
}
}
private boolean isJndiConfig() throws ConfigurationException {
Class<?> driverClass = null;
try {
if (driver.length() > 0) {
driverClass = Class.forName(driver);
}
} catch (ClassNotFoundException e) {
throw new ConfigurationException("Could not load JDBC driver class " + driver, e);
}
return driverClass != null && Context.class.isAssignableFrom(driverClass);
}
/**
* @return the logicalName
*/
public String getLogicalName() {
return logicalName;
}
/**
* @return the driver
*/
public String getDriver() {
return driver;
}
/**
* @return the url
*/
public String getUrl() {
return url;
}
/**
* @return the user
*/
public String getUser() {
return user;
}
/**
* @return the dbType
*/
public String getDbType() {
return dbType;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @return the validationQuery
*/
public String getValidationQuery() {
return validationQuery;
}
/**
* @return the maxPoolSize
*/
public int getMaxPoolSize() {
return maxPoolSize;
}
}
}