Updated OperationMonitor
git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/portlets/user/tabular-data-gwt-service@99226 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
parent
0dc3ddff6a
commit
a78ae2f365
|
@ -32,6 +32,8 @@ import org.gcube.portlets.user.td.gwtservice.shared.monitor.GroupByMonitor;
|
|||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.LabelColumnMonitor;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.MergeColumnMonitor;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.NormalizationMonitor;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.OperationMonitor;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.OperationMonitorSession;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.ReplaceBatchColumnMonitor;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.ReplaceColumnMonitor;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.RollBackSessionMonitor;
|
||||
|
@ -1076,4 +1078,15 @@ public interface TDGWTService extends RemoteService {
|
|||
DenormalizationSession denormalizationSession)
|
||||
throws TDGWTServiceException;
|
||||
|
||||
|
||||
// Operation Monitor
|
||||
/**
|
||||
* Get Operation Monitor
|
||||
*
|
||||
* @return
|
||||
* @throws TDGWTServiceException
|
||||
*/
|
||||
public OperationMonitor getOperationMonitor(OperationMonitorSession operationMonitorSession)
|
||||
throws TDGWTServiceException;
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,9 @@ import org.gcube.portlets.user.td.gwtservice.shared.monitor.ExtractCodelistMonit
|
|||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.GroupByMonitor;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.LabelColumnMonitor;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.MergeColumnMonitor;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.OperationMonitorSession;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.NormalizationMonitor;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.OperationMonitor;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.ReplaceBatchColumnMonitor;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.ReplaceColumnMonitor;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.monitor.RollBackSessionMonitor;
|
||||
|
@ -135,6 +137,7 @@ public interface TDGWTServiceAsync {
|
|||
void getTableValidationsMetadata(TRId trId,AsyncCallback<TabValidationsMetadata> callback);
|
||||
void getValidationColumns(TRId trId, String columnName, AsyncCallback<ArrayList<ColumnData>> callback);
|
||||
|
||||
|
||||
//RollBack
|
||||
void rollBack(RollBackSession rollBackSession,AsyncCallback<Void> callback);
|
||||
void getRollBackMonitor(AsyncCallback<RollBackSessionMonitor> callback);
|
||||
|
@ -282,4 +285,8 @@ public interface TDGWTServiceAsync {
|
|||
void getDenormalizationMonitor(AsyncCallback<DenormalizationMonitor> callback);
|
||||
void startDenormalization(DenormalizationSession denormalizationSession, AsyncCallback<Void> callback);
|
||||
|
||||
//Operation Monitor
|
||||
void getOperationMonitor(OperationMonitorSession operationMonitorSession, AsyncCallback<OperationMonitor> callback);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -6,11 +6,14 @@ public class SessionConstants {
|
|||
protected static final String TDOPEN_SESSION = "TDOPEN_SESSION";
|
||||
protected static final String TABULAR_RESOURCE_LIST = "TABULAR_RESOURCE_LIST";
|
||||
|
||||
protected static final String OPERATIONS_TASKS="OPERATION_TASKS";
|
||||
|
||||
protected static final String TR_TASK_MANAGER = "TR_TASK_MANAGER";
|
||||
|
||||
protected static final String SDMX_REGISTRY_SOURCE = "SDMX_REGISTRY_SOURCE";
|
||||
|
||||
|
||||
|
||||
protected static final String SDMX_CLIENT_ATTRIBUTE = "SDMX_CLIENT";
|
||||
protected static final String SDMX_IMPORT_SESSION = "SDMX_IMPORT";
|
||||
protected static final String SDMX_IMPORT_TABULAR_RESOURCE = "SDMX_IMPORT_TABULAR_RESOURCE";
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package org.gcube.portlets.user.td.gwtservice.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
@ -2179,7 +2180,48 @@ public class SessionUtil {
|
|||
}
|
||||
|
||||
|
||||
public static Task getTaskById(HttpSession httpSession, String taskId){
|
||||
Task task=null;
|
||||
|
||||
if(taskId==null|| taskId.isEmpty()){
|
||||
logger.error("TaskId is not valid: "+taskId);
|
||||
return task;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<String,Task> tasks= (HashMap<String, Task>) httpSession.getAttribute(SessionConstants.OPERATIONS_TASKS);
|
||||
if(tasks==null){
|
||||
logger.error("Task with id="+taskId+ " was not acquired");
|
||||
return task;
|
||||
}
|
||||
|
||||
task=tasks.get(taskId);
|
||||
if(task== null){
|
||||
logger.error("Task with id="+taskId+ " was not acquired");
|
||||
}
|
||||
return task;
|
||||
};
|
||||
|
||||
|
||||
|
||||
public static void setTaskById(HttpSession httpSession, Task task) {
|
||||
if(task==null){
|
||||
logger.error("Task is null");
|
||||
return;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<String,Task> tasks=((HashMap<String, Task>) httpSession.getAttribute(SessionConstants.OPERATIONS_TASKS));
|
||||
if(tasks==null){
|
||||
tasks=new HashMap<String, Task>();
|
||||
tasks.put(task.getId().getValue(), task);
|
||||
} else {
|
||||
tasks.put(task.getId().getValue(), task);
|
||||
httpSession.removeAttribute(SessionConstants.OPERATIONS_TASKS);
|
||||
}
|
||||
httpSession.setAttribute(SessionConstants.OPERATIONS_TASKS, tasks);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package org.gcube.portlets.user.td.gwtservice.server.trservice;
|
||||
|
||||
import org.gcube.data.analysis.tabulardata.commons.webservice.types.WorkerStatus;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.task.WorkerState;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author "Giancarlo Panichi"
|
||||
* <a href="mailto:g.panichi@isti.cnr.it">g.panichi@isti.cnr.it</a>
|
||||
*
|
||||
*/
|
||||
public class WorkerStateMap {
|
||||
public static WorkerState map(WorkerStatus status) {
|
||||
switch (status) {
|
||||
case FAILED:
|
||||
return WorkerState.FAILED;
|
||||
case INITIALIZING:
|
||||
return WorkerState.INITIALIZING;
|
||||
case IN_PROGRESS:
|
||||
return WorkerState.IN_PROGRESS;
|
||||
case PENDING:
|
||||
return WorkerState.PENDING;
|
||||
case SUCCEDED:
|
||||
return WorkerState.SUCCEDED;
|
||||
case VALIDATING_DATA:
|
||||
return WorkerState.VALIDATING_DATA;
|
||||
default:
|
||||
return WorkerState.FAILED;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
package org.gcube.portlets.user.td.gwtservice.shared;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Tabular Data Service User Interface Operations Id
|
||||
*
|
||||
* <table>
|
||||
* <tr><td>CSVImport</td><td>100</td></tr>
|
||||
* <tr><td>CSVExport</td><td>101</td></tr>
|
||||
* <tr><td>SDMXCodelistImport</td><td>200</td></tr>
|
||||
* <tr><td>SDMXCodelistExport</td><td>201</td></tr>
|
||||
* <tr><td>SDMXDatasetImport</td><td>202</td></tr>
|
||||
* <tr><td>SDMXDatasetExport</td><td>203</td></tr>
|
||||
* <tr><td>JSONImport</td><td>300</td></tr>
|
||||
* <tr><td>JSONExport</td><td>301</td></tr>
|
||||
* <tr><td>ValidateCodelist</td><td>1000</td></tr>
|
||||
* <tr><td>ValidateDataset</td><td>1001</td></tr>
|
||||
* <tr><td>ChangeTableType</td><td>1002</td></tr>
|
||||
* <tr><td>CreateDatasetView</td><td>1003</td></tr>
|
||||
* <tr><td>RemoveColumn</td><td>1004</td></tr>
|
||||
* <tr><td>AddsAColumn</td><td>1005</td></tr>
|
||||
* <tr><td>ColumnNameAdd</td><td>1006</td></tr>
|
||||
* <tr><td>ColumnNameRemove</td><td>1007</td></tr>
|
||||
* <tr><td>TableNameAdd</td><td>1008</td></tr>
|
||||
* <tr><td>TableNameRemove</td><td>1009</td></tr>
|
||||
* <tr><td>ChangeToAnnotationColumn</td><td>2000</td></tr>
|
||||
* <tr><td>ChangeToAttributeColumn</td><td>2001</td></tr>
|
||||
* <tr><td>ChangeToMeasureColumn</td><td>2002</td></tr>
|
||||
* <tr><td>ChangeToCodeColumn</td><td>2003</td></tr>
|
||||
* <tr><td>ChangeToCodeName</td><td>2004</td></tr>
|
||||
* <tr><td>ChangeToCodeDescription</td><td>2005</td></tr>
|
||||
* <tr><td>ChangeToDimensionColumn</td><td>2006</td></tr>
|
||||
* <tr><td>ChangeToTimeDimensionColumn</td><td>2007</td></tr>
|
||||
* <tr><td>ModifyTuplesValuesByExpression</td><td>3000</td></tr>
|
||||
* <tr><td>ModifyTuplesValuesById</td><td>3001</td></tr>
|
||||
* <tr><td>ModifyTuplesValuesByValidation</td><td>3002</td></tr>
|
||||
* <tr><td>AddRow</td><td>3004</td></tr>
|
||||
* <tr><td>Denormalize</td><td>3005</td></tr>
|
||||
* <tr><td>GroupBy</td><td>3006</td></tr>
|
||||
* <tr><td>RemoveDuplicateTuples</td><td>3007</td></tr>
|
||||
* <tr><td>ReplaceColumnByExpression</td><td>3101</td></tr>
|
||||
* <tr><td>ReplaceById</td><td>3102</td></tr>
|
||||
* <tr><td>FilterByExpression</td><td>3201</td></tr>
|
||||
* <tr><td>RemoveRowById</td><td>3202</td></tr>
|
||||
* <tr><td>Union</td><td>3208</td></tr>
|
||||
* <tr><td>CodelistValidation</td><td>5001</td></tr>
|
||||
* <tr><td>ColumnTypeCastCheck</td><td>5002</td></tr>
|
||||
* <tr><td>DuplicateTupleValidation</td><td>5003</td></tr>
|
||||
* <tr><td>DuplicateValuesInColumnValidator</td><td>5004</td></tr>
|
||||
* <tr><td>PeriodFormatCheck</td><td>5005</td></tr>
|
||||
* <tr><td>ExpressionValidation</td><td>5006</td></tr>
|
||||
* <tr><td>AmbiguousExternalReferenceCheck</td><td>5007</td></tr>
|
||||
* <tr><td>DimensionColumnValidator</td><td>5010</td></tr>
|
||||
* <tr><td>ValidateTable</td><td>5011</td></tr>
|
||||
* <tr><td>ValidateDataSet</td><td>5012</td></tr>
|
||||
* <tr><td>ValidateGeneric</td><td>5013</td></tr>
|
||||
* <tr><td>ExtractCodelist</td><td>11001</td></tr>
|
||||
* </table>
|
||||
*
|
||||
* @author "Giancarlo Panichi"
|
||||
* <a href="mailto:g.panichi@isti.cnr.it">g.panichi@isti.cnr.it</a>
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
public enum UIOperationsId {
|
||||
CSVImport("100"),
|
||||
CSVExport("101"),
|
||||
CLONE("102"),
|
||||
SDMXCodelistImport("200"),
|
||||
SDMXCodelistExport("201"),
|
||||
SDMXDatasetImport("202"),
|
||||
SDMXDatasetExport("203"),
|
||||
JSONImport("300"),
|
||||
JSONExport("301"),
|
||||
ValidateCodelist("1000"),
|
||||
ValidateDataset("1001"),
|
||||
ChangeTableType("1002"),
|
||||
CreateDatasetView("1003"),
|
||||
RemoveColumn("1004"),
|
||||
AddColumn("1005"),
|
||||
ColumnNameAdd("1006"),
|
||||
ColumnNameRemove("1007"),
|
||||
TableNameAdd("1008"),
|
||||
TableNameRemove("1009"),
|
||||
ChangeToAnnotationColumn("2000"),
|
||||
ChangeToAttributeColumn("2001"),
|
||||
ChangeToMeasureColumn("2002"),
|
||||
ChangeToCodeColumn("2003"),
|
||||
ChangeToCodeName("2004"),
|
||||
ChangeToCodeDescription("2005"),
|
||||
ChangeToDimensionColumn("2006"),
|
||||
ChangeToTimeDimensionColumn("2007"),
|
||||
ModifyTuplesValuesByExpression("3000"),
|
||||
ModifyTuplesValuesById("3001"),
|
||||
ModifyTuplesValuesByValidation("3002"),
|
||||
AddRow("3004"),
|
||||
Denormalize("3005"),
|
||||
GroupBy("3006"),
|
||||
RemoveDuplicateTuples("3007"),
|
||||
Normalize("3008"),
|
||||
ReplaceColumnByExpression("3101"),
|
||||
ReplaceById("3102"),
|
||||
FilterByExpression("3201"),
|
||||
RemoveRowById("3202"),
|
||||
Union("3208"),
|
||||
CodelistValidation("5001"),
|
||||
ColumnTypeCastCheck("5002"),
|
||||
DuplicateTupleValidation("5003"),
|
||||
DuplicateValuesInColumnValidator("5004"),
|
||||
PeriodFormatCheck("5005"),
|
||||
ExpressionValidation("5006"),
|
||||
AmbiguousExternalReferenceCheck("5007"),
|
||||
DimensionColumnValidator("5010"),
|
||||
ValidateTable("5011"),
|
||||
ValidateDataSet("5012"),
|
||||
ValidateGeneric("5013"),
|
||||
StatisticalOperation("10001"),
|
||||
ExportToStatisticalOperation("10002"),
|
||||
ImportFromStatistical("10003"),
|
||||
ExtractCodelist("11001"),
|
||||
GuessCodelist("11002"),
|
||||
CodelistMappingImport("12001");
|
||||
|
||||
/**
|
||||
* @param text
|
||||
*/
|
||||
private UIOperationsId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
private final String id;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Long toLong(){
|
||||
return Long.valueOf(id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -5,62 +5,79 @@ package org.gcube.portlets.user.td.gwtservice.shared.monitor;
|
|||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.task.State;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.UIOperationsId;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.task.TaskS;
|
||||
import org.gcube.portlets.user.td.widgetcommonevent.shared.TRId;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author "Giancarlo Panichi"
|
||||
* <a href="mailto:g.panichi@isti.cnr.it">g.panichi@isti.cnr.it</a>
|
||||
* @author "Giancarlo Panichi" <a
|
||||
* href="mailto:g.panichi@isti.cnr.it">g.panichi@isti.cnr.it</a>
|
||||
*
|
||||
*/
|
||||
public class OperationMonitor implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 5378053063599667767L;
|
||||
|
||||
protected float progress;
|
||||
protected State status;
|
||||
protected String statusDescription;
|
||||
protected Throwable error;
|
||||
protected UIOperationsId operationId;
|
||||
protected String taskId;
|
||||
// protected float progress;
|
||||
// protected State status;
|
||||
// protected String statusDescription;
|
||||
protected TaskS task;
|
||||
protected boolean inBackground;
|
||||
protected boolean abort;
|
||||
protected TRId trId;
|
||||
protected String columnName;
|
||||
|
||||
public float getProgress(){
|
||||
return progress;
|
||||
};
|
||||
// protected String columnName;
|
||||
|
||||
public OperationMonitor() {
|
||||
|
||||
public State getStatus(){
|
||||
return status;
|
||||
}
|
||||
|
||||
public String getStatusDescription(){
|
||||
return statusDescription;
|
||||
public OperationMonitor(UIOperationsId operationId, String taskId) {
|
||||
this.operationId = operationId;
|
||||
this.taskId = taskId;
|
||||
}
|
||||
|
||||
public void setProgress(float progress) {
|
||||
this.progress = progress;
|
||||
public UIOperationsId getOperationId() {
|
||||
return operationId;
|
||||
}
|
||||
|
||||
public void setStatus(State status) {
|
||||
this.status = status;
|
||||
public void setOperationId(UIOperationsId operationId) {
|
||||
this.operationId = operationId;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = State.values()[status];
|
||||
public String getTaskId() {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setStatusDescription(String statusDescription) {
|
||||
this.statusDescription = statusDescription;
|
||||
public void setTaskId(String taskId) {
|
||||
this.taskId = taskId;
|
||||
}
|
||||
|
||||
public Throwable getError() {
|
||||
return error;
|
||||
public TaskS getTask() {
|
||||
return task;
|
||||
}
|
||||
|
||||
public void setError(Throwable error) {
|
||||
this.error = error;
|
||||
public void setTask(TaskS task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
public boolean isInBackground() {
|
||||
return inBackground;
|
||||
}
|
||||
|
||||
public void setInBackground(boolean inBackground) {
|
||||
this.inBackground = inBackground;
|
||||
}
|
||||
|
||||
public boolean isAbort() {
|
||||
return abort;
|
||||
}
|
||||
|
||||
public void setAbort(boolean abort) {
|
||||
this.abort = abort;
|
||||
}
|
||||
|
||||
public TRId getTrId() {
|
||||
|
@ -71,22 +88,11 @@ public class OperationMonitor implements Serializable {
|
|||
this.trId = trId;
|
||||
}
|
||||
|
||||
public String getColumnName() {
|
||||
return columnName;
|
||||
}
|
||||
|
||||
public void setColumnName(String columnName) {
|
||||
this.columnName = columnName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Monitor [progress=" + progress + ", status="
|
||||
+ status + ", statusDescription=" + statusDescription
|
||||
+ ", error=" + error + ", trId=" + trId + ", columnName="
|
||||
+ columnName + "]";
|
||||
return "OperationMonitor [operationId=" + operationId + ", taskId="
|
||||
+ taskId + ", task=" + task + ", inBackground=" + inBackground
|
||||
+ ", abort=" + abort + ", trId=" + trId + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,390 @@
|
|||
package org.gcube.portlets.user.td.gwtservice.shared.monitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.gcube.application.framework.core.session.ASLSession;
|
||||
import org.gcube.data.analysis.tabulardata.commons.utils.AuthorizationProvider;
|
||||
import org.gcube.data.analysis.tabulardata.commons.utils.AuthorizationToken;
|
||||
import org.gcube.data.analysis.tabulardata.commons.webservice.types.TaskStatus;
|
||||
import org.gcube.data.analysis.tabulardata.model.metadata.table.DatasetViewTableMetadata;
|
||||
import org.gcube.data.analysis.tabulardata.model.table.Table;
|
||||
import org.gcube.data.analysis.tabulardata.service.TabularDataService;
|
||||
import org.gcube.data.analysis.tabulardata.service.impl.TabularDataServiceFactory;
|
||||
import org.gcube.data.analysis.tabulardata.service.operation.Job;
|
||||
import org.gcube.data.analysis.tabulardata.service.operation.Task;
|
||||
import org.gcube.data.analysis.tabulardata.service.operation.ValidationJob;
|
||||
import org.gcube.data.analysis.tabulardata.service.tabular.TabularResource;
|
||||
import org.gcube.data.analysis.tabulardata.service.tabular.TabularResourceId;
|
||||
import org.gcube.portlets.user.td.gwtservice.server.SessionUtil;
|
||||
import org.gcube.portlets.user.td.gwtservice.server.trservice.TaskStateMap;
|
||||
import org.gcube.portlets.user.td.gwtservice.server.trservice.WorkerStateMap;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.UIOperationsId;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.exception.TDGWTServiceException;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.exception.TDGWTSessionExpiredException;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.task.JobS;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.task.TaskS;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.task.ValidationsJobS;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.tr.TabResource;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.tr.clone.CloneTabularResourceSession;
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.tr.union.UnionSession;
|
||||
import org.gcube.portlets.user.td.widgetcommonevent.shared.TRId;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author "Giancarlo Panichi" email: <a
|
||||
* href="mailto:g.panichi@isti.cnr.it">g.panichi@isti.cnr.it</a>
|
||||
*
|
||||
*/
|
||||
public class OperationMonitorCreator {
|
||||
protected static Logger logger = LoggerFactory
|
||||
.getLogger(OperationMonitorCreator.class);
|
||||
|
||||
protected HttpSession session;
|
||||
protected Task task;
|
||||
protected OperationMonitorSession operationMonitorSession;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param task
|
||||
* @param startTRId
|
||||
* @param operationMonitorSession
|
||||
*/
|
||||
public OperationMonitorCreator(HttpSession session, Task task,
|
||||
OperationMonitorSession operationMonitorSession) {
|
||||
this.session=session;
|
||||
this.task = task;
|
||||
this.operationMonitorSession = operationMonitorSession;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
* @throws TDGWTServiceException
|
||||
*/
|
||||
public OperationMonitor create() throws TDGWTServiceException {
|
||||
OperationMonitor operationMonitor = new OperationMonitor(
|
||||
operationMonitorSession.getOperationId(),
|
||||
operationMonitorSession.getTaskId());
|
||||
|
||||
if (task == null) {
|
||||
logger.debug("Task is null");
|
||||
throw new TDGWTServiceException(
|
||||
"Error in Operation Monitor task is null");
|
||||
} else {
|
||||
operationMonitor.setTaskId(task.getId().getValue());
|
||||
|
||||
TaskStatus status = task.getStatus();
|
||||
if (status == null) {
|
||||
logger.debug("Services TaskStatus : null");
|
||||
throw new TDGWTServiceException(
|
||||
"Error in OperationMonitor Status is null");
|
||||
} else {
|
||||
TaskS taskS = createTaskS();
|
||||
operationMonitor.setTask(taskS);
|
||||
}
|
||||
SessionUtil.setTaskById(session, task);
|
||||
postOperation(operationMonitor);
|
||||
}
|
||||
|
||||
return operationMonitor;
|
||||
}
|
||||
|
||||
protected TaskS createTaskS() {
|
||||
TaskS taskS = new TaskS();
|
||||
|
||||
ArrayList<JobS> jobSList = new ArrayList<JobS>();
|
||||
int i = 1;
|
||||
for (Job job : task.getTaskJobs()) {
|
||||
|
||||
ArrayList<ValidationsJobS> validationsJobS = new ArrayList<ValidationsJobS>();
|
||||
int j = 1;
|
||||
for (ValidationJob valJob : job.getValidationJobs()) {
|
||||
|
||||
ValidationsJobS validationJ = new ValidationsJobS(
|
||||
String.valueOf(j), WorkerStateMap.map(valJob
|
||||
.getStatus()), valJob.getProgress(),
|
||||
valJob.getDescription(), valJob.getErrorMessage(),
|
||||
valJob.getHumaReadableStatus());
|
||||
validationsJobS.add(validationJ);
|
||||
}
|
||||
|
||||
JobS jobS = new JobS(String.valueOf(i), job.getProgress(),
|
||||
job.getHumaReadableStatus(), job.getDescription(),
|
||||
WorkerStateMap.map(job.getStatus()), job.getErrorMessage(),
|
||||
validationsJobS);
|
||||
|
||||
jobSList.add(jobS);
|
||||
j++;
|
||||
|
||||
}
|
||||
|
||||
|
||||
taskS = new TaskS(task.getId().getValue(), task.getProgress(),
|
||||
TaskStateMap.map(task.getStatus()), task.getErrorCause(), task.getSubmitter(),
|
||||
task.getStartTime(), task.getEndTime(), jobSList);
|
||||
|
||||
logger.debug("Retrieved task information");
|
||||
return taskS;
|
||||
}
|
||||
|
||||
|
||||
protected void postOperation(OperationMonitor operationMonitor) throws TDGWTServiceException {
|
||||
TRId startTRId=retrieveTabularResourceIdFromOperation();
|
||||
|
||||
// Table table;
|
||||
TRId trId;
|
||||
TabResource tabResource;
|
||||
switch (operationMonitor.getTask().getState()) {
|
||||
case FAILED:
|
||||
if (task.getResult() != null) {
|
||||
logger.debug("Task exception: " + task.getErrorCause());
|
||||
task.getErrorCause().printStackTrace();
|
||||
} else {
|
||||
logger.debug("Task exception: Error In Operation no Error Cause present");
|
||||
|
||||
}
|
||||
break;
|
||||
case SUCCEDED:
|
||||
logger.debug("Task Result:" + task.getResult());
|
||||
trId = new TRId();
|
||||
trId.setId(startTRId.getId());
|
||||
trId = retrieveTabularResourceBasicData(trId);
|
||||
|
||||
operationMonitor.setTrId(trId);
|
||||
tabResource = SessionUtil.getTabResource(session);
|
||||
tabResource.setTrId(trId);
|
||||
SessionUtil.setTabResource(session, tabResource);
|
||||
SessionUtil.setTRId(session, trId);
|
||||
break;
|
||||
case IN_PROGRESS:
|
||||
break;
|
||||
case VALIDATING_RULES:
|
||||
break;
|
||||
case GENERATING_VIEW:
|
||||
break;
|
||||
case ABORTED:
|
||||
break;
|
||||
case STOPPED:
|
||||
logger.debug("Task Result:" + task.getResult());
|
||||
trId = new TRId();
|
||||
trId.setId(startTRId.getId());
|
||||
trId = retrieveTabularResourceBasicData(trId);
|
||||
|
||||
operationMonitor.setTrId(trId);
|
||||
tabResource = SessionUtil.getTabResource(session);
|
||||
tabResource.setTrId(trId);
|
||||
SessionUtil.setTabResource(session, tabResource);
|
||||
SessionUtil.setTRId(session, trId);
|
||||
break;
|
||||
case INITIALIZING:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
protected TRId retrieveTabularResourceBasicData(TRId trId)
|
||||
throws TDGWTServiceException {
|
||||
try {
|
||||
ASLSession aslSession = SessionUtil.getAslSession(session);
|
||||
|
||||
AuthorizationProvider.instance.set(new AuthorizationToken(
|
||||
aslSession.getUsername(), aslSession.getScope()));
|
||||
TabularDataService service = TabularDataServiceFactory.getService();
|
||||
TabularResourceId tabularResourceId = new TabularResourceId(
|
||||
new Long(trId.getId()));
|
||||
|
||||
TabularResource tr = service.getTabularResource(tabularResourceId);
|
||||
Table table = service.getLastTable(tabularResourceId);
|
||||
|
||||
Table viewTable = null;
|
||||
|
||||
if (table.contains(DatasetViewTableMetadata.class)) {
|
||||
DatasetViewTableMetadata dwm = table
|
||||
.getMetadata(DatasetViewTableMetadata.class);
|
||||
try {
|
||||
viewTable = service.getTable(dwm
|
||||
.getTargetDatasetViewTableId());
|
||||
} catch (Exception e) {
|
||||
logger.error("view table not found");
|
||||
}
|
||||
}
|
||||
|
||||
TRId newTRId;
|
||||
if (viewTable == null) {
|
||||
newTRId = new TRId(String.valueOf(tr.getId().getValue()),
|
||||
tr.getTableType(), String.valueOf(table.getId()
|
||||
.getValue()), table.getTableType().getName());
|
||||
|
||||
} else {
|
||||
newTRId = new TRId(String.valueOf(tr.getId().getValue()),
|
||||
tr.getTableType(), String.valueOf(viewTable.getId()
|
||||
.getValue()), viewTable.getTableType()
|
||||
.getName(), String.valueOf(table.getId()
|
||||
.getValue()), true);
|
||||
|
||||
}
|
||||
|
||||
logger.debug("Retrieved TRId basic info:" + newTRId.toString());
|
||||
return newTRId;
|
||||
|
||||
} catch (TDGWTSessionExpiredException e) {
|
||||
throw e;
|
||||
} catch (SecurityException e) {
|
||||
e.printStackTrace();
|
||||
throw new TDGWTServiceException(
|
||||
"Security exception, you haven't rights!");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new TDGWTServiceException("Error in Client Library Request: "
|
||||
+ e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected TRId retrieveTabularResourceIdFromOperation() {
|
||||
TRId trId = null;
|
||||
|
||||
UIOperationsId operationId = operationMonitorSession.getOperationId();
|
||||
switch (operationId) {
|
||||
case AddColumn:
|
||||
break;
|
||||
case AddRow:
|
||||
break;
|
||||
case AmbiguousExternalReferenceCheck:
|
||||
break;
|
||||
case CLONE:
|
||||
CloneTabularResourceSession cloneTabularResourceSession = SessionUtil
|
||||
.getCloneTabularResourceSession(session);
|
||||
trId = cloneTabularResourceSession.getTrId();
|
||||
break;
|
||||
case CSVExport:
|
||||
break;
|
||||
case CSVImport:
|
||||
break;
|
||||
case ChangeTableType:
|
||||
break;
|
||||
case ChangeToAnnotationColumn:
|
||||
break;
|
||||
case ChangeToAttributeColumn:
|
||||
break;
|
||||
case ChangeToCodeColumn:
|
||||
break;
|
||||
case ChangeToCodeDescription:
|
||||
break;
|
||||
case ChangeToCodeName:
|
||||
break;
|
||||
case ChangeToDimensionColumn:
|
||||
break;
|
||||
case ChangeToMeasureColumn:
|
||||
break;
|
||||
case ChangeToTimeDimensionColumn:
|
||||
break;
|
||||
case CodelistMappingImport:
|
||||
break;
|
||||
case CodelistValidation:
|
||||
break;
|
||||
case ColumnNameAdd:
|
||||
break;
|
||||
case ColumnNameRemove:
|
||||
break;
|
||||
case ColumnTypeCastCheck:
|
||||
break;
|
||||
case CreateDatasetView:
|
||||
break;
|
||||
case Denormalize:
|
||||
break;
|
||||
case DimensionColumnValidator:
|
||||
break;
|
||||
case DuplicateTupleValidation:
|
||||
break;
|
||||
case DuplicateValuesInColumnValidator:
|
||||
break;
|
||||
case ExportToStatisticalOperation:
|
||||
break;
|
||||
case ExpressionValidation:
|
||||
break;
|
||||
case ExtractCodelist:
|
||||
break;
|
||||
case FilterByExpression:
|
||||
break;
|
||||
case GroupBy:
|
||||
break;
|
||||
case GuessCodelist:
|
||||
break;
|
||||
case ImportFromStatistical:
|
||||
break;
|
||||
case JSONExport:
|
||||
break;
|
||||
case JSONImport:
|
||||
break;
|
||||
case ModifyTuplesValuesByExpression:
|
||||
break;
|
||||
case ModifyTuplesValuesById:
|
||||
break;
|
||||
case ModifyTuplesValuesByValidation:
|
||||
break;
|
||||
case Normalize:
|
||||
break;
|
||||
case PeriodFormatCheck:
|
||||
break;
|
||||
case RemoveColumn:
|
||||
break;
|
||||
case RemoveDuplicateTuples:
|
||||
break;
|
||||
case RemoveRowById:
|
||||
break;
|
||||
case ReplaceById:
|
||||
break;
|
||||
case ReplaceColumnByExpression:
|
||||
break;
|
||||
case SDMXCodelistExport:
|
||||
break;
|
||||
case SDMXCodelistImport:
|
||||
break;
|
||||
case SDMXDatasetExport:
|
||||
break;
|
||||
case SDMXDatasetImport:
|
||||
break;
|
||||
case StatisticalOperation:
|
||||
break;
|
||||
case TableNameAdd:
|
||||
break;
|
||||
case TableNameRemove:
|
||||
break;
|
||||
case Union:
|
||||
UnionSession unionSession = SessionUtil.getUnionSession(session);
|
||||
trId = unionSession.getTrId();
|
||||
break;
|
||||
case ValidateCodelist:
|
||||
break;
|
||||
case ValidateDataSet:
|
||||
break;
|
||||
case ValidateDataset:
|
||||
break;
|
||||
case ValidateGeneric:
|
||||
break;
|
||||
case ValidateTable:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return trId;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package org.gcube.portlets.user.td.gwtservice.shared.monitor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.gcube.portlets.user.td.gwtservice.shared.UIOperationsId;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author "Giancarlo Panichi"
|
||||
* email: <a href="mailto:g.panichi@isti.cnr.it">g.panichi@isti.cnr.it</a>
|
||||
*
|
||||
*/
|
||||
public class OperationMonitorSession implements Serializable {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 7998971732364151219L;
|
||||
|
||||
protected UIOperationsId operationId;
|
||||
protected String taskId;
|
||||
protected boolean inBackground;
|
||||
protected boolean abort;
|
||||
|
||||
public OperationMonitorSession(){
|
||||
|
||||
}
|
||||
|
||||
public OperationMonitorSession(UIOperationsId operationId){
|
||||
this.operationId=operationId;
|
||||
taskId=null;
|
||||
inBackground=false;
|
||||
abort=false;
|
||||
}
|
||||
|
||||
public OperationMonitorSession(UIOperationsId operationId,String taskId){
|
||||
this.operationId=operationId;
|
||||
this.taskId=taskId;
|
||||
inBackground=false;
|
||||
abort=false;
|
||||
}
|
||||
|
||||
public UIOperationsId getOperationId() {
|
||||
return operationId;
|
||||
}
|
||||
|
||||
public void setOperationId(UIOperationsId operationId) {
|
||||
this.operationId = operationId;
|
||||
}
|
||||
|
||||
public String getTaskId() {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public void setTaskId(String taskId) {
|
||||
this.taskId = taskId;
|
||||
}
|
||||
|
||||
public boolean isInBackground() {
|
||||
return inBackground;
|
||||
}
|
||||
|
||||
public void setInBackground(boolean inBackground) {
|
||||
this.inBackground = inBackground;
|
||||
}
|
||||
|
||||
public boolean isAbort() {
|
||||
return abort;
|
||||
}
|
||||
|
||||
public void setAbort(boolean abort) {
|
||||
this.abort = abort;
|
||||
}
|
||||
|
||||
public static long getSerialversionuid() {
|
||||
return serialVersionUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MonitorSession [operationId=" + operationId + ", taskId="
|
||||
+ taskId + ", inBackground=" + inBackground + ", abort="
|
||||
+ abort + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -20,20 +20,61 @@ public class JobS implements Serializable {
|
|||
protected String description;
|
||||
protected InvocationS invocation;
|
||||
protected ArrayList<Validations> validations;
|
||||
|
||||
protected Throwable errorMessage;
|
||||
protected WorkerState workerState;
|
||||
protected ArrayList<ValidationsJobS> validationsJobS;
|
||||
|
||||
public JobS() {
|
||||
|
||||
}
|
||||
|
||||
public JobS(String id, float progress, String humaReadableStatus, String description,
|
||||
ArrayList<Validations> validations, InvocationS invocation) {
|
||||
/**
|
||||
* For Validation Tasks
|
||||
*
|
||||
* @param id
|
||||
* @param progress
|
||||
* @param humaReadableStatus
|
||||
* @param description
|
||||
* @param validations
|
||||
* @param invocation
|
||||
*/
|
||||
public JobS(String id, float progress, String humaReadableStatus,
|
||||
String description, ArrayList<Validations> validations,
|
||||
InvocationS invocation) {
|
||||
this.id = id;
|
||||
this.progress = progress;
|
||||
this.humaReadableStatus = humaReadableStatus;
|
||||
this.description = description;
|
||||
this.validations = validations;
|
||||
this.invocation = invocation;
|
||||
validationsJobS = null;
|
||||
errorMessage = null;
|
||||
validationsJobS = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* For Operation Monitor
|
||||
*
|
||||
* @param id
|
||||
* @param progress
|
||||
* @param humaReadableStatus
|
||||
* @param description
|
||||
* @param errorMessage
|
||||
* @param workerState
|
||||
* @param validationsJobs
|
||||
*/
|
||||
public JobS(String id, float progress, String humaReadableStatus,
|
||||
String description, WorkerState workerState,
|
||||
Throwable errorMessage, ArrayList<ValidationsJobS> validationsJobs) {
|
||||
this.id = id;
|
||||
this.progress = progress;
|
||||
this.humaReadableStatus = humaReadableStatus;
|
||||
this.description = description;
|
||||
this.validationsJobS = validationsJobs;
|
||||
this.errorMessage = errorMessage;
|
||||
this.workerState = workerState;
|
||||
this.validations = null;
|
||||
this.invocation = null;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
|
@ -84,16 +125,38 @@ public class JobS implements Serializable {
|
|||
this.invocation = invocation;
|
||||
}
|
||||
|
||||
public Throwable getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public void setErrorMessage(Throwable errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
|
||||
public WorkerState getWorkerState() {
|
||||
return workerState;
|
||||
}
|
||||
|
||||
public void setWorkerState(WorkerState workerState) {
|
||||
this.workerState = workerState;
|
||||
}
|
||||
|
||||
public ArrayList<ValidationsJobS> getValidationsJobS() {
|
||||
return validationsJobS;
|
||||
}
|
||||
|
||||
public void setValidationsJobS(ArrayList<ValidationsJobS> validationsJobS) {
|
||||
this.validationsJobS = validationsJobS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JobS [id=" + id + ", progress=" + progress
|
||||
+ ", humaReadableStatus=" + humaReadableStatus
|
||||
+ ", description=" + description + ", invocation=" + invocation
|
||||
+ ", validations=" + validations + "]";
|
||||
+ ", validations=" + validations + ", errorMessage="
|
||||
+ errorMessage + ", workerState=" + workerState
|
||||
+ ", validationsJobS=" + validationsJobS + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ public class TaskS implements Serializable {
|
|||
protected String id;
|
||||
protected float progress;
|
||||
protected State state;
|
||||
protected Throwable errorCause;
|
||||
protected String submitter;
|
||||
protected Date startTime;
|
||||
protected Date endTime;
|
||||
|
@ -25,11 +26,23 @@ public class TaskS implements Serializable {
|
|||
|
||||
}
|
||||
|
||||
public TaskS(String id, float progress, State state, String submitter,
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
* @param progress
|
||||
* @param state
|
||||
* @param errorCause
|
||||
* @param submitter
|
||||
* @param startTime
|
||||
* @param endTime
|
||||
* @param jobs
|
||||
*/
|
||||
public TaskS(String id, float progress, State state, Throwable errorCause, String submitter,
|
||||
Date startTime, Date endTime, ArrayList<JobS> jobs) {
|
||||
this.id = id;
|
||||
this.progress = progress;
|
||||
this.state = state;
|
||||
this.errorCause=errorCause;
|
||||
this.submitter = submitter;
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
|
@ -60,6 +73,14 @@ public class TaskS implements Serializable {
|
|||
this.state = state;
|
||||
}
|
||||
|
||||
public Throwable getErrorCause() {
|
||||
return errorCause;
|
||||
}
|
||||
|
||||
public void setErrorCause(Throwable errorCause) {
|
||||
this.errorCause = errorCause;
|
||||
}
|
||||
|
||||
public String getSubmitter() {
|
||||
return submitter;
|
||||
}
|
||||
|
@ -94,9 +115,12 @@ public class TaskS implements Serializable {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "STask [id=" + id + ", progress=" + progress + ", state="
|
||||
+ state + ", submitter=" + submitter + ", startTime="
|
||||
+ startTime + ", endTime=" + endTime + ", jobs=" + jobs + "]";
|
||||
return "TaskS [id=" + id + ", progress=" + progress + ", state="
|
||||
+ state + ", errorCause=" + errorCause + ", submitter="
|
||||
+ submitter + ", startTime=" + startTime + ", endTime="
|
||||
+ endTime + ", jobs=" + jobs + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
package org.gcube.portlets.user.td.gwtservice.shared.task;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author "Giancarlo Panichi" email: <a
|
||||
* href="mailto:g.panichi@isti.cnr.it">g.panichi@isti.cnr.it</a>
|
||||
*
|
||||
*/
|
||||
public class ValidationsJobS implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 5763629588700935290L;
|
||||
|
||||
protected String id;// For grid only
|
||||
protected WorkerState workerState;
|
||||
protected float progress;
|
||||
protected String description;
|
||||
protected Throwable errorMessage;
|
||||
protected String humanReadableStatus;
|
||||
|
||||
public ValidationsJobS() {
|
||||
|
||||
}
|
||||
|
||||
public ValidationsJobS(String id, WorkerState workerState, float progress,
|
||||
String description, Throwable errorMessage,
|
||||
String humanReadableStatus) {
|
||||
this.id = id;
|
||||
this.workerState = workerState;
|
||||
this.progress = progress;
|
||||
this.description = description;
|
||||
this.errorMessage = errorMessage;
|
||||
this.humanReadableStatus = humanReadableStatus;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public WorkerState getWorkerState() {
|
||||
return workerState;
|
||||
}
|
||||
|
||||
public void setWorkerState(WorkerState workerState) {
|
||||
this.workerState = workerState;
|
||||
}
|
||||
|
||||
public float getProgress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
public void setProgress(float progress) {
|
||||
this.progress = progress;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Throwable getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public void setErrorMessage(Throwable errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
|
||||
public String getHumanReadableStatus() {
|
||||
return humanReadableStatus;
|
||||
}
|
||||
|
||||
public void setHumanReadableStatus(String humanReadableStatus) {
|
||||
this.humanReadableStatus = humanReadableStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ValidationsJobS [id=" + id + ", workerState=" + workerState
|
||||
+ ", progress=" + progress + ", description=" + description
|
||||
+ ", errorMessage=" + errorMessage + ", humanReadableStatus="
|
||||
+ humanReadableStatus + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package org.gcube.portlets.user.td.gwtservice.shared.task;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author "Giancarlo Panichi"
|
||||
* email: <a href="mailto:g.panichi@isti.cnr.it">g.panichi@isti.cnr.it</a>
|
||||
*
|
||||
*/
|
||||
public enum WorkerState {
|
||||
|
||||
PENDING, INITIALIZING, VALIDATING_DATA, IN_PROGRESS, SUCCEDED, FAILED
|
||||
}
|
Loading…
Reference in New Issue