Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow resource references in persistence xml datasource #24964

Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2024 Contributors to the Eclipse Foundation.
*
* 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 org.glassfish.main.itest.tools.setup;

import static java.lang.System.Logger.Level.INFO;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import org.jboss.shrinkwrap.api.exporter.ZipExporter;
import org.jboss.shrinkwrap.api.spec.WebArchive;

/**
* Adds some helper methods as default interface methods related to creating deployments in tests.
* @author Ondro Mihalyi
*/
public interface DeploymentAware {

System.Logger getLogger();

default File createDeploymentWar(WebArchive webArchive, String archiveFileBase) throws IOException {
getLogger().log(INFO, webArchive.toString(true));

File tmpDir = Files.createTempDirectory(archiveFileBase).toFile();
File warFile = new File(tmpDir, archiveFileBase + ".war");
webArchive.as(ZipExporter.class).exportTo(warFile, true);
tmpDir.deleteOnExit();
return warFile;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package org.glassfish.persistence.common;

import static java.lang.System.Logger.Level.DEBUG;

import com.sun.appserv.connectors.internal.api.ConnectorRuntime;
import com.sun.enterprise.deployment.BundleDescriptor;
import com.sun.enterprise.deployment.types.ResourceReferenceContainer;
import com.sun.enterprise.deployment.util.DOLUtils;

import javax.naming.NamingException;
import javax.sql.DataSource;
Expand All @@ -27,14 +31,15 @@
import org.glassfish.api.naming.SimpleJndiName;
import org.glassfish.resourcebase.resources.api.ResourceInfo;


/**
* Contains helper methods for persistence module
*
* @author Mitesh Meswani
*/
public class PersistenceHelper {

private static final System.Logger LOGGER = System.getLogger(PersistenceHelper.class.getName());

public static DataSource lookupNonTxResource(ConnectorRuntime connectorRuntime, DeploymentContext ctx, SimpleJndiName dataSourceName) throws NamingException {
return connectorRuntime.lookupNonTxResource(getResourceInfo(ctx, dataSourceName), true);
}
Expand All @@ -44,10 +49,29 @@ public static DataSource lookupPMResource(ConnectorRuntime connectorRuntime, Dep
}

private static ResourceInfo getResourceInfo(DeploymentContext ctx, SimpleJndiName dataSourceName) {
if (ctx != null) {
// ctx can be null e.g. in appclient
dataSourceName = translateResourceReference(ctx, dataSourceName);
}
if (dataSourceName.isJavaApp()) {
String applicationName = ctx.getCommandParameters(OpsParams.class).name();
return new ResourceInfo(dataSourceName, applicationName);
}
return new ResourceInfo(dataSourceName);
}

private static SimpleJndiName translateResourceReference(DeploymentContext ctx, SimpleJndiName dataSourceName) {
final BundleDescriptor currentBundle = DOLUtils.getCurrentBundleForContext(ctx);
if (currentBundle instanceof ResourceReferenceContainer) {
ResourceReferenceContainer referenceContainer = (ResourceReferenceContainer)currentBundle;
try {
return referenceContainer.getResourceReferenceByName(dataSourceName.toString()).getJndiName();
} catch (IllegalArgumentException e) {
LOGGER.log(DEBUG, () -> "Datasource name " + dataSourceName + " is not a reference, will use it as a JNDI name. Error: " + e.getMessage(), e);
return dataSourceName;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to log the exception as a warning at least.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not here. This is a valid condition - if the datasource name is a proper JNDI and not a reference, just use it without any change. It would only pollute logs if it was a warning. I can add a debug logging.

The getResourceReferenceByName gives an exception if resource not found. Ideally, I would rather use findResourceReferenceByName, which returns a null, but that one is protected and only in WebBundleDescriptor, so I rather used a method on the interface ResourceReferenceContainer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, debug/trace is good then. Sometimes I am hunting things around DOL and XML/annotations and any such log is useful.

}
}
return dataSourceName;

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 Contributors to the Eclipse Foundation.
*
* 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 org.glassfish.main.test.app.persistence.resourceref.webapp;

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;

import java.util.Set;

@ApplicationPath("")
public class ResourceRefApplication extends Application {

@Override
public Set<Class<?>> getClasses() {
return Set.of(ResourceRefResource.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2024 Contributors to the Eclipse Foundation.
*
* 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 org.glassfish.main.test.app.persistence.resourceref.webapp;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.PersistenceUnit;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;

@Path("/")
public class ResourceRefResource {

@PersistenceUnit(unitName = "resourceRefPU")
private EntityManagerFactory persistenceUnit;

@GET
public Response getResponse() {
final EntityManager entityManager = persistenceUnit.createEntityManager();
if (entityManager == null) {
return Response.serverError().build();
}
return Response.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright (c) 2024 Contributors to the Eclipse Foundation. 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

-->
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
version="3.0">
<persistence-unit name="resourceRefPU" transaction-type="JTA">
<jta-data-source>myDS</jta-data-source>
</persistence-unit>
</persistence>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright (c) 2024 Contributors to the Eclipse Foundation. 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

-->
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="6.0"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd">
<resource-ref>
<description>Primary database</description>
<res-ref-name>myDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright (c) 2024 Contributors to the Eclipse Foundation.
*
* 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 org.glassfish.main.test.app.persistence.resourceref;

import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.nio.file.Files;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.jupiter.api.Test;

import static java.lang.System.Logger.Level.WARNING;
import static org.glassfish.main.itest.tools.GlassFishTestEnvironment.getAsadmin;
import static org.glassfish.main.itest.tools.GlassFishTestEnvironment.openConnection;
import static org.glassfish.main.itest.tools.asadmin.AsadminResultMatcher.asadminOK;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

import org.glassfish.main.itest.tools.asadmin.Asadmin;
import org.glassfish.main.itest.tools.asadmin.AsadminResult;
import org.glassfish.main.itest.tools.setup.DeploymentAware;
import org.glassfish.main.test.app.persistence.resourceref.webapp.ResourceRefApplication;
import org.glassfish.main.test.app.persistence.resourceref.webapp.ResourceRefResource;

/**
* Tests that JTA datasource in persistence.xml can be a resource reference
*/
public class JtaDataSourceResourceRefTest implements DeploymentAware {

private static final Class<?> TEST_CLASS = JtaDataSourceResourceRefTest.class;

private static final Package TEST_PACKAGE = TEST_CLASS.getPackage();

private static final System.Logger LOG = System.getLogger(TEST_CLASS.getName());

private static final String APP_NAME = TEST_CLASS.getSimpleName() + "WebApp";

private static final String CONTEXT_ROOT = "/" + APP_NAME;

protected static final Asadmin ASADMIN = getAsadmin();

public System.Logger getLogger() {
return LOG;
}

@Test
public void testDeploy() throws IOException {
makeTheDefaultDataSourceEmbededded();
File warFile = createDeployment();
try {
assertThat(ASADMIN.exec("deploy", warFile.getAbsolutePath()), asadminOK());
} finally {
try {
Files.deleteIfExists(warFile.toPath());
} catch (IOException e) {
LOG.log(WARNING, "An error occurred while remove temp file " + warFile.getAbsolutePath(), e);
}
}

HttpURLConnection connection = openConnection(8080, CONTEXT_ROOT);
connection.setRequestMethod("GET");
try {
assertThat(connection.getResponseCode(), equalTo(200));
} finally {
connection.disconnect();
}

assertThat(ASADMIN.exec("undeploy", APP_NAME), asadminOK());
}

private File createDeployment() throws IOException {
WebArchive webArchive = ShrinkWrap.create(WebArchive.class)
.addClass(ResourceRefResource.class)
.addClass(ResourceRefApplication.class)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
.addAsWebInfResource(TEST_PACKAGE, "web.xml", "web.xml")
.addAsResource(TEST_PACKAGE, "persistence.xml", "META-INF/persistence.xml");

return createDeploymentWar(webArchive, APP_NAME);
}

private static void makeTheDefaultDataSourceEmbededded() {
final AsadminResult result = ASADMIN.exec(5_000, "set",
"resources.jdbc-connection-pool.DerbyPool.datasource-classname=org.apache.derby.jdbc.EmbeddedDataSource",
"resources.jdbc-connection-pool.DerbyPool.property.PortNumber=",
"resources.jdbc-connection-pool.DerbyPool.property.serverName=",
"resources.jdbc-connection-pool.DerbyPool.property.URL=");
if (result.isError()) {
System.out.println("Failed to update the default datasource DerbyPool.");
} else {
System.out.println("The default datasource changed to embedded.");
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 Contributors to the Eclipse Foundation.
* Copyright (c) 2023,2024 Contributors to the Eclipse Foundation.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -36,7 +36,11 @@
*/
public class ClassTransformerEjbWebAppTest extends ClassTransformerTestBase {

private static final System.Logger LOG = System.getLogger(ClassTransformerEjbWebAppTest.class.getName());
private static final Class<?> TEST_CLASS = ClassTransformerEjbWebAppTest.class;

private static final Package TEST_PACKAGE = TEST_CLASS.getPackage();

private static final System.Logger LOG = System.getLogger(TEST_CLASS.getName());

private static final String APP_NAME = "TransformEjbWebApp";

Expand All @@ -60,9 +64,7 @@ private static File createDeployment() throws IOException {
.addAsLibrary(createProvider())
.addClass(ClassTransformerBean.class)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
.addAsResource(
new File("src/main/resources/org/glassfish/main/test/app/persistence/transform/persistence.xml"),
"META-INF/persistence.xml");
.addAsResource(TEST_PACKAGE, "persistence.xml", "META-INF/persistence.xml");

LOG.log(INFO, webArchive.toString(true));

Expand Down
Loading