BATCHEE-107 improve getJobNames handling
diff --git a/extensions/shiro/src/main/java/org/apache/batchee/shiro/ShiroSecurityService.java b/extensions/shiro/src/main/java/org/apache/batchee/shiro/ShiroSecurityService.java
index 5ae20c0..bdccb58 100644
--- a/extensions/shiro/src/main/java/org/apache/batchee/shiro/ShiroSecurityService.java
+++ b/extensions/shiro/src/main/java/org/apache/batchee/shiro/ShiroSecurityService.java
@@ -25,6 +25,7 @@
public class ShiroSecurityService extends DefaultSecurityService {
private String instancePrefix;
private String permissionPrefix;
+ private String jobNamePrefix;
private boolean isAuthenticatedAndAuthorized(final String permission) {
return getSubject().isAuthenticated() && getSubject().isPermitted(permission);
@@ -41,6 +42,11 @@
}
@Override
+ public boolean isAuthorizedJobName(String jobName) {
+ return isAuthenticatedAndAuthorized(jobNamePrefix + jobName);
+ }
+
+ @Override
public String getLoggedUser() {
if (getSubject().isAuthenticated()) {
return getSubject().getPrincipal().toString();
@@ -53,5 +59,6 @@
super.init(batchConfig);
permissionPrefix = batchConfig.getProperty("security.job.permission-prefix", "jbatch:");
instancePrefix = permissionPrefix + batchConfig.getProperty("security.job.permission-prefix", "instance:");
+ jobNamePrefix = permissionPrefix + batchConfig.getProperty("security.job.permission-prefix", "jobName:");
}
}
diff --git a/jbatch/src/main/java/org/apache/batchee/container/impl/JobOperatorImpl.java b/jbatch/src/main/java/org/apache/batchee/container/impl/JobOperatorImpl.java
index 790def2..bde0b87 100755
--- a/jbatch/src/main/java/org/apache/batchee/container/impl/JobOperatorImpl.java
+++ b/jbatch/src/main/java/org/apache/batchee/container/impl/JobOperatorImpl.java
@@ -54,7 +54,6 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
@@ -173,8 +172,8 @@
final InternalJobExecution jobEx = persistenceManagerService.jobOperatorGetJobExecution(executionId);
// if it is not in STARTED or STARTING state, mark it as ABANDONED
- BatchStatus status = jobEx.getBatchStatus();
- if (status == BatchStatus.STARTING || status == BatchStatus.STARTED) {
+ BatchStatus status = jobEx.getBatchStatus();
+ if (status == BatchStatus.STARTING || status == BatchStatus.STARTED) {
throw new JobExecutionIsRunningException("Job Execution: " + executionId + " is still running");
}
@@ -284,11 +283,10 @@
@Override
public Set<String> getJobNames() throws JobSecurityException {
final Set<String> jobNames = new HashSet<String>();
- final Map<Long, String> data = persistenceManagerService.jobOperatorGetExternalJobInstanceData();
- for (final Map.Entry<Long, String> entry : data.entrySet()) {
- long instanceId = entry.getKey();
- if (securityService.isAuthorized(instanceId)) {
- jobNames.add(entry.getValue());
+ final Set<String> jobNamesFromDb = persistenceManagerService.getJobNames();
+ for (String jobName : jobNamesFromDb) {
+ if (securityService.isAuthorizedJobName(jobName)) {
+ jobNames.add(jobName);
}
}
return jobNames;
diff --git a/jbatch/src/main/java/org/apache/batchee/container/services/persistence/JDBCPersistenceManagerService.java b/jbatch/src/main/java/org/apache/batchee/container/services/persistence/JDBCPersistenceManagerService.java
index d09abef..56101b5 100755
--- a/jbatch/src/main/java/org/apache/batchee/container/services/persistence/JDBCPersistenceManagerService.java
+++ b/jbatch/src/main/java/org/apache/batchee/container/services/persistence/JDBCPersistenceManagerService.java
@@ -571,6 +571,30 @@
}
@Override
+ public Set<String> getJobNames() {
+ Connection conn = null;
+ PreparedStatement statement = null;
+ ResultSet rs = null;
+
+ Set<String> jobNames = new HashSet<String>();
+ try {
+ conn = getConnection();
+
+ statement = conn.prepareStatement(dictionary.getFindJobNames());
+ rs = statement.executeQuery();
+ while (rs.next()) {
+ jobNames.add(rs.getString(1));
+ }
+
+ } catch (final SQLException e) {
+ throw new PersistenceException(e);
+ } finally {
+ cleanupConnection(conn, rs, statement);
+ }
+ return jobNames;
+ }
+
+ @Override
public Timestamp jobOperatorQueryJobExecutionTimestamp(final long key, final TimestampType timestampType) {
Connection conn = null;
PreparedStatement statement = null;
diff --git a/jbatch/src/main/java/org/apache/batchee/container/services/persistence/JPAPersistenceManagerService.java b/jbatch/src/main/java/org/apache/batchee/container/services/persistence/JPAPersistenceManagerService.java
index 90eea56..be07489 100644
--- a/jbatch/src/main/java/org/apache/batchee/container/services/persistence/JPAPersistenceManagerService.java
+++ b/jbatch/src/main/java/org/apache/batchee/container/services/persistence/JPAPersistenceManagerService.java
@@ -63,6 +63,7 @@
import java.util.Map;
import java.util.Properties;
import java.util.Set;
+import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -166,6 +167,22 @@
}
@Override
+ public Set<String> getJobNames() {
+ Set<String> jobNames = new TreeSet<String>();
+ final EntityManager em = emProvider.newEntityManager();
+
+ try {
+ final List<String> list = em.createNamedQuery(JobInstanceEntity.Queries.FIND_JOBNAMES, String.class)
+ .setParameter("pattern", PartitionedStepBuilder.JOB_ID_SEPARATOR + "%")
+ .getResultList();
+ jobNames.addAll(list);
+ } finally {
+ emProvider.release(em);
+ }
+ return jobNames;
+ }
+
+ @Override
public JobStatus getJobStatusFromExecution(final long executionId) {
final EntityManager em = emProvider.newEntityManager();
try {
diff --git a/jbatch/src/main/java/org/apache/batchee/container/services/persistence/MemoryPersistenceManagerService.java b/jbatch/src/main/java/org/apache/batchee/container/services/persistence/MemoryPersistenceManagerService.java
index a2165f8..78d5e68 100644
--- a/jbatch/src/main/java/org/apache/batchee/container/services/persistence/MemoryPersistenceManagerService.java
+++ b/jbatch/src/main/java/org/apache/batchee/container/services/persistence/MemoryPersistenceManagerService.java
@@ -144,6 +144,17 @@
}
@Override
+ public Set<String> getJobNames() {
+ Set<String> jobNames = new HashSet<String>();
+ for (final Structures.JobInstanceData jobInstanceData : data.jobInstanceData.values()) {
+ if (jobInstanceData.instance.getJobName() != null && !jobInstanceData.instance.getJobName().startsWith(PartitionedStepBuilder.JOB_ID_SEPARATOR)) {
+ jobNames.add(jobInstanceData.instance.getJobName());
+ }
+ }
+ return jobNames;
+ }
+
+ @Override
public List<Long> jobOperatorGetJobInstanceIds(final String jobName, final int start, final int count) {
return jobOperatorGetJobInstanceIds(jobName, null, start, count);
}
diff --git a/jbatch/src/main/java/org/apache/batchee/container/services/persistence/jdbc/Dictionary.java b/jbatch/src/main/java/org/apache/batchee/container/services/persistence/jdbc/Dictionary.java
index 33b7608..8e24433 100644
--- a/jbatch/src/main/java/org/apache/batchee/container/services/persistence/jdbc/Dictionary.java
+++ b/jbatch/src/main/java/org/apache/batchee/container/services/persistence/jdbc/Dictionary.java
@@ -20,7 +20,7 @@
import org.apache.batchee.container.services.persistence.jdbc.database.Database;
public class Dictionary {
- public static interface SQL { // needs to be kept aligned with JPA mapping, we can't use reflection to find fields since order can change between executions with java 7
+ public interface SQL { // needs to be kept aligned with JPA mapping, we can't use reflection to find fields since order can change between executions with java 7
String CREATE_TABLE = "create table ";
String INSERT_INTO = "insert into ";
String SELECT = "select ";
@@ -45,6 +45,7 @@
String JOB_INSTANCE_COUNT = JOB_INSTANCE_COUNT_FROM_NAME + " and %s = ?";
String JOB_INSTANCE_IDS = SELECT + "%s" + FROM + "%s" + WHERE + "%s = ? and %s = ? order by %s desc";
String JOB_INSTANCE_IDS_FROM_NAME = SELECT + "%s" + FROM + "%s" + WHERE + " %s = ? order by %s desc";
+ String JOB_NAMES = SELECT + "distinct %s" + FROM + "%s" + WHERE + "%s not like '%s'";
String EXTERNAL_JOB_INSTANCE = SELECT + "distinct %s, %s" + FROM + "%s" + WHERE + "%s not like '%s'";
String JOB_INSTANCE_CREATE = INSERT_INTO + "%s" + "(%s, %s) VALUES(?, ?)";
String JOB_INSTANCE_CREATE_WITH_JOB_XML = INSERT_INTO + "%s" + "(%s, %s, %s) VALUES(?, ?, ?)";
@@ -112,6 +113,7 @@
private final String countJobInstanceByNameAndTag;
private final String findJoBInstanceIds;
private final String findJobInstanceIdsByName;
+ private final String findJobNames;
private final String findExternalJobInstances;
private final String createJobInstance;
private final String createJobInstanceWithJobXml;
@@ -199,6 +201,7 @@
this.findJoBInstanceIds = String.format(SQL.JOB_INSTANCE_IDS, jobInstanceColumns[0], jobInstanceTable, jobInstanceColumns[3],
jobInstanceColumns[8], jobInstanceColumns[0]);
this.findJobInstanceIdsByName = String.format(SQL.JOB_INSTANCE_IDS_FROM_NAME, jobInstanceColumns[0], jobInstanceTable, jobInstanceColumns[3], jobInstanceColumns[0]);
+ this.findJobNames = String.format(SQL.JOB_NAMES, jobInstanceColumns[3], jobInstanceTable, jobInstanceColumns[3], PartitionedStepBuilder.JOB_ID_SEPARATOR + "%");
this.findExternalJobInstances = String.format(SQL.EXTERNAL_JOB_INSTANCE, jobInstanceColumns[0], jobInstanceColumns[3], jobInstanceTable,
jobInstanceColumns[3], PartitionedStepBuilder.JOB_ID_SEPARATOR + "%");
this.createJobInstance = String.format(SQL.JOB_INSTANCE_CREATE, jobInstanceTable, jobInstanceColumns[3], jobInstanceColumns[8]);
@@ -365,6 +368,10 @@
return findExternalJobInstances;
}
+ public String getFindJobNames() {
+ return findJobNames;
+ }
+
public String getCreateJobInstance() {
return createJobInstance;
}
diff --git a/jbatch/src/main/java/org/apache/batchee/container/services/persistence/jpa/domain/JobInstanceEntity.java b/jbatch/src/main/java/org/apache/batchee/container/services/persistence/jpa/domain/JobInstanceEntity.java
index a4e8862..c005d5f 100644
--- a/jbatch/src/main/java/org/apache/batchee/container/services/persistence/jpa/domain/JobInstanceEntity.java
+++ b/jbatch/src/main/java/org/apache/batchee/container/services/persistence/jpa/domain/JobInstanceEntity.java
@@ -39,6 +39,7 @@
@NamedQuery(name = JobInstanceEntity.Queries.COUNT_BY_NAME, query = "select count(j) from JobInstanceEntity j where j.name = :name"),
@NamedQuery(name = JobInstanceEntity.Queries.FIND_FROM_EXECUTION, query = "select j from JobInstanceEntity j inner join j.executions e where e.executionId = :executionId"),
@NamedQuery(name = JobInstanceEntity.Queries.FIND_EXTERNALS, query = "select j from JobInstanceEntity j where j.name not like :pattern"),
+ @NamedQuery(name = JobInstanceEntity.Queries.FIND_JOBNAMES, query = "select distinct(j.name) from JobInstanceEntity j where j.name not like :pattern"),
@NamedQuery(name = JobInstanceEntity.Queries.FIND_BY_NAME_AND_TAG, query = "select j from JobInstanceEntity j where j.name = :name and j.tag = :tag"),
@NamedQuery(name = JobInstanceEntity.Queries.FIND_BY_NAME, query = "select j from JobInstanceEntity j where j.name = :name"),
@NamedQuery(name = JobInstanceEntity.Queries.DELETE_BY_INSTANCE_ID, query = "delete from JobInstanceEntity e where e.jobInstanceId = :instanceId"),
@@ -48,12 +49,13 @@
})
@Table(name=JobInstanceEntity.TABLE_NAME)
public class JobInstanceEntity {
- public static interface Queries {
+ public interface Queries {
String COUNT_BY_NAME_AND_TAG = "org.apache.batchee.container.services.persistence.jpa.domain.JobInstanceEntity.countByNameAndTag";
String COUNT_BY_NAME = "org.apache.batchee.container.services.persistence.jpa.domain.JobInstanceEntity.countByName";
String FIND_BY_NAME = "org.apache.batchee.container.services.persistence.jpa.domain.JobInstanceEntity.findByName";
String FIND_BY_NAME_AND_TAG = "org.apache.batchee.container.services.persistence.jpa.domain.JobInstanceEntity.findByNameAndTag";
String FIND_EXTERNALS = "org.apache.batchee.container.services.persistence.jpa.domain.JobInstanceEntity.findExternals";
+ String FIND_JOBNAMES = "org.apache.batchee.container.services.persistence.jpa.domain.JobInstanceEntity.findJobNames";
String FIND_FROM_EXECUTION = "org.apache.batchee.container.services.persistence.jpa.domain.JobInstanceEntity.findByExecution";
String DELETE_BY_INSTANCE_ID = "org.apache.batchee.container.services.persistence.jpa.domain.JobInstanceEntity.deleteFromInstanceId";
String DELETE_BY_DATE = "org.apache.batchee.container.services.persistence.jpa.domain.JobInstanceEntity.deleteByDate";
diff --git a/jbatch/src/main/java/org/apache/batchee/container/services/security/DefaultSecurityService.java b/jbatch/src/main/java/org/apache/batchee/container/services/security/DefaultSecurityService.java
index f827226..0ace389 100644
--- a/jbatch/src/main/java/org/apache/batchee/container/services/security/DefaultSecurityService.java
+++ b/jbatch/src/main/java/org/apache/batchee/container/services/security/DefaultSecurityService.java
@@ -35,6 +35,11 @@
}
@Override
+ public boolean isAuthorizedJobName(String jobName) {
+ return isDefaultUserAuthorized();
+ }
+
+ @Override
public String getLoggedUser() {
return defaultUser;
}
diff --git a/jbatch/src/main/java/org/apache/batchee/container/services/security/JAASSecurityService.java b/jbatch/src/main/java/org/apache/batchee/container/services/security/JAASSecurityService.java
index 8891ae5..b97dea8 100644
--- a/jbatch/src/main/java/org/apache/batchee/container/services/security/JAASSecurityService.java
+++ b/jbatch/src/main/java/org/apache/batchee/container/services/security/JAASSecurityService.java
@@ -51,6 +51,11 @@
}
@Override
+ public boolean isAuthorizedJobName(String jobName) {
+ return isAuthenticatedAndAuthorized("read");
+ }
+
+ @Override
public String getLoggedUser() {
final Subject subject = getSubject();
if (subject != null) {
diff --git a/jbatch/src/main/java/org/apache/batchee/spi/PersistenceManagerService.java b/jbatch/src/main/java/org/apache/batchee/spi/PersistenceManagerService.java
index a50e10a..0613ea0 100755
--- a/jbatch/src/main/java/org/apache/batchee/spi/PersistenceManagerService.java
+++ b/jbatch/src/main/java/org/apache/batchee/spi/PersistenceManagerService.java
@@ -49,6 +49,11 @@
int jobOperatorGetJobInstanceCount(String jobName, String appTag);
+ Set<String> getJobNames();
+
+ /**
+ * @deprecated replaced by {@link #getJobNames()}
+ */
Map<Long, String> jobOperatorGetExternalJobInstanceData();
List<Long> jobOperatorGetJobInstanceIds(String jobName, int start, int count);
diff --git a/jbatch/src/main/java/org/apache/batchee/spi/SecurityService.java b/jbatch/src/main/java/org/apache/batchee/spi/SecurityService.java
index cc9623f..c32dbdf 100644
--- a/jbatch/src/main/java/org/apache/batchee/spi/SecurityService.java
+++ b/jbatch/src/main/java/org/apache/batchee/spi/SecurityService.java
@@ -21,6 +21,12 @@
boolean isAuthorized(String perm);
/**
+ * @return whether the current user is allowed to see the given jobName
+ * @see javax.batch.operations.JobOperator#getJobNames()
+ */
+ boolean isAuthorizedJobName(String jobName);
+
+ /**
* @return logged user if exists or a default name for anonymous launches
*/
String getLoggedUser();