diff --git a/appserver/jdbc/jdbc-runtime/pom.xml b/appserver/jdbc/jdbc-runtime/pom.xml index 03638a68be3..d6b340fcaa6 100644 --- a/appserver/jdbc/jdbc-runtime/pom.xml +++ b/appserver/jdbc/jdbc-runtime/pom.xml @@ -105,6 +105,11 @@ jakarta.el test - + + org.mockito + mockito-core + test + + diff --git a/appserver/jdbc/jdbc-runtime/src/main/java/org/glassfish/jdbcruntime/deployment/annotation/handlers/DataSourceDefinitionHandler.java b/appserver/jdbc/jdbc-runtime/src/main/java/org/glassfish/jdbcruntime/deployment/annotation/handlers/DataSourceDefinitionHandler.java index 6c05822a5cc..cb531064bdc 100644 --- a/appserver/jdbc/jdbc-runtime/src/main/java/org/glassfish/jdbcruntime/deployment/annotation/handlers/DataSourceDefinitionHandler.java +++ b/appserver/jdbc/jdbc-runtime/src/main/java/org/glassfish/jdbcruntime/deployment/annotation/handlers/DataSourceDefinitionHandler.java @@ -48,6 +48,7 @@ import org.glassfish.apf.AnnotationInfo; import org.glassfish.apf.AnnotationProcessorException; import org.glassfish.apf.HandlerProcessingResult; +import org.glassfish.config.support.TranslatedConfigView; import org.glassfish.deployment.common.JavaEEResourceType; import org.glassfish.deployment.common.RootDeploymentDescriptor; import org.jvnet.hk2.annotations.Service; @@ -236,12 +237,12 @@ private void merge(Set dsdDescs, DataSourceDefinition defn) if (desc.getName().equals(defn.name())) { if (desc.getClassName() == null) { - desc.setClassName(defn.className()); + desc.setClassName(TranslatedConfigView.expandValue(defn.className())); } if (desc.getDescription() == null) { if (defn.description() != null && !defn.description().equals("")) { - desc.setDescription(defn.description()); + desc.setDescription(TranslatedConfigView.expandValue(defn.description())); } } @@ -255,7 +256,7 @@ private void merge(Set dsdDescs, DataSourceDefinition defn) if (!desc.isServerNameSet() && desc.getUrl() == null) { //localhost is the default value (even in the descriptor) if (defn.serverName() != null && !defn.serverName().equals("localhost")) { - desc.setServerName(defn.serverName()); + desc.setServerName(TranslatedConfigView.expandValue(defn.serverName())); } } @@ -269,7 +270,7 @@ private void merge(Set dsdDescs, DataSourceDefinition defn) //try only when URL is not set if (desc.getDatabaseName() == null && desc.getUrl() == null) { if (defn.databaseName() != null && !defn.databaseName().equals("")) { - desc.setDatabaseName(defn.databaseName()); + desc.setDatabaseName(TranslatedConfigView.expandValue(defn.databaseName())); } } @@ -278,20 +279,20 @@ private void merge(Set dsdDescs, DataSourceDefinition defn) !(desc.getPortNumber() != -1 && desc.getServerName() != null && (desc.getDatabaseName() != null))) { if (defn.url() != null && !defn.url().equals("")) { - desc.setUrl(defn.url()); + desc.setUrl(TranslatedConfigView.expandValue(defn.url())); } } if (desc.getUser() == null) { if (defn.user() != null && !defn.user().equals("")) { - desc.setUser(defn.user()); + desc.setUser(TranslatedConfigView.expandValue(defn.user())); } } if (desc.getPassword() == null) { if (defn.password() != null /*ALLOW EMPTY PASSWORDS && !defn.password().equals("")*/) { - desc.setPassword(defn.password()); + desc.setPassword(TranslatedConfigView.expandValue(defn.password())); } } @@ -357,7 +358,7 @@ private void merge(Set dsdDescs, DataSourceDefinition defn) String value = property.substring(index + 1); //add to properties only when not already present if (properties.get(name) == null) { - properties.put(name, value); + properties.put(name, TranslatedConfigView.expandValue(value)); } } } @@ -374,15 +375,15 @@ DataSourceDefinitionDescriptor createDescriptor(DataSourceDefinition defn) { DataSourceDefinitionDescriptor desc = new DataSourceDefinitionDescriptor(); desc.setMetadataSource(MetadataSource.ANNOTATION); - desc.setName(defn.name()); - desc.setClassName(defn.className()); + desc.setName(TranslatedConfigView.expandValue(defn.name())); + desc.setClassName(TranslatedConfigView.expandValue(defn.className())); if (defn.description() != null && !defn.description().equals("")) { - desc.setDescription(defn.description()); + desc.setDescription(TranslatedConfigView.expandValue(defn.description())); } if (defn.serverName() != null && !defn.serverName().equals("localhost")) { - desc.setServerName(defn.serverName()); + desc.setServerName(TranslatedConfigView.expandValue(defn.serverName())); } if (defn.portNumber() != -1) { @@ -391,28 +392,28 @@ DataSourceDefinitionDescriptor createDescriptor(DataSourceDefinition defn) { if (defn.databaseName() != null && !defn.databaseName().equals("")) { - desc.setDatabaseName(defn.databaseName()); + desc.setDatabaseName(TranslatedConfigView.expandValue(defn.databaseName())); } if (desc.getPortNumber() != -1 && desc.getDatabaseName() != null && desc.getServerName() != null) { //standard properties are set, ignore URL } else { if (defn.url() != null && !defn.url().equals("")) { - desc.setUrl(defn.url()); + desc.setUrl(TranslatedConfigView.expandValue(defn.url())); desc.setServerName(null); //To prevent serverName overriding the URL, always use the URL if the standard properties are not set } } if (defn.user() != null && !defn.user().equals("")) { - desc.setUser(defn.user()); + desc.setUser(TranslatedConfigView.expandValue(defn.user())); } if (defn.password() != null /*ALLOW EMPTY PASSWORDS && !defn.password().equals("")*/) { - desc.setPassword(defn.password()); + desc.setPassword(TranslatedConfigView.expandValue(defn.password())); } if (defn.isolationLevel() != -1) { - desc.setIsolationLevel(String.valueOf(defn.isolationLevel())); + desc.setIsolationLevel(TranslatedConfigView.expandValue(String.valueOf(defn.isolationLevel()))); } if (defn.transactional()) { @@ -443,7 +444,6 @@ DataSourceDefinitionDescriptor createDescriptor(DataSourceDefinition defn) { desc.setLoginTimeout(String.valueOf(defn.loginTimeout())); } - if (defn.properties() != null) { Properties properties = desc.getProperties(); @@ -455,7 +455,7 @@ DataSourceDefinitionDescriptor createDescriptor(DataSourceDefinition defn) { if (index > -1 && index != 0 && index < property.length() - 1) { String name = property.substring(0, index); String value = property.substring(index + 1); - properties.put(name, value); + properties.put(name, TranslatedConfigView.expandValue(value)); } } } diff --git a/appserver/jdbc/jdbc-runtime/src/test/java/org/glassfish/jdbcruntime/deployment/annotation/handlers/DataSourceDefinitionTest.java b/appserver/jdbc/jdbc-runtime/src/test/java/org/glassfish/jdbcruntime/deployment/annotation/handlers/DataSourceDefinitionTest.java index 1dab489ef32..7ac40bf86b8 100644 --- a/appserver/jdbc/jdbc-runtime/src/test/java/org/glassfish/jdbcruntime/deployment/annotation/handlers/DataSourceDefinitionTest.java +++ b/appserver/jdbc/jdbc-runtime/src/test/java/org/glassfish/jdbcruntime/deployment/annotation/handlers/DataSourceDefinitionTest.java @@ -40,17 +40,93 @@ package org.glassfish.jdbcruntime.deployment.annotation.handlers; import com.sun.enterprise.deployment.DataSourceDefinitionDescriptor; -import java.lang.annotation.Annotation; -import javax.annotation.sql.DataSourceDefinition; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import javax.annotation.sql.DataSourceDefinition; +import java.util.HashMap; +import java.util.Map; + +import static org.mockito.Mockito.when; /** * Test for DataSourceDefinition processing in DataSourceDefinitionHandler * @author jonathan coustick */ +@RunWith(MockitoJUnitRunner.class) public class DataSourceDefinitionTest { - + + @Mock + private DataSourceDefinition dataSourceDefinition; + + @Before + public void before() { + when(dataSourceDefinition.portNumber()).thenReturn(-1); + when(dataSourceDefinition.isolationLevel()).thenReturn(-1); + when(dataSourceDefinition.transactional()).thenReturn(false); + when(dataSourceDefinition.initialPoolSize()).thenReturn(-1); + when(dataSourceDefinition.maxPoolSize()).thenReturn(-1); + when(dataSourceDefinition.minPoolSize()).thenReturn(-1); + when(dataSourceDefinition.maxIdleTime()).thenReturn(-1); + when(dataSourceDefinition.maxStatements()).thenReturn(-1); + when(dataSourceDefinition.loginTimeout()).thenReturn(-1); + } + + @Test + public void test_environment_variable_expansion_works() throws Exception { + String url = "url"; + String serverName = "server name"; + String className = "class name"; + String name = "name"; + String description = "description"; + String user = "user"; + String password = "password"; + String databaseName = "database name"; + String property1 = "property 1"; + String property2 = "property 2"; + + Map env = new HashMap<>(); + env.put("DB_URL", url); + env.put("DB_SERVER_NAME", serverName); + env.put("DB_CLASS_NAME", className); + env.put("DB_NAME", name); + env.put("DB_DESCRIPTION", description); + env.put("DB_USER", user); + env.put("DB_PASSWORD", password); + env.put("DB_DATABASE_NAME", databaseName); + env.put("DB_PROPERTY1", property1); + env.put("DB_PROPERTY2", property2); + EnvironmentUtil.setEnv(env); + DataSourceDefinitionHandler handler = new DataSourceDefinitionHandler(); + + when(dataSourceDefinition.url()).thenReturn("${ENV=DB_URL}"); + when(dataSourceDefinition.serverName()).thenReturn("${ENV=DB_SERVER_NAME}"); + when(dataSourceDefinition.className()).thenReturn("${ENV=DB_CLASS_NAME}"); + when(dataSourceDefinition.name()).thenReturn("${ENV=DB_NAME}"); + when(dataSourceDefinition.description()).thenReturn("${ENV=DB_DESCRIPTION}"); + when(dataSourceDefinition.user()).thenReturn("${ENV=DB_USER}"); + when(dataSourceDefinition.password()).thenReturn("${ENV=DB_PASSWORD}"); + when(dataSourceDefinition.databaseName()).thenReturn("${ENV=DB_DATABASE_NAME}"); + when(dataSourceDefinition.properties()).thenReturn(new String[]{"property1=${ENV=DB_PROPERTY1}", "property2=${ENV=DB_PROPERTY2}"}); + + DataSourceDefinitionDescriptor descriptor = handler.createDescriptor(dataSourceDefinition); + + Assert.assertEquals(url,descriptor.getUrl()); + Assert.assertNull(descriptor.getServerName()); // because url is set + Assert.assertEquals(className,descriptor.getClassName()); + Assert.assertEquals(name,descriptor.getName()); + Assert.assertEquals(description,descriptor.getDescription()); + Assert.assertEquals(user,descriptor.getUser()); + Assert.assertEquals(password,descriptor.getPassword()); + Assert.assertEquals(databaseName,descriptor.getDatabaseName()); + Assert.assertEquals(property1,descriptor.getProperty("property1")); + Assert.assertEquals(property2,descriptor.getProperty("property2")); + } + /** * Test to ensure that if the URL has been set, it will override the default serverName of localhost * and cause that to be set to null. @@ -58,126 +134,23 @@ public class DataSourceDefinitionTest { @Test public void testServerAndURL() { DataSourceDefinitionHandler handler = new DataSourceDefinitionHandler(); - + + String url = "http://database:5432/demo"; + String serverName = "localhost"; + //Check url overrides serverName and sets it to null - DataSourceDefinition definition = new DataSourceDefinitionImpl() { - @Override - public String url() { - return "http://database:5432/demo"; - } - - @Override - public String serverName() { - return "localhost"; - } - - }; - DataSourceDefinitionDescriptor descriptor = handler.createDescriptor(definition); + when(dataSourceDefinition.url()).thenReturn(url); + when(dataSourceDefinition.serverName()).thenReturn(serverName); + + DataSourceDefinitionDescriptor descriptor = handler.createDescriptor(dataSourceDefinition); + Assert.assertNull(descriptor.getServerName()); - - + //Check if url is not set then serverName is left as-is - definition = new DataSourceDefinitionImpl() { - @Override - public String url() { - return null; - } - - @Override - public String serverName() { - return "localhost"; - } - }; - descriptor = handler.createDescriptor(definition); + when(dataSourceDefinition.url()).thenReturn(null); + + descriptor = handler.createDescriptor(dataSourceDefinition ); + Assert.assertEquals("localhost", descriptor.getServerName()); } - - abstract class DataSourceDefinitionImpl implements DataSourceDefinition { - @Override - public String name() { - return null; - } - - @Override - public String className() { - return null; - } - - @Override - public String description() { - return null; - } - - @Override - public String user() { - return null; - } - - @Override - public String password() { - return null; - } - - @Override - public String databaseName() { - return null; - } - - @Override - public int portNumber() { - return -1; - } - - @Override - public int isolationLevel() { - return -1; - } - - @Override - public boolean transactional() { - return false; - } - - @Override - public int initialPoolSize() { - return -1; - } - - @Override - public int maxPoolSize() { - return -1; - } - - @Override - public int minPoolSize() { - return -1; - } - - @Override - public int maxIdleTime() { - return -1; - } - - @Override - public int maxStatements() { - return -1; - } - - @Override - public String[] properties() { - return null; - } - - @Override - public int loginTimeout() { - return -1; - } - - @Override - public Class annotationType() { - return DataSourceDefinition.class; - } - } - - } diff --git a/appserver/jdbc/jdbc-runtime/src/test/java/org/glassfish/jdbcruntime/deployment/annotation/handlers/EnvironmentUtil.java b/appserver/jdbc/jdbc-runtime/src/test/java/org/glassfish/jdbcruntime/deployment/annotation/handlers/EnvironmentUtil.java new file mode 100644 index 00000000000..688303917db --- /dev/null +++ b/appserver/jdbc/jdbc-runtime/src/test/java/org/glassfish/jdbcruntime/deployment/annotation/handlers/EnvironmentUtil.java @@ -0,0 +1,76 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2020 Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package org.glassfish.jdbcruntime.deployment.annotation.handlers; + +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.Map; + +class EnvironmentUtil { + static void setEnv(Map newenv) throws Exception { + try { + Class processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment"); + Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment"); + theEnvironmentField.setAccessible(true); + @SuppressWarnings("unchecked") + Map env = (Map) theEnvironmentField.get(null); + env.putAll(newenv); + Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment"); + theCaseInsensitiveEnvironmentField.setAccessible(true); + @SuppressWarnings("unchecked") + Map cienv = (Map) theCaseInsensitiveEnvironmentField.get(null); + cienv.putAll(newenv); + } catch (NoSuchFieldException e) { + Class[] classes = Collections.class.getDeclaredClasses(); + Map env = System.getenv(); + for(Class cl : classes) { + if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) { + Field field = cl.getDeclaredField("m"); + field.setAccessible(true); + Object obj = field.get(env); + @SuppressWarnings("unchecked") + Map map = (Map) obj; + map.clear(); + map.putAll(newenv); + } + } + } + } +}