/*
* Copyright 2008 biaoping.yin
*
* Licensed 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" bboss persistent,
* 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 com.frameworkset.common.poolman.management;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
//import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.log4j.Logger;
import com.frameworkset.common.poolman.PoolManConstants;
import com.frameworkset.util.ValueObjectUtil;
import com.frameworkset.velocity.BBossVelocityUtil;
/**
* This service configures ObjectPools by first looking for 'poolman.xml' in the
* CLASSPATH. If it finds it, it parses the database entries and generic Class
* entries and creates MBeans and pools for them, adding each one to an
* appropriate PoolManager and the MBeanServer. If it cannot find this xml file,
* it looks for 'poolman.props' and loads those properties in order to create
* the pools (with no MBeans). If it cannot find poolman.props, it looks for the
* deprecated pool.props file and treats it as if it were named 'poolman.props'.
* If it cannot find any of these files, it throws an Exception.
*/
public class PoolManConfiguration implements Serializable {
private static Logger log = Logger.getLogger(PoolManConfiguration.class);
private String configFile;
private ConfigParser handler;
private ArrayList datasources;
private ArrayList genericObjects;
private boolean useJMX = PoolManConstants.DEFAULT_USE_JMX;
public static String jndi_principal = null;
public static String jndi_credentials = null;
private String[] filterdbname = null;
private String dbnamespace;
public static String pooltemplates;
/**
* 用户自定义的适配器
*/
public Map<String, String> adaptors = new HashMap<String, String>();
public PoolManConfiguration(String configFile, String dbname) {
// this.configFile = configFile;
// this.datasources = new ArrayList();
// this.genericObjects = new ArrayList();
// this.filterdbname = dbname;
this(configFile, null, dbname == null ? null : new String[] { dbname });
}
public PoolManConfiguration(String configFile, String dbnamespace,
String[] dbnames) {
this.configFile = configFile;
this.datasources = new ArrayList();
this.genericObjects = new ArrayList();
this.filterdbname = dbnames;
this.dbnamespace = dbnamespace;
}
public PoolManConfiguration(String configFile) {
this(configFile, null);
}
public boolean isUsingJMX() {
return handler.isManagementJMX();
}
/** Load DataSource info from XML and create a Service for each entry set. */
public void loadConfiguration(Map context) throws Exception {
// first try XML
try {
parseXML(context);
} catch (NullPointerException ne) {
ne.printStackTrace();
// then try deprecated properties
System.out.println("\n** ERROR: Unable to find XML file "
+ configFile + ": " + ne);
// don't try the props files anymore, it's been over a year
// System.out.println("** WARNING: Attempting to use deprecated properties files\n");
// this.datasources =
// parseProperties(PoolManConstants.PROPS_CONFIG_FILE);
} catch (Exception e) {
System.out.println("\n** ERROR: Unable to parse XML file "
+ configFile + ": " + e);
}
}
public ArrayList getDataSources() {
return this.datasources;
}
public ArrayList getGenericPools() {
return this.genericObjects;
}
public Properties getAdminProperties() {
return handler.getAdminProps();
}
private static Object lock = new Object();
private static void initpooltemplates() {
if (pooltemplates == null) {
synchronized (lock) {
if (pooltemplates == null) {
InputStream reader = null;
ByteArrayOutputStream swriter = null;
OutputStream temp = null;
try {
reader = ValueObjectUtil
.getInputStreamFromFile(PoolManConstants.XML_CONFIG_FILE_TEMPLATE);
swriter = new ByteArrayOutputStream();
temp = new BufferedOutputStream(swriter);
int len = 0;
byte[] buffer = new byte[1024];
while ((len = reader.read(buffer)) > 0) {
temp.write(buffer, 0, len);
}
temp.flush();
pooltemplates = swriter.toString("UTF-8");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (reader != null)
try {
reader.close();
} catch (IOException e) {
}
if (swriter != null)
try {
swriter.close();
} catch (IOException e) {
}
if (temp != null)
try {
temp.close();
} catch (IOException e) {
}
}
// pooltemplates =
// ValueObjectUtil.getFileContent(PoolManConstants.XML_CONFIG_FILE_TEMPLATE,"UTF-8");
}
}
}
}
private void parseXML(Map context) throws Exception {
/* CHANGED TO USE JAXP */
if (!this.configFile.equals(PoolManConstants.XML_CONFIG_FILE_TEMPLATE)) {
URL confURL = PoolManConfiguration.class.getClassLoader()
.getResource(configFile);
if (confURL == null)
PoolManConfiguration.class.getClassLoader().getResource(
"/" + configFile);
if (confURL == null)
getTCL().getResource(configFile);
if (confURL == null)
getTCL().getResource("/" + configFile);
if (confURL == null)
confURL = ClassLoader.getSystemResource(configFile);
if (confURL == null)
confURL = ClassLoader.getSystemResource("/" + configFile);
String url = "";
if (confURL == null) {
url = System.getProperty("user.dir");
url += "/" + configFile;
log.debug("Pool Config file:" + System.getProperty("user.dir")
+ "/" + configFile);
} else
url = confURL.toString();
this.handler = new ConfigParser(url, this.dbnamespace,
this.filterdbname);
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(false);
factory.setValidating(false);
SAXParser parser = factory.newSAXParser();
parser.parse(url, handler);
this.adaptors = handler.getAdaptors();
this.datasources = handler.getDataSourceProperties();
this.genericObjects = handler.getGenericProperties();
} else {
initpooltemplates();
String poolconfig = BBossVelocityUtil.evaluate(context, "",
pooltemplates);
InputStream in = null;
ByteArrayInputStream sr = null;
try {
this.handler = new ConfigParser(
PoolManConstants.XML_CONFIG_FILE_TEMPLATE,
this.dbnamespace, this.filterdbname);
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(false);
factory.setValidating(false);
SAXParser parser = factory.newSAXParser();
sr = new ByteArrayInputStream(poolconfig.getBytes());
in = new java.io.BufferedInputStream(sr);
parser.parse(in, handler);
this.adaptors = handler.getAdaptors();
this.datasources = handler.getDataSourceProperties();
this.genericObjects = handler.getGenericProperties();
} finally {
if (sr != null) {
try {
sr.close();
} catch (Exception e2) {
}
}
if (in != null) {
try {
in.close();
} catch (Exception e2) {
}
}
}
}
}
private static ClassLoader getTCL() throws IllegalAccessException,
InvocationTargetException {
Method method = null;
try {
method = (java.lang.Thread.class).getMethod(
"getContextClassLoader", null);
} catch (NoSuchMethodException e) {
return null;
}
return (ClassLoader) method.invoke(Thread.currentThread(), null);
}
private ArrayList parseProperties(String propsfilename) throws Exception {
// backwards compatibility is a b****
HashMap datasources = new HashMap();
this.getClass().getClassLoader().getParent().getSystemClassLoader()
.getResource(null);
InputStream is = null;
Properties p = null;
try {
is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream(propsfilename);
p = new Properties();
p.load(is);
} catch (Exception e) {
if (propsfilename.equals(PoolManConstants.PROPS_CONFIG_FILE)) {
try {
is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream(
PoolManConstants.OLDPROPS_CONFIG_FILE);
p = new Properties();
p.load(is);
} catch (Exception e2) {
throw new Exception(
"Unable to find and read a valid poolman.xml config file. "
+ "Please ensure that '"
+ PoolManConstants.XML_CONFIG_FILE
+ "' is in a directory that is in your CLASSPATH.\n");
}
System.out
.println("\nPLEASE NOTE: You should replace the pool.props file with a valid poolman.xml file\n");
} else {
throw new Exception(
"ERROR: Unable to find and read a valid PoolMan properties file.\n"
+ "Please ensure that "
+ PoolManConstants.XML_CONFIG_FILE
+ " or at least "
+ propsfilename
+ " is in a directory that is in your CLASSPATH.\n");
}
}
// now have props with each set of datasource entries delimited by a
// number
// split those into an ArrayList of Properties objects
Properties theseProps = null;
String entrySetNumber = null;
for (Enumeration enum_ = p.keys(); enum_.hasMoreElements();) {
String key = (String) enum_.nextElement();
// get rid of the "_"
String adjustedKey = key;
if (key.indexOf("_") != -1) {
StringBuffer sb = new StringBuffer(key.substring(0, key
.indexOf("_")));
sb.append(key.substring(key.indexOf("_") + 1, key.length()));
adjustedKey = sb.toString();
if ((!adjustedKey.toLowerCase().equals("dbname"))
&& (adjustedKey.startsWith("db"))) {
adjustedKey = adjustedKey
.substring(2, adjustedKey.length());
}
}
if (adjustedKey.toLowerCase().startsWith("cacherefresh")) {
adjustedKey = "cacherefreshinterval"
+ adjustedKey.substring(12, adjustedKey.length());
}
try {
entrySetNumber = key.substring(key.indexOf('.') + 1, key
.length());
} catch (StringIndexOutOfBoundsException sbe) {
throw new Exception("Unnumbered property in poolman.props: "
+ key);
}
if (datasources.containsKey(entrySetNumber))
theseProps = (Properties) datasources.get(entrySetNumber);
else
theseProps = new Properties();
theseProps.setProperty(adjustedKey.substring(0, adjustedKey
.indexOf('.')), p.getProperty(key));
datasources.put(entrySetNumber, theseProps);
}
ArrayList finalDataSourceList = new ArrayList();
for (Iterator iter = datasources.keySet().iterator(); iter.hasNext();) {
Properties testp = (Properties) datasources.get(iter.next());
finalDataSourceList.add(testp);
}
return finalDataSourceList;
}
/**
* @return the adaptors
*/
public Map<String, String> getAdaptors() {
return adaptors;
}
/**
* @param adaptors
* the adaptors to set
*/
public void setAdaptors(Map<String, String> adaptors) {
this.adaptors = adaptors;
}
}