diff --git a/bom/application/pom.xml b/bom/application/pom.xml
index 7c0ecb3ac7fd..a7a09a32ae6c 100644
--- a/bom/application/pom.xml
+++ b/bom/application/pom.xml
@@ -1152,7 +1152,7 @@
org.jboss.weld.servlet
weld-servlet-shaded
- 3.1.9.Final
+ 4.0.0.Final
@@ -1167,6 +1167,12 @@
2.5.0
+
+ org.glassfish.jersey.inject
+ jersey-cdi2-se
+ 2.28
+
+
org.jboss.weld
weld-junit5
diff --git a/dotCMS/pom.xml b/dotCMS/pom.xml
index 0563719b8027..d43b6e13e719 100644
--- a/dotCMS/pom.xml
+++ b/dotCMS/pom.xml
@@ -1411,7 +1411,12 @@
org.jboss.weld.servlet
weld-servlet-shaded
- 3.1.9.Final
+ 4.0.0.Final
+
+
+
+ org.glassfish.jersey.inject
+ jersey-cdi2-se
diff --git a/dotCMS/src/main/java/com/dotcms/business/FactoryLocatorProducers.java b/dotCMS/src/main/java/com/dotcms/business/FactoryLocatorProducers.java
deleted file mode 100644
index 0c2d4cf8fe3a..000000000000
--- a/dotCMS/src/main/java/com/dotcms/business/FactoryLocatorProducers.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.dotcms.business;
-
-import com.dotcms.cube.CubeJSClientFactory;
-import com.dotmarketing.business.FactoryLocator;
-
-import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.inject.Produces;
-
-/**
- * This class is useful to include classes are not into the CDI container but
- * wants to be available to be injected.
- * Most of the {@link FactoryLocator} classes will be eventually here.
- * @author jsanca
- */
-@ApplicationScoped
-public class FactoryLocatorProducers {
-
-
- @Produces
- public CubeJSClientFactory getCubeJSClientFactory() {
- return FactoryLocator.getCubeJSClientFactory();
- }
-}
diff --git a/dotCMS/src/main/java/com/dotcms/cube/CubeJSClientFactoryImpl.java b/dotCMS/src/main/java/com/dotcms/cube/CubeJSClientFactoryImpl.java
index c0adf31d92c6..a2603e2125f0 100644
--- a/dotCMS/src/main/java/com/dotcms/cube/CubeJSClientFactoryImpl.java
+++ b/dotCMS/src/main/java/com/dotcms/cube/CubeJSClientFactoryImpl.java
@@ -4,19 +4,22 @@
import com.dotcms.analytics.app.AnalyticsApp;
import com.dotcms.analytics.helper.AnalyticsHelper;
import com.dotcms.analytics.model.AccessToken;
-import com.dotcms.analytics.model.AccessTokenFetchMode;
import com.dotcms.exception.AnalyticsException;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.exception.DotSecurityException;
import com.google.common.annotations.VisibleForTesting;
import com.liferay.portal.model.User;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Default;
/**
* Factory to create {@link CubeJSClient} instances.
*
* @author vico
*/
+@Default
+@ApplicationScoped
public class CubeJSClientFactoryImpl implements CubeJSClientFactory {
private static AnalyticsHelper analyticsHelper = AnalyticsHelper.get();
diff --git a/dotCMS/src/main/java/com/dotcms/jobs/business/api/JobQueueManagerAPIImpl.java b/dotCMS/src/main/java/com/dotcms/jobs/business/api/JobQueueManagerAPIImpl.java
index f675c331d21f..34fb94052036 100644
--- a/dotCMS/src/main/java/com/dotcms/jobs/business/api/JobQueueManagerAPIImpl.java
+++ b/dotCMS/src/main/java/com/dotcms/jobs/business/api/JobQueueManagerAPIImpl.java
@@ -48,6 +48,8 @@
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.inject.Default;
import javax.inject.Inject;
/**
diff --git a/dotCMS/src/main/java/com/dotcms/jobs/business/queue/JobQueueProducer.java b/dotCMS/src/main/java/com/dotcms/jobs/business/queue/JobQueueProducer.java
index 1596e9fb17d6..764146d2eac3 100644
--- a/dotCMS/src/main/java/com/dotcms/jobs/business/queue/JobQueueProducer.java
+++ b/dotCMS/src/main/java/com/dotcms/jobs/business/queue/JobQueueProducer.java
@@ -22,8 +22,6 @@ public class JobQueueProducer {
*
* @return A JobQueue instance
*/
- @Produces
- @ApplicationScoped
public JobQueue produceJobQueue() {
if (JOB_QUEUE_IMPLEMENTATION_TYPE.equals("postgres")) {
diff --git a/dotCMS/src/main/java/com/dotcms/jobs/business/queue/PostgresJobQueue.java b/dotCMS/src/main/java/com/dotcms/jobs/business/queue/PostgresJobQueue.java
index 37bb0fa9ac1e..6eae10deced7 100644
--- a/dotCMS/src/main/java/com/dotcms/jobs/business/queue/PostgresJobQueue.java
+++ b/dotCMS/src/main/java/com/dotcms/jobs/business/queue/PostgresJobQueue.java
@@ -7,6 +7,7 @@
import com.dotcms.jobs.business.queue.error.JobNotFoundException;
import com.dotcms.jobs.business.queue.error.JobQueueDataException;
import com.dotcms.jobs.business.queue.error.JobQueueException;
+import com.dotcms.repackage.org.directwebremoting.guice.ApplicationScoped;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.common.db.DotConnect;
import com.dotmarketing.exception.DotDataException;
@@ -28,6 +29,7 @@
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
+import javax.enterprise.inject.Default;
/**
* PostgreSQL implementation of the JobQueue interface. This class provides concrete implementations
@@ -53,6 +55,8 @@
* @see Job
* @see JobState
*/
+@Default
+@ApplicationScoped
public class PostgresJobQueue implements JobQueue {
private static final String CREATE_JOB_QUEUE_QUERY = "INSERT INTO job_queue "
diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/JobQueueResource.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/JobQueueResource.java
new file mode 100644
index 000000000000..b5fbdd3c9ff6
--- /dev/null
+++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/JobQueueResource.java
@@ -0,0 +1,157 @@
+package com.dotcms.rest.api.v1.job;
+
+import com.dotcms.jobs.business.api.JobQueueManagerAPI;
+import com.dotcms.jobs.business.job.Job;
+import com.dotcms.jobs.business.job.JobPaginatedResult;
+import com.dotcms.rest.InitDataObject;
+import com.dotcms.rest.ResponseEntityView;
+import com.dotcms.rest.WebResource;
+import com.dotcms.rest.annotation.NoCache;
+import com.dotmarketing.business.APILocator;
+import com.dotmarketing.util.Logger;
+import com.liferay.portal.model.User;
+import org.glassfish.jersey.media.sse.EventOutput;
+import org.glassfish.jersey.media.sse.OutboundEvent;
+import org.glassfish.jersey.media.sse.SseFeature;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+@Path("/v1/jobs")
+public class JobQueueResource {
+
+ private final WebResource webResource;
+ private final JobQueueManagerAPI jobQueueManagerAPI;
+
+ //@Inject
+ MyTestBean myTestBean;
+
+ public JobQueueResource() {
+ this(new WebResource(), APILocator.getJobQueueManagerAPI());
+ }
+
+ //@Inject
+ public JobQueueResource(WebResource webResource, JobQueueManagerAPI jobQueueManagerAPI) {
+ this.webResource = webResource;
+ this.jobQueueManagerAPI = jobQueueManagerAPI;
+ }
+
+ @POST
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response createJob(@Context HttpServletRequest request,
+ @QueryParam("queueName") String queueName,
+ Map jobParameters) {
+ try {
+ InitDataObject initData = webResource.init(null, true, request, true, null);
+ User user = initData.getUser();
+
+ String jobId = jobQueueManagerAPI.createJob(queueName, jobParameters);
+
+ return Response.ok(new ResponseEntityView<>(jobId)).build();
+ } catch (Exception e) {
+ Logger.error(this, "Error creating job", e);
+ return Response.serverError().entity(new ResponseEntityView<>(e.getMessage())).build();
+ }
+ }
+
+ @GET
+ @Path("/{jobId}/status")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getJobStatus(@Context HttpServletRequest request, @PathParam("jobId") String jobId) {
+ try {
+ InitDataObject initData = webResource.init(null, true, request, true, null);
+ User user = initData.getUser();
+
+ Job job = jobQueueManagerAPI.getJob(jobId);
+ Map statusInfo = Map.of(
+ "state", job.state(),
+ "progress", job.progress(),
+ "executionNode", job.executionNode().orElse("N/A")
+ );
+
+ return Response.ok(new ResponseEntityView<>(statusInfo)).build();
+ } catch (Exception e) {
+ Logger.error(this, "Error getting job status", e);
+ return Response.serverError().entity(new ResponseEntityView<>(e.getMessage())).build();
+ }
+ }
+
+ @POST
+ @Path("/{jobId}/cancel")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response cancelJob(@Context HttpServletRequest request, @PathParam("jobId") String jobId) {
+ try {
+ InitDataObject initData = webResource.init(null, true, request, true, null);
+ User user = initData.getUser();
+
+ jobQueueManagerAPI.cancelJob(jobId);
+ return Response.ok(new ResponseEntityView<>("Job cancelled successfully")).build();
+ } catch (Exception e) {
+ Logger.error(this, "Error cancelling job", e);
+ return Response.serverError().entity(new ResponseEntityView<>(e.getMessage())).build();
+ }
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response listJobs(@Context HttpServletRequest request,
+ @QueryParam("page") @DefaultValue("1") int page,
+ @QueryParam("pageSize") @DefaultValue("20") int pageSize) {
+ try {
+ System.out.println(myTestBean.sayHello());
+ InitDataObject initData = webResource.init(null, true, request, true, null);
+ User user = initData.getUser();
+
+ JobPaginatedResult result = jobQueueManagerAPI.getJobs(page, pageSize);
+ return Response.ok(new ResponseEntityView(result)).build();
+ } catch (Exception e) {
+ Logger.error(this, "Error listing jobs", e);
+ return Response.serverError().entity(new ResponseEntityView<>(e.getMessage())).build();
+ }
+ }
+
+ @GET
+ @Path("/{jobId}/monitor")
+ @Produces(SseFeature.SERVER_SENT_EVENTS)
+ @NoCache
+ public EventOutput monitorJob(@Context HttpServletRequest request, @PathParam("jobId") String jobId) {
+ EventOutput eventOutput = new EventOutput();
+ try {
+ InitDataObject initData = webResource.init(null, true, request, true, null);
+ User user = initData.getUser();
+
+ jobQueueManagerAPI.watchJob(jobId, job -> {
+ try {
+ OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
+ eventBuilder.name("job-update");
+ eventBuilder.data(Job.class, job);
+ eventOutput.write(eventBuilder.build());
+ } catch (IOException e) {
+ Logger.error(this, "Error writing SSE event", e);
+ }
+ });
+
+ // Keep the connection open for a reasonable time (e.g., 5 minutes)
+ if (!eventOutput.isClosed()) {
+ Thread.sleep(TimeUnit.MINUTES.toMillis(5));
+ }
+ } catch (Exception e) {
+ Logger.error(this, "Error monitoring job", e);
+ } finally {
+ try {
+ eventOutput.close();
+ } catch (IOException e) {
+ Logger.error(this, "Error closing SSE connection", e);
+ }
+ }
+ return eventOutput;
+ }
+}
diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/MyTestBean.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/MyTestBean.java
new file mode 100644
index 000000000000..a5dcf0d24246
--- /dev/null
+++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/MyTestBean.java
@@ -0,0 +1,7 @@
+package com.dotcms.rest.api.v1.job;
+
+public interface MyTestBean {
+
+ String sayHello();
+
+}
diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/MyTestBeanImpl.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/MyTestBeanImpl.java
new file mode 100644
index 000000000000..13ccac024af7
--- /dev/null
+++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/job/MyTestBeanImpl.java
@@ -0,0 +1,12 @@
+package com.dotcms.rest.api.v1.job;
+
+import javax.enterprise.context.ApplicationScoped;
+
+@ApplicationScoped
+public class MyTestBeanImpl implements MyTestBean {
+
+ public String sayHello() {
+ return "Hello, World!";
+ }
+
+}
diff --git a/dotCMS/src/main/java/com/dotcms/rest/config/DotRestApplication.java b/dotCMS/src/main/java/com/dotcms/rest/config/DotRestApplication.java
index 38af8db95716..79ec0e004c18 100644
--- a/dotCMS/src/main/java/com/dotcms/rest/config/DotRestApplication.java
+++ b/dotCMS/src/main/java/com/dotcms/rest/config/DotRestApplication.java
@@ -47,7 +47,6 @@
public class DotRestApplication extends ResourceConfig {
public DotRestApplication() {
-
register(MultiPartFeature.class).
register(JacksonJaxbJsonProvider.class).
registerClasses(customClasses.keySet()).
diff --git a/dotCMS/src/main/webapp/WEB-INF/beans.xml b/dotCMS/src/main/webapp/WEB-INF/beans.xml
index 1675ad7ab74c..b72a4692cabe 100644
--- a/dotCMS/src/main/webapp/WEB-INF/beans.xml
+++ b/dotCMS/src/main/webapp/WEB-INF/beans.xml
@@ -1,9 +1,13 @@
-
+ xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
+ http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
+ version="2.0" bean-discovery-mode="all">
+
+
+
-
\ No newline at end of file
+
+
diff --git a/dotCMS/src/test/resources/META-INF/beans.xml b/dotCMS/src/test/resources/META-INF/beans.xml
index 1675ad7ab74c..5a387688145b 100644
--- a/dotCMS/src/test/resources/META-INF/beans.xml
+++ b/dotCMS/src/test/resources/META-INF/beans.xml
@@ -1,9 +1,11 @@
-
+ xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
+ http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
+ version="2.0" bean-discovery-mode="all">
+
-
\ No newline at end of file
+
+
diff --git a/dotcms-integration/src/test/java/com/dotcms/jobs/business/api/JobQueueManagerAPICDITest.java b/dotcms-integration/src/test/java/com/dotcms/jobs/business/api/JobQueueManagerAPICDITest.java
index bc028f524dd0..d151654a34a8 100644
--- a/dotcms-integration/src/test/java/com/dotcms/jobs/business/api/JobQueueManagerAPICDITest.java
+++ b/dotcms-integration/src/test/java/com/dotcms/jobs/business/api/JobQueueManagerAPICDITest.java
@@ -5,16 +5,9 @@
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;
-import com.dotcms.jobs.business.api.events.EventProducer;
-import com.dotcms.jobs.business.api.events.RealTimeJobMonitor;
-import com.dotcms.jobs.business.error.CircuitBreaker;
import com.dotcms.jobs.business.error.ExponentialBackoffRetryStrategy;
-import com.dotcms.jobs.business.error.RetryStrategy;
-import com.dotcms.jobs.business.error.RetryStrategyProducer;
import com.dotcms.jobs.business.queue.JobQueue;
-import com.dotcms.jobs.business.queue.JobQueueProducer;
import javax.inject.Inject;
-import org.jboss.weld.bootstrap.api.helpers.RegistrySingletonProvider;
import org.jboss.weld.junit5.WeldInitiator;
import org.jboss.weld.junit5.WeldJunit5Extension;
import org.jboss.weld.junit5.WeldSetup;
@@ -29,15 +22,7 @@
public class JobQueueManagerAPICDITest {
@WeldSetup
- public WeldInitiator weld = WeldInitiator.of(
- WeldInitiator.createWeld()
- .containerId(RegistrySingletonProvider.STATIC_INSTANCE)
- .beanClasses(JobQueueManagerAPIImpl.class, JobQueueConfig.class,
- JobQueue.class, RetryStrategy.class, CircuitBreaker.class,
- JobQueueProducer.class, JobQueueConfigProducer.class,
- RetryStrategyProducer.class, RealTimeJobMonitor.class,
- EventProducer.class)
- );
+ public WeldInitiator weld = WeldInitiator.performDefaultDiscovery();
@Inject
private JobQueueManagerAPI jobQueueManagerAPI;
diff --git a/dotcms-integration/src/test/java/com/dotcms/util/IntegrationTestInitService.java b/dotcms-integration/src/test/java/com/dotcms/util/IntegrationTestInitService.java
index e2d589cb1ae5..fcc689ef704c 100644
--- a/dotcms-integration/src/test/java/com/dotcms/util/IntegrationTestInitService.java
+++ b/dotcms-integration/src/test/java/com/dotcms/util/IntegrationTestInitService.java
@@ -60,6 +60,7 @@ public void init() throws Exception {
if (initCompleted.compareAndSet(false, true)) {
weld = new Weld().containerId(RegistrySingletonProvider.STATIC_INSTANCE)
+ /*
.beanClasses(
JobQueueManagerAPIImpl.class,
JobQueueConfig.class,
@@ -71,6 +72,7 @@ public void init() throws Exception {
RetryStrategyProducer.class,
RealTimeJobMonitor.class,
EventProducer.class)
+ */
.initialize();
System.setProperty(TestUtil.DOTCMS_INTEGRATION_TEST, TestUtil.DOTCMS_INTEGRATION_TEST);
diff --git a/dotcms-integration/src/test/resources/META-INF/beans.xml b/dotcms-integration/src/test/resources/META-INF/beans.xml
index 1675ad7ab74c..5a387688145b 100644
--- a/dotcms-integration/src/test/resources/META-INF/beans.xml
+++ b/dotcms-integration/src/test/resources/META-INF/beans.xml
@@ -1,9 +1,11 @@
-
+ xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
+ http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
+ version="2.0" bean-discovery-mode="all">
+
-
\ No newline at end of file
+
+