| /* |
| * Copyright (c) 2022 Contributors to the Eclipse Foundation. |
| * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0, which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * This Source Code may also be made available under the following Secondary |
| * Licenses when the conditions for such availability set forth in the |
| * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
| * version 2 with the GNU Classpath Exception, which is available at |
| * https://www.gnu.org/software/classpath/license.html. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
| */ |
| |
| package com.sun.gjc.common; |
| |
| import static com.sun.gjc.common.DataSourceSpec.CLASSNAME; |
| import static com.sun.gjc.common.DataSourceSpec.DATABASENAME; |
| import static com.sun.gjc.common.DataSourceSpec.DATASOURCENAME; |
| import static com.sun.gjc.common.DataSourceSpec.DELIMITER; |
| import static com.sun.gjc.common.DataSourceSpec.DESCRIPTION; |
| import static com.sun.gjc.common.DataSourceSpec.DRIVERPROPERTIES; |
| import static com.sun.gjc.common.DataSourceSpec.ESCAPECHARACTER; |
| import static com.sun.gjc.common.DataSourceSpec.INITIALPOOLSIZE; |
| import static com.sun.gjc.common.DataSourceSpec.LOGINTIMEOUT; |
| import static com.sun.gjc.common.DataSourceSpec.LOGWRITER; |
| import static com.sun.gjc.common.DataSourceSpec.MAXIDLETIME; |
| import static com.sun.gjc.common.DataSourceSpec.MAXPOOLSIZE; |
| import static com.sun.gjc.common.DataSourceSpec.MAXSTATEMENTS; |
| import static com.sun.gjc.common.DataSourceSpec.MINPOOLSIZE; |
| import static com.sun.gjc.common.DataSourceSpec.NETWORKPROTOCOL; |
| import static com.sun.gjc.common.DataSourceSpec.PASSWORD; |
| import static com.sun.gjc.common.DataSourceSpec.PORTNUMBER; |
| import static com.sun.gjc.common.DataSourceSpec.PROPERTYCYCLE; |
| import static com.sun.gjc.common.DataSourceSpec.ROLENAME; |
| import static com.sun.gjc.common.DataSourceSpec.SERVERNAME; |
| import static com.sun.gjc.common.DataSourceSpec.USERNAME; |
| import static java.util.Arrays.asList; |
| import static java.util.logging.Level.SEVERE; |
| |
| import java.io.Serializable; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.logging.Logger; |
| |
| import org.glassfish.internal.api.ClassLoaderHierarchy; |
| import org.glassfish.internal.api.Globals; |
| |
| import com.sun.enterprise.util.i18n.StringManager; |
| import com.sun.gjc.util.MethodExecutor; |
| import com.sun.logging.LogDomains; |
| |
| import jakarta.resource.ResourceException; |
| |
| /** |
| * Utility class, which would create necessary Datasource object according to |
| * the specification. |
| * |
| * @author Binod P.G |
| * @version 1.0, 02/07/23 |
| * @see com.sun.gjc.common.DataSourceSpec |
| * @see com.sun.gjc.util.MethodExcecutor |
| */ |
| public class DataSourceObjectBuilder implements Serializable { |
| |
| private static final long serialVersionUID = 1L; |
| |
| private static Logger _logger = LogDomains.getLogger(MethodExecutor.class, LogDomains.RSR_LOGGER); |
| private static final StringManager sm = StringManager.getManager(DataSourceObjectBuilder.class); |
| |
| private DataSourceSpec spec; |
| private MethodExecutor executor; |
| |
| /** |
| * Construct a DataSource Object from the spec. |
| * |
| * @param spec <code> DataSourceSpec </code> object. |
| */ |
| public DataSourceObjectBuilder(DataSourceSpec spec) { |
| this.spec = spec; |
| executor = new MethodExecutor(); |
| } |
| |
| /** |
| * Construct the DataSource Object from the spec. |
| * |
| * @return Object constructed using the DataSourceSpec. |
| * @throws <code>ResourceException</code> if the class is not found or some |
| * issue in executing some method. |
| */ |
| public Object constructDataSourceObject() throws ResourceException { |
| Map<String, List<String>> driverProperties = parseDriverProperties(spec, true); |
| Object dataSourceObject = getDataSourceObject(); |
| |
| for (Method method : dataSourceObject.getClass().getMethods()) { |
| String methodName = method.getName(); |
| |
| // Check for driver properties first since some jdbc properties |
| // may be supported in form of driver properties |
| if (driverProperties.containsKey(methodName.toUpperCase(Locale.getDefault()))) { |
| executor.runMethod(method, dataSourceObject, driverProperties.get(methodName.toUpperCase(Locale.getDefault()))); |
| |
| } else if (methodName.equalsIgnoreCase("setUser")) { |
| executor.runJavaBeanMethod(spec.getDetail(USERNAME), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setPassword")) { |
| executor.runJavaBeanMethod(spec.getDetail(PASSWORD), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setLoginTimeOut")) { |
| executor.runJavaBeanMethod(spec.getDetail(LOGINTIMEOUT), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setLogWriter")) { |
| executor.runJavaBeanMethod(spec.getDetail(LOGWRITER), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setDatabaseName")) { |
| executor.runJavaBeanMethod(spec.getDetail(DATABASENAME), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setDataSourceName")) { |
| executor.runJavaBeanMethod(spec.getDetail(DATASOURCENAME), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setDescription")) { |
| executor.runJavaBeanMethod(spec.getDetail(DESCRIPTION), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setNetworkProtocol")) { |
| executor.runJavaBeanMethod(spec.getDetail(NETWORKPROTOCOL), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setPortNumber")) { |
| executor.runJavaBeanMethod(spec.getDetail(PORTNUMBER), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setRoleName")) { |
| executor.runJavaBeanMethod(spec.getDetail(ROLENAME), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setServerName")) { |
| executor.runJavaBeanMethod(spec.getDetail(SERVERNAME), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setMaxStatements")) { |
| executor.runJavaBeanMethod(spec.getDetail(MAXSTATEMENTS), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setInitialPoolSize")) { |
| executor.runJavaBeanMethod(spec.getDetail(INITIALPOOLSIZE), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setMinPoolSize")) { |
| executor.runJavaBeanMethod(spec.getDetail(MINPOOLSIZE), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setMaxPoolSize")) { |
| executor.runJavaBeanMethod(spec.getDetail(MAXPOOLSIZE), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setMaxIdleTime")) { |
| executor.runJavaBeanMethod(spec.getDetail(MAXIDLETIME), method, dataSourceObject); |
| |
| } else if (methodName.equalsIgnoreCase("setPropertyCycle")) { |
| executor.runJavaBeanMethod(spec.getDetail(PROPERTYCYCLE), method, dataSourceObject); |
| |
| } |
| } |
| |
| return dataSourceObject; |
| } |
| |
| /** |
| * Get the extra driver properties from the DataSourceSpec object and parse them |
| * to a set of methodName and parameters. Prepare a hashtable containing these |
| * details and return. |
| * |
| * @param spec <code> DataSourceSpec </code> object. |
| * @return Hashtable containing method names and parameters, |
| * @throws ResourceException If delimiter is not provided and property string is |
| * not null. |
| */ |
| public Map<String, List<String>> parseDriverProperties(DataSourceSpec spec, boolean returnUpperCase) throws ResourceException { |
| String delim = spec.getDetail(DELIMITER); |
| String escape = spec.getDetail(ESCAPECHARACTER); |
| String prop = spec.getDetail(DRIVERPROPERTIES); |
| |
| if (prop == null || prop.trim().equals("")) { |
| return new HashMap<>(); |
| } |
| |
| if (delim == null || delim.equals("")) { |
| throw new ResourceException(sm.getString("dsob.delim_not_specified")); |
| } |
| |
| if (escape == null || escape.equals("")) { |
| throw new ResourceException(sm.getString("dsob.escape_char_not_specified")); |
| } |
| |
| return parseDriverProperties(prop, escape, delim, returnUpperCase); |
| } |
| |
| /** |
| * parse the driver properties and re-generate name value pairs with unescaped |
| * values. |
| * |
| * @param values driverProperties |
| * @param escape escape character |
| * @param delimiter delimiter |
| * @return Hashtable |
| */ |
| public Map<String, List<String>> parseDriverProperties(String values, String escape, String delimiter, boolean returnUpperCase) { |
| Map<String, List<String>> parsedDriverProperties = new HashMap<>(); |
| String parsedValue = ""; |
| String name = ""; |
| |
| char escapeChar = escape.charAt(0); |
| char delimiterChar = delimiter.charAt(0); |
| while (values.length() > 0) { |
| if (values.charAt(0) == delimiterChar) { |
| if (values.length() > 1 && values.charAt(1) == delimiterChar) { |
| if (values.length() > 2 && values.charAt(2) == delimiterChar) { |
| |
| // Check for first property that does not have a value |
| // There is no value specified for this property. |
| // Store the name or it will be lost |
| if (returnUpperCase) { |
| name = parsedValue.toUpperCase(Locale.getDefault()); |
| } else { |
| name = parsedValue; |
| } |
| |
| // no value specified for value |
| parsedValue = ""; |
| } |
| |
| parsedDriverProperties.put(name, asList(parsedValue)); |
| |
| parsedValue = ""; |
| values = values.substring(2); |
| } else { |
| if (returnUpperCase) { |
| name = parsedValue.toUpperCase(Locale.getDefault()); |
| } else { |
| name = parsedValue; |
| } |
| parsedValue = ""; |
| values = values.substring(1); |
| } |
| } else if (values.charAt(0) == escapeChar) { |
| if (values.charAt(1) == escapeChar) { |
| parsedValue += values.charAt(1); |
| } else if (values.charAt(1) == delimiterChar) { |
| parsedValue += values.charAt(1); |
| } |
| values = values.substring(2); |
| } else if (values.charAt(0) != escapeChar) { |
| parsedValue += values.charAt(0); |
| values = values.substring(1); |
| } |
| } |
| |
| return parsedDriverProperties; |
| } |
| |
| /** |
| * Creates a Datasource object according to the spec. |
| * |
| * @return Initial DataSource Object instance. |
| * @throws <code>ResourceException</code> If class name is wrong or classpath is |
| * not set properly. |
| */ |
| private Object getDataSourceObject() throws ResourceException { |
| String className = spec.getDetail(CLASSNAME); |
| |
| try { |
| ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); |
| Class<?> dataSourceClass; |
| try { |
| dataSourceClass = Class.forName(className, true, classLoader); |
| } catch (ClassNotFoundException cnfe) { |
| // OSGi-ed apps can't see lib dir, so try using CommonClassLoader |
| classLoader = Globals.get(ClassLoaderHierarchy.class).getCommonClassLoader(); |
| dataSourceClass = Class.forName(className, true, classLoader); |
| } |
| |
| return dataSourceClass.getDeclaredConstructor().newInstance(); |
| } catch (ClassNotFoundException cnfe) { |
| _logger.log(SEVERE, "jdbc.exc_cnfe_ds", cnfe); |
| throw new ResourceException(sm.getString("dsob.class_not_found", className), cnfe); |
| } catch (InstantiationException | NoSuchMethodException | InvocationTargetException ce) { |
| _logger.log(SEVERE, "jdbc.exc_inst", className); |
| throw new ResourceException(sm.getString("dsob.error_instantiating", className), ce); |
| } catch (IllegalAccessException ce) { |
| _logger.log(SEVERE, "jdbc.exc_acc_inst", className); |
| throw new ResourceException(sm.getString("dsob.access_error", className), ce); |
| } |
| } |
| |
| } |