Merge pull request 'new-is-app-with-new-msro' (#13) from new-is-app-with-new-msro into new-is-app
Reviewed-on: #13
This commit is contained in:
commit
8c3ae35dc4
|
@ -20,6 +20,12 @@
|
|||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>eu.dnetlib.dhp</groupId>
|
||||
<artifactId>dnet-wf-service</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>eu.dnetlib.dhp</groupId>
|
||||
<artifactId>dnet-data-services</artifactId>
|
||||
|
|
|
@ -20,7 +20,11 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
|
|||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@EnableJpaRepositories(entityManagerFactoryRef = "mainEntityManagerFactory", transactionManagerRef = "mainTransactionManager", basePackages = {
|
||||
"eu.dnetlib.is", "eu.dnetlib.data.mdstore", "eu.dnetlib.msro"
|
||||
"eu.dnetlib.is",
|
||||
"eu.dnetlib.common",
|
||||
"eu.dnetlib.manager.history",
|
||||
"eu.dnetlib.manager.wf",
|
||||
"eu.dnetlib.data.mdstore"
|
||||
})
|
||||
public class MainDBConfig {
|
||||
|
||||
|
@ -38,7 +42,7 @@ public class MainDBConfig {
|
|||
@Qualifier("mainDataSource") final DataSource ds) {
|
||||
return builder
|
||||
.dataSource(ds)
|
||||
.packages("eu.dnetlib.is.model", "eu.dnetlib.msro.model", "eu.dnetlib.data.mdstore.model")
|
||||
.packages("eu.dnetlib.is.model", "eu.dnetlib.manager.history.model", "eu.dnetlib.common.model", "eu.dnetlib.manager.wf.model", "eu.dnetlib.data.mdstore.model")
|
||||
.persistenceUnit("is")
|
||||
.build();
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ public class ZeppelinAjaxController extends AbstractDnetController {
|
|||
@GetMapping("/templates")
|
||||
public List<String> getTemplates() throws MDStoreManagerException {
|
||||
try {
|
||||
// if (zeppelinClient.get)
|
||||
return zeppelinClient.listTemplates();
|
||||
} catch (final Throwable e) {
|
||||
throw new MDStoreManagerException("Zeppelin is unreachable", e);
|
||||
|
|
|
@ -40,9 +40,9 @@ public class DsmAjaxController extends AbstractDnetController {
|
|||
private ProtocolService protocolService;
|
||||
|
||||
@GetMapping("/browsableFields")
|
||||
public List<KeyValue> browsableFields() {
|
||||
public List<KeyValue<String>> browsableFields() {
|
||||
return Arrays.stream(DsmBrowsableFields.values())
|
||||
.map(f -> new KeyValue(f.name(), f.desc))
|
||||
.map(f -> new KeyValue<>(f.name(), f.desc))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package eu.dnetlib.is.email;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import eu.dnetlib.common.controller.AbstractDnetController;
|
||||
import eu.dnetlib.common.model.EmailTemplate;
|
||||
import eu.dnetlib.notifications.mail.EmailService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/ajax/templates/email")
|
||||
public class EmailTemplateController extends AbstractDnetController {
|
||||
|
||||
@Autowired
|
||||
protected EmailService emailService;
|
||||
|
||||
@GetMapping("/")
|
||||
public List<EmailTemplate> listEmailTemplates() {
|
||||
return emailService.listEmailTemplates();
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
public List<EmailTemplate> saveEmailTemplate(@RequestBody final EmailTemplate email) {
|
||||
emailService.saveEmailTemplate(email);
|
||||
return emailService.listEmailTemplates();
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public List<EmailTemplate> deleteEmailTemplate(@PathVariable final String id) {
|
||||
emailService.deleteEmailTemplate(id);
|
||||
return emailService.listEmailTemplates();
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package eu.dnetlib.is.importer;
|
||||
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
|
@ -47,7 +47,7 @@ public class OldProfilesImporter {
|
|||
final Document doc = DocumentHelper.parseText(xml);
|
||||
|
||||
final String id = StringUtils.substringBefore(doc.valueOf("//RESOURCE_IDENTIFIER/@value"), "_");
|
||||
final Date now = new Date();
|
||||
final LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
final SimpleResource res = new SimpleResource();
|
||||
res.setId(id);
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package eu.dnetlib.is.importer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
|
@ -17,8 +19,8 @@ import org.springframework.stereotype.Service;
|
|||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import eu.dnetlib.msro.history.repository.WfProcessExecutionRepository;
|
||||
import eu.dnetlib.msro.model.history.WfProcessExecution;
|
||||
import eu.dnetlib.manager.history.model.WfProcessExecution;
|
||||
import eu.dnetlib.manager.history.repository.WfProcessExecutionRepository;
|
||||
|
||||
@Service
|
||||
public class WfHistoryImporter {
|
||||
|
@ -53,8 +55,10 @@ public class WfHistoryImporter {
|
|||
wf.setDsApi(node.get("dataprovider:interface").asText());
|
||||
}
|
||||
|
||||
wf.setStartDate(new Date(NumberUtils.toLong(node.get("system:startDate").asText())));
|
||||
wf.setEndDate(new Date(NumberUtils.toLong(node.get("system:endDate").asText())));
|
||||
wf.setStartDate(LocalDateTime
|
||||
.ofInstant(Instant.ofEpochMilli(NumberUtils.toLong(node.get("system:startDate").asText())), TimeZone.getDefault().toZoneId()));
|
||||
|
||||
wf.setEndDate(LocalDateTime.ofInstant(Instant.ofEpochMilli(NumberUtils.toLong(node.get("system:endDate").asText())), TimeZone.getDefault().toZoneId()));
|
||||
|
||||
if (BooleanUtils.toBoolean(node.get("system:isCompletedSuccessfully").asText())) {
|
||||
wf.setStatus("success");
|
||||
|
|
|
@ -56,30 +56,30 @@ public class InfoAjaxController extends AbstractDnetController {
|
|||
return res;
|
||||
}
|
||||
|
||||
private InfoSection<KeyValue> jvm() {
|
||||
final InfoSection<KeyValue> jvm = new InfoSection<>("JVM");
|
||||
jvm.getData().add(new KeyValue("JVM Name", mxbean.getVmName()));
|
||||
jvm.getData().add(new KeyValue("JVM Vendor", mxbean.getVmVendor()));
|
||||
jvm.getData().add(new KeyValue("JVM Version", mxbean.getVmVersion()));
|
||||
jvm.getData().add(new KeyValue("JVM Spec Name", mxbean.getSpecName()));
|
||||
jvm.getData().add(new KeyValue("JVM Spec Vendor", mxbean.getSpecVendor()));
|
||||
jvm.getData().add(new KeyValue("JVM Spec Version", mxbean.getSpecVersion()));
|
||||
jvm.getData().add(new KeyValue("Running JVM Name", mxbean.getName()));
|
||||
jvm.getData().add(new KeyValue("Management Spec Version", mxbean.getManagementSpecVersion()));
|
||||
private InfoSection<KeyValue<String>> jvm() {
|
||||
final InfoSection<KeyValue<String>> jvm = new InfoSection<>("JVM");
|
||||
jvm.getData().add(new KeyValue<>("JVM Name", mxbean.getVmName()));
|
||||
jvm.getData().add(new KeyValue<>("JVM Vendor", mxbean.getVmVendor()));
|
||||
jvm.getData().add(new KeyValue<>("JVM Version", mxbean.getVmVersion()));
|
||||
jvm.getData().add(new KeyValue<>("JVM Spec Name", mxbean.getSpecName()));
|
||||
jvm.getData().add(new KeyValue<>("JVM Spec Vendor", mxbean.getSpecVendor()));
|
||||
jvm.getData().add(new KeyValue<>("JVM Spec Version", mxbean.getSpecVersion()));
|
||||
jvm.getData().add(new KeyValue<>("Running JVM Name", mxbean.getName()));
|
||||
jvm.getData().add(new KeyValue<>("Management Spec Version", mxbean.getManagementSpecVersion()));
|
||||
return jvm;
|
||||
}
|
||||
|
||||
private InfoSection<KeyValue> args() {
|
||||
final InfoSection<KeyValue> libs = new InfoSection<>("Arguments");
|
||||
libs.getData().add(new KeyValue("Input arguments", StringUtils.join(mxbean.getInputArguments(), " ")));
|
||||
private InfoSection<KeyValue<String>> args() {
|
||||
final InfoSection<KeyValue<String>> libs = new InfoSection<>("Arguments");
|
||||
libs.getData().add(new KeyValue<>("Input arguments", StringUtils.join(mxbean.getInputArguments(), " ")));
|
||||
return libs;
|
||||
}
|
||||
|
||||
private List<InfoSection<KeyValue>> props() {
|
||||
final List<InfoSection<KeyValue>> res = new ArrayList<>();
|
||||
private List<InfoSection<KeyValue<?>>> props() {
|
||||
final List<InfoSection<KeyValue<?>>> res = new ArrayList<>();
|
||||
|
||||
configurableEnvironment.getPropertySources().forEach(ps -> {
|
||||
final InfoSection<KeyValue> section = new InfoSection<>("Properties: " + ps.getName());
|
||||
final InfoSection<KeyValue<?>> section = new InfoSection<>("Properties: " + ps.getName());
|
||||
addAllProperties(section, ps);
|
||||
res.add(section);
|
||||
});
|
||||
|
@ -87,13 +87,13 @@ public class InfoAjaxController extends AbstractDnetController {
|
|||
return res;
|
||||
}
|
||||
|
||||
private void addAllProperties(final InfoSection<KeyValue> res, final PropertySource<?> ps) {
|
||||
private void addAllProperties(final InfoSection<KeyValue<?>> res, final PropertySource<?> ps) {
|
||||
if (ps instanceof CompositePropertySource) {
|
||||
final CompositePropertySource cps = (CompositePropertySource) ps;
|
||||
cps.getPropertySources().forEach(x -> addAllProperties(res, x));
|
||||
} else if (ps instanceof EnumerablePropertySource<?>) {
|
||||
final EnumerablePropertySource<?> eps = (EnumerablePropertySource<?>) ps;
|
||||
Arrays.asList(eps.getPropertyNames()).forEach(k -> res.getData().add(new KeyValue(k, eps.getProperty(k))));
|
||||
Arrays.asList(eps.getPropertyNames()).forEach(k -> res.getData().add(new KeyValue<>(k, eps.getProperty(k))));
|
||||
} else {}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package eu.dnetlib.is.info;
|
||||
|
||||
public class KeyValue {
|
||||
public class KeyValue<T> {
|
||||
|
||||
private final String k;
|
||||
private final Object v;
|
||||
private final T v;
|
||||
|
||||
public KeyValue(final String k, final Object v) {
|
||||
public KeyValue(final String k, final T v) {
|
||||
this.k = k;
|
||||
this.v = v;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ public class KeyValue {
|
|||
return k;
|
||||
}
|
||||
|
||||
public Object getV() {
|
||||
public T getV() {
|
||||
return v;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,11 +25,12 @@ public class ResourceAjaxController extends AbstractResourceController {
|
|||
@PostMapping("/")
|
||||
public SimpleResource newResource(@RequestParam final String name,
|
||||
@RequestParam final String type,
|
||||
@RequestParam(required = false, defaultValue = "") final String subtype,
|
||||
@RequestParam(required = false, defaultValue = "") final String description,
|
||||
@RequestParam final String content)
|
||||
throws InformationServiceException {
|
||||
|
||||
return service.saveNewResource(name, type, description, content);
|
||||
return service.saveNewResource(name, type, subtype, description, content);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{resId}")
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package eu.dnetlib.manager.wf;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import eu.dnetlib.common.controller.AbstractDnetController;
|
||||
import eu.dnetlib.manager.history.WorkflowLogger;
|
||||
import eu.dnetlib.manager.history.model.WfProcessExecution;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/ajax/wf_history")
|
||||
public class WfHistoryAjaxController extends AbstractDnetController {
|
||||
|
||||
@Autowired
|
||||
private WorkflowLogger logger;
|
||||
|
||||
@GetMapping("/")
|
||||
public List<WfProcessExecution> history(
|
||||
@RequestParam(required = true) final int total,
|
||||
@RequestParam(required = false) final Long from,
|
||||
@RequestParam(required = false) final Long to) {
|
||||
return logger.history(total, from, to);
|
||||
}
|
||||
|
||||
@GetMapping("/{processId}")
|
||||
public WfProcessExecution getProcessExecution(@PathVariable final String processId) {
|
||||
return logger.getProcessExecution(processId);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package eu.dnetlib.manager.wf;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import eu.dnetlib.common.controller.AbstractDnetController;
|
||||
import eu.dnetlib.is.info.KeyValue;
|
||||
import eu.dnetlib.manager.wf.model.WorkflowInstance;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/ajax/wf_instances")
|
||||
public class WfInstancesController extends AbstractDnetController {
|
||||
|
||||
private WorkflowManagerService wfManagerService;
|
||||
|
||||
@GetMapping("/instance/{id}")
|
||||
public WorkflowInstance getWfInstance(@PathVariable final String id) throws Exception {
|
||||
return wfManagerService.findWorkflowInstance(id);
|
||||
}
|
||||
|
||||
@GetMapping("/search")
|
||||
public List<KeyValue<String>> listWfInstances(@RequestParam final String section) throws Exception {
|
||||
return wfManagerService.streamWfInstancesBySection(section)
|
||||
.map(x -> new KeyValue<>(x.getId(), x.getName()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@GetMapping("/sections")
|
||||
public List<KeyValue<Long>> listWfFamilies() throws Exception {
|
||||
return wfManagerService.streamSections()
|
||||
.map(x -> new KeyValue<>(x.getValue(), x.getCount()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
package eu.dnetlib.msro.history;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import eu.dnetlib.msro.history.repository.WfProcessExecutionRepository;
|
||||
import eu.dnetlib.msro.model.history.WfProcessExecution;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/ajax/wfs")
|
||||
public class WfHistoryAjaxController {
|
||||
|
||||
@Autowired
|
||||
private WfProcessExecutionRepository wfProcessExecutionRepository;
|
||||
|
||||
@Deprecated
|
||||
public static final int MAX_NUMBER_OF_RECENT_WFS = 100;
|
||||
|
||||
@GetMapping("/")
|
||||
public List<WfProcessExecution> history(
|
||||
@RequestParam(required = true) final int total,
|
||||
@RequestParam(required = false) final Long from,
|
||||
@RequestParam(required = false) final Long to) {
|
||||
if (from == null && to == null) {
|
||||
return wfProcessExecutionRepository.findAll(PageRequest.of(0, total, Sort.by("endDate").descending())).toList();
|
||||
} else if (from == null) {
|
||||
return wfProcessExecutionRepository.findByEndDateBetweenOrderByEndDateDesc(new Date(0), new Date(to));
|
||||
} else if (to == null) {
|
||||
return wfProcessExecutionRepository.findByEndDateBetweenOrderByEndDateDesc(new Date(from), new Date());
|
||||
} else {
|
||||
return wfProcessExecutionRepository.findByEndDateBetweenOrderByEndDateDesc(new Date(from), new Date(to));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{processId}")
|
||||
public WfProcessExecution getProcess(@PathVariable final String processId) {
|
||||
return wfProcessExecutionRepository.findById(processId).get();
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,8 @@ server.port=8280
|
|||
server.public_url =
|
||||
server.public_desc = API Base URL
|
||||
|
||||
dnet.configuration.infrastructure = LOCAL DEV
|
||||
|
||||
spring.profiles.active=dev
|
||||
|
||||
maven.pom.path = /META-INF/maven/eu.dnetlib.dhp/dnet-is-application/effective-pom.xml
|
||||
|
@ -57,5 +59,12 @@ dhp.mdstore-manager.hadoop.zeppelin.login =
|
|||
dhp.mdstore-manager.hadoop.zeppelin.password =
|
||||
dhp.mdstore-manager.hadoop.zeppelin.name-prefix = mdstoreManager
|
||||
|
||||
|
||||
# Email Configuration
|
||||
dnet.configuration.mail.sender.email =
|
||||
dnet.configuration.mail.sender.name =
|
||||
dnet.configuration.mail.cc =
|
||||
dnet.configuration.mail.smtp.host =
|
||||
dnet.configuration.mail.smtp.port = 25
|
||||
dnet.configuration.mail.smtp.user =
|
||||
dnet.configuration.mail.smtp.password =
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ import { ContextViewerComponent, ContextsComponent } from './contexts/contexts.c
|
|||
import { DsmSearchComponent, DsmResultsComponent, DsmApiComponent } from './dsm/dsm.component';
|
||||
import { MdstoreInspectorComponent, MdstoresComponent } from './mdstores/mdstores.component';
|
||||
import { CleanerTesterComponent } from './cleaner-tester/cleaner-tester.component';
|
||||
import { EmailsComponent } from './emails/emails.component';
|
||||
import { WfInstancesComponent } from './wf-instances/wf-instances.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: "", redirectTo: 'info', pathMatch: 'full' },
|
||||
|
@ -17,6 +19,8 @@ const routes: Routes = [
|
|||
{ path: "adv_resources/context", component: ContextsComponent },
|
||||
{ path: "adv_resources/vocabulary", component: VocabulariesComponent },
|
||||
{ path: "adv_resources/protocol", component: ProtocolsComponent },
|
||||
{ path: "adv_resources/email", component: EmailsComponent },
|
||||
{ path: "wfs", component: WfInstancesComponent },
|
||||
{ path: "wf_history", component: WfHistoryComponent },
|
||||
{ path: "ctx_viewer", component: ContextViewerComponent },
|
||||
{ path: "voc_editor", component: VocabularyEditorComponent },
|
||||
|
|
|
@ -36,6 +36,9 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|||
import { SpinnerHttpInterceptor } from './common/spinner.service';
|
||||
import { MdstoresComponent, MdstoreInspectorComponent, MDStoreVersionsDialog, AddMDStoreDialog } from './mdstores/mdstores.component';
|
||||
import { CleanerTesterComponent } from './cleaner-tester/cleaner-tester.component';
|
||||
import { EmailDialog, EmailsComponent } from './emails/emails.component';
|
||||
import { WfInstancesComponent } from './wf-instances/wf-instances.component';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -66,7 +69,10 @@ import { CleanerTesterComponent } from './cleaner-tester/cleaner-tester.componen
|
|||
MdstoreInspectorComponent,
|
||||
MDStoreVersionsDialog,
|
||||
AddMDStoreDialog,
|
||||
CleanerTesterComponent
|
||||
CleanerTesterComponent,
|
||||
EmailsComponent,
|
||||
EmailDialog,
|
||||
WfInstancesComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -95,7 +101,8 @@ import { CleanerTesterComponent } from './cleaner-tester/cleaner-tester.componen
|
|||
ReactiveFormsModule,
|
||||
MatSnackBarModule,
|
||||
MatPaginatorModule,
|
||||
MatProgressSpinnerModule
|
||||
MatProgressSpinnerModule,
|
||||
MatTabsModule
|
||||
],
|
||||
providers: [{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
|
|
|
@ -54,6 +54,7 @@ export interface SimpleResource {
|
|||
id: string,
|
||||
name: string,
|
||||
type: string,
|
||||
subtype?: string,
|
||||
description?: string,
|
||||
creationDate?: string,
|
||||
modificationDate?: string
|
||||
|
@ -198,3 +199,29 @@ export interface MDStoreRecord {
|
|||
dateOfTransformation: string,
|
||||
provenance: any
|
||||
}
|
||||
|
||||
export interface EmailTemplate {
|
||||
id: string,
|
||||
description: string,
|
||||
subject: string,
|
||||
message: string
|
||||
}
|
||||
|
||||
|
||||
export interface WfInstance {
|
||||
id: string,
|
||||
details: Map<string, string>,
|
||||
priority: number,
|
||||
dsId?: string,
|
||||
dsName?: string,
|
||||
apiId?: string,
|
||||
enabled: boolean,
|
||||
configured: boolean,
|
||||
schedulingEnabled: boolean,
|
||||
cronExpression?: string,
|
||||
cronMinInterval?: number,
|
||||
workflow: string,
|
||||
destroyWf?: string,
|
||||
systemParams: Map<string, string>,
|
||||
userParams: Map<string, string>
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
||||
import { Page, DsmConf, ResourceType, Protocol, WfHistoryEntry, SimpleResource, Context, ContextNode, Vocabulary, VocabularyTerm, KeyValue, BrowseTerm, Datasource, MDStore, MDStoreVersion, MDStoreRecord } from './is.model';
|
||||
import { Page, DsmConf, ResourceType, Protocol, WfHistoryEntry, SimpleResource, Context, ContextNode, Vocabulary, VocabularyTerm, KeyValue, BrowseTerm, Datasource, MDStore, MDStoreVersion, MDStoreRecord, EmailTemplate } from './is.model';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
|
@ -72,11 +72,12 @@ export class ISService {
|
|||
});
|
||||
}
|
||||
|
||||
addSimpleResource(name: string, type: string, description: string, content: string, onSuccess: Function, relatedForm?: FormGroup): void {
|
||||
addSimpleResource(name: string, type: string, subtype: string, description: string, content: string, onSuccess: Function, relatedForm?: FormGroup): void {
|
||||
const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
|
||||
let body = new HttpParams()
|
||||
.set('name', name)
|
||||
.set('type', type)
|
||||
.set('subtype', subtype)
|
||||
.set('description', description)
|
||||
.set('content', content);
|
||||
this.client.post<void>('/ajax/resources/', body, { headers: headers }).subscribe({
|
||||
|
@ -98,7 +99,7 @@ export class ISService {
|
|||
if (from && from > 0) { params = params.append('from', from); }
|
||||
if (to && to > 0) { params = params.append('to', to); }
|
||||
|
||||
this.client.get<WfHistoryEntry[]>('/ajax/wfs/', { params: params }).subscribe({
|
||||
this.client.get<WfHistoryEntry[]>('/ajax/wf_history/', { params: params }).subscribe({
|
||||
next: data => onSuccess(data),
|
||||
error: error => this.showError(error)
|
||||
});
|
||||
|
@ -328,6 +329,47 @@ export class ISService {
|
|||
});
|
||||
}
|
||||
|
||||
loadEmailTemplates(onSuccess: Function): void {
|
||||
this.client.get<void>('./ajax/templates/email/').subscribe({
|
||||
next: data => onSuccess(data),
|
||||
error: error => this.showError(error)
|
||||
});
|
||||
}
|
||||
|
||||
saveEmailTemplate(email: EmailTemplate, onSuccess: Function, relatedForm?: FormGroup): void {
|
||||
this.client.post<void>('./ajax/templates/email/', email).subscribe({
|
||||
next: data => onSuccess(data),
|
||||
error: error => this.showError(error, relatedForm)
|
||||
});
|
||||
}
|
||||
|
||||
deleteEmailTemplate(id: string, onSuccess: Function): void {
|
||||
this.client.delete<void>('./ajax/templates/email/' + encodeURIComponent(id)).subscribe({
|
||||
next: data => onSuccess(data),
|
||||
error: error => this.showError(error)
|
||||
});
|
||||
}
|
||||
|
||||
loadWfIntancesSections(onSuccess: Function): void {
|
||||
this.client.get<void>('./ajax/wf_instances/sections').subscribe({
|
||||
next: data => onSuccess(data),
|
||||
error: error => this.showError(error)
|
||||
});
|
||||
}
|
||||
|
||||
loadWfIntances(section: string, onSuccess: Function): void {
|
||||
this.client.get<void>('./ajax/wf_instances/search?section=' + encodeURIComponent(section)).subscribe({
|
||||
next: data => onSuccess(data),
|
||||
error: error => this.showError(error)
|
||||
});
|
||||
}
|
||||
|
||||
loadWfIntance(id: string, onSuccess: Function): void {
|
||||
this.client.get<void>('./ajax/wf_instances/instance/' + encodeURIComponent(id)).subscribe({
|
||||
next: data => onSuccess(data),
|
||||
error: error => this.showError(error)
|
||||
});
|
||||
}
|
||||
|
||||
private showError(error: any, form?: FormGroup) {
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<form [formGroup]="emailForm" (ngSubmit)="onSubmit()">
|
||||
|
||||
<h1 mat-dialog-title *ngIf="emailForm.get('id')?.value">Edit Email Template</h1>
|
||||
<h1 mat-dialog-title *ngIf="!emailForm.get('id')?.value">New Email Template</h1>
|
||||
|
||||
<div mat-dialog-content>
|
||||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%;" *ngIf="emailForm.get('id')?.value">
|
||||
<mat-label>ID</mat-label>
|
||||
<input matInput formControlName="id" readonly="readonly" />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%;">
|
||||
<mat-label>Description</mat-label>
|
||||
<input matInput formControlName="description" />
|
||||
<mat-error *ngIf="emailForm.get('description')?.invalid">This field is <strong>required</strong></mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%;">
|
||||
<mat-label>Email: subject</mat-label>
|
||||
<input matInput formControlName="subject" />
|
||||
<mat-error *ngIf="emailForm.get('subject')?.invalid">This field is <strong>required</strong></mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%;">
|
||||
<mat-label>Email: message</mat-label>
|
||||
<textarea matInput formControlName="message" required rows="16" style="font-size: 0.8em;"></textarea>
|
||||
<mat-error *ngIf="emailForm.get('message')?.invalid">This field is <strong>required</strong></mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
</div>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button mat-stroked-button color="primary" type="submit" [disabled]="!emailForm.valid">Submit</button>
|
||||
<button mat-stroked-button color="primary" mat-dialog-close>Close</button>
|
||||
<mat-error *ngIf="emailForm.errors?.['serverError']">
|
||||
{{ emailForm.errors?.['serverError'] }}
|
||||
</mat-error>
|
||||
</div>
|
||||
|
||||
</form>
|
|
@ -0,0 +1,42 @@
|
|||
<h2>Email Templates</h2>
|
||||
|
||||
<button mat-stroked-button color="primary" (click)="openAddEmailTemplateDialog()">
|
||||
<mat-icon fontIcon="add"></mat-icon>
|
||||
create a new template
|
||||
</button>
|
||||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%; margin-top: 10px;">
|
||||
<mat-label>Filter</mat-label>
|
||||
<input matInput (keyup)="applyFilter($event)" placeholder="Filter..." #input />
|
||||
</mat-form-field>
|
||||
|
||||
<table mat-table [dataSource]="emailsDatasource" matSort class="mat-elevation-z8">
|
||||
|
||||
<ng-container matColumnDef="id">
|
||||
<th mat-header-cell *matHeaderCellDef style="width: 25%;" mat-sort-header sortActionDescription="Sort by ID"> Id
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
<a (click)="openEditEmailTemplateDialog(element)">{{element.id}}</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="description">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header sortActionDescription="Sort by Description"> Description </th>
|
||||
<td mat-cell *matCellDef="let element"> {{element.description}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="buttons">
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: right;" style="width: 20%"></th>
|
||||
<td mat-cell *matCellDef="let element" class="table-buttons">
|
||||
<button mat-stroked-button color="warn" (click)="deleteEmailTemplate(element)">delete</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="colums"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: colums;"></tr>
|
||||
|
||||
<!-- Row shown when there is no matching data. -->
|
||||
<tr class="mat-row" *matNoDataRow>
|
||||
<td class="mat-cell" colspan="4" style="padding: 0 16px;">No data matching the filter "{{input.value}}"</td>
|
||||
</tr>
|
||||
</table>
|
|
@ -0,0 +1,98 @@
|
|||
import { AfterViewInit, Component, Inject, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { EmailTemplate } from '../common/is.model';
|
||||
import { ISService } from '../common/is.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-emails',
|
||||
templateUrl: './emails.component.html',
|
||||
styleUrls: ['./emails.component.css']
|
||||
})
|
||||
export class EmailsComponent implements OnInit, AfterViewInit {
|
||||
emailsDatasource: MatTableDataSource<EmailTemplate> = new MatTableDataSource<EmailTemplate>([]);
|
||||
|
||||
colums: string[] = ['id', 'description', 'buttons'];
|
||||
|
||||
@ViewChild(MatSort) sort: MatSort | undefined
|
||||
|
||||
searchText: string = '';
|
||||
|
||||
constructor(public service: ISService, public route: ActivatedRoute, public dialog: MatDialog) { }
|
||||
|
||||
ngOnInit() { this.reload() }
|
||||
ngAfterViewInit() { if (this.sort) this.emailsDatasource.sort = this.sort; }
|
||||
reload() { this.service.loadEmailTemplates((data: EmailTemplate[]) => this.emailsDatasource.data = data); }
|
||||
|
||||
applyFilter(event: Event) {
|
||||
const filterValue = (event.target as HTMLInputElement).value.trim().toLowerCase();
|
||||
this.emailsDatasource.filter = filterValue;
|
||||
}
|
||||
|
||||
openAddEmailTemplateDialog(): void {
|
||||
const dialogRef = this.dialog.open(EmailDialog, {
|
||||
data: {
|
||||
id: '',
|
||||
description: '',
|
||||
subject: '',
|
||||
message: ''
|
||||
},
|
||||
width: '80%'
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) this.reload();
|
||||
});
|
||||
}
|
||||
|
||||
openEditEmailTemplateDialog(email: EmailTemplate): void {
|
||||
const dialogRef = this.dialog.open(EmailDialog, {
|
||||
data: email,
|
||||
width: '80%'
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) this.reload();
|
||||
});
|
||||
}
|
||||
|
||||
deleteEmailTemplate(email: EmailTemplate) {
|
||||
if (confirm('Are you sure?')) {
|
||||
this.service.deleteEmailTemplate(email.id, (data: void) => this.reload());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'email-dialog',
|
||||
templateUrl: './email-dialog.html',
|
||||
styleUrls: ['./emails.component.css']
|
||||
})
|
||||
export class EmailDialog {
|
||||
|
||||
emailForm = new FormGroup({
|
||||
id: new FormControl(''),
|
||||
description: new FormControl('', [Validators.required]),
|
||||
subject: new FormControl('', [Validators.required]),
|
||||
message: new FormControl('', [Validators.required])
|
||||
});
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<EmailDialog>, @Inject(MAT_DIALOG_DATA) public data: any, public service: ISService) {
|
||||
this.emailForm.get('id')?.setValue(data.id);
|
||||
this.emailForm.get('description')?.setValue(data.description);
|
||||
this.emailForm.get('subject')?.setValue(data.subject);
|
||||
this.emailForm.get('message')?.setValue(data.message);
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
const email = Object.assign({}, this.data, this.emailForm.value);
|
||||
this.service.saveEmailTemplate(email, (data: void) => this.dialogRef.close(1), this.emailForm);
|
||||
}
|
||||
|
||||
onNoClick(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
}
|
|
@ -51,6 +51,15 @@
|
|||
</div>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>Workflows</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
<div>
|
||||
<a class="menu-item" routerLink="wfs">Workflows</a>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>Tools</mat-panel-title>
|
||||
|
|
|
@ -13,9 +13,14 @@
|
|||
<input matInput readonly value="{{data.type}}" />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%;">
|
||||
<mat-label>SubType (optional)</mat-label>
|
||||
<input matInput formControlName="subtype" />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%;">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput formControlName="name" required />
|
||||
<input matInput formControlName="name" />
|
||||
<mat-error *ngIf="metadataForm.get('name')?.invalid">This field is <strong>required</strong></mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
|
|
|
@ -5,10 +5,15 @@
|
|||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%;">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput formControlName="name" required />
|
||||
<input matInput formControlName="name" />
|
||||
<mat-error *ngIf="newResourceForm.get('name')?.invalid">This field is <strong>required</strong></mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%;">
|
||||
<mat-label>SubType (optional)</mat-label>
|
||||
<input matInput formControlName="subtype" />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%;">
|
||||
<mat-label>Description</mat-label>
|
||||
<textarea matInput formControlName="description" rows="2"></textarea>
|
||||
|
@ -16,7 +21,7 @@
|
|||
|
||||
<mat-form-field appearance="fill" floatLabel="always" style="width: 100%;">
|
||||
<mat-label>Content ({{data.contentType}})</mat-label>
|
||||
<textarea matInput formControlName="content" required rows="10" style="font-size: 0.8em;"></textarea>
|
||||
<textarea matInput formControlName="content" rows="10" style="font-size: 0.8em;"></textarea>
|
||||
<mat-error *ngIf="newResourceForm.get('content')?.invalid">This field is <strong>required</strong></mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
|
|
|
@ -12,14 +12,18 @@
|
|||
|
||||
<mat-card *ngFor="let r of resources | searchFilter: searchText" style="margin-top: 10px;">
|
||||
<mat-card-header>
|
||||
<mat-card-title title="{{r.id}}">{{r.name}} <span class="badge-label badge-info"
|
||||
style="font-size: 0.7em;">{{type.contentType}}</span></mat-card-title>
|
||||
<mat-card-title title="{{r.id}}">
|
||||
{{r.name}}
|
||||
<span class="badge-label badge-warning" style="font-size: 0.7em;" *ngIf="r.subtype">{{r.subtype}}</span>
|
||||
<span class="badge-label badge-info" style="font-size: 0.7em;">{{type.contentType}}</span>
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<p>{{r.description}}</p>
|
||||
<p class="muted small">
|
||||
<b>Id:</b> {{r.id}}<br /> <b>Creation date:</b> {{r.creationDate}}<br /> <b>Modification date:</b>
|
||||
{{r.modificationDate}}
|
||||
<b>Id:</b> {{r.id}}<br />
|
||||
<b>Creation date:</b> {{r.creationDate}}<br />
|
||||
<b>Modification date:</b> {{r.modificationDate}}
|
||||
</p>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
|
|
|
@ -3,7 +3,7 @@ import { ISService } from '../common/is.service';
|
|||
import { ActivatedRoute } from '@angular/router';
|
||||
import { MatDialog, MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { ResourceType, SimpleResource } from '../common/is.model';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-resources',
|
||||
|
@ -115,12 +115,16 @@ export class ResContentDialog {
|
|||
})
|
||||
export class ResMetadataDialog {
|
||||
metadataForm = new FormGroup({
|
||||
name: new FormControl(''),
|
||||
name: new FormControl('', [Validators.required]),
|
||||
subtype: new FormControl(''),
|
||||
description: new FormControl('')
|
||||
});
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<ResMetadataDialog>, @Inject(MAT_DIALOG_DATA) public data: any, public service: ISService) {
|
||||
this.metadataForm.get('name')?.setValue(data.name);
|
||||
if (data.subtype) {
|
||||
this.metadataForm.get('subtype')?.setValue(data.subtype);
|
||||
}
|
||||
if (data.description) {
|
||||
this.metadataForm.get('description')?.setValue(data.description);
|
||||
}
|
||||
|
@ -143,9 +147,10 @@ export class ResMetadataDialog {
|
|||
})
|
||||
export class ResCreateNewDialog {
|
||||
newResourceForm = new FormGroup({
|
||||
name: new FormControl(''),
|
||||
name: new FormControl('', [Validators.required]),
|
||||
subtype: new FormControl(''),
|
||||
description: new FormControl(''),
|
||||
content: new FormControl('')
|
||||
content: new FormControl('', [Validators.required])
|
||||
});
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<ResCreateNewDialog>, @Inject(MAT_DIALOG_DATA) public data: any, public service: ISService) { }
|
||||
|
@ -153,10 +158,11 @@ export class ResCreateNewDialog {
|
|||
onSubmit(): void {
|
||||
let name: string = this.newResourceForm.get('name')?.value!;
|
||||
let type: string = this.data.id!;
|
||||
let subtype: string = this.newResourceForm.get('subtype')?.value!;
|
||||
let description: string = this.newResourceForm.get('description')?.value!;
|
||||
let content: string = this.newResourceForm.get('content')?.value!;
|
||||
|
||||
this.service.addSimpleResource(name, type, description, content, (data: void) => this.dialogRef.close(1), this.newResourceForm);
|
||||
this.service.addSimpleResource(name, type, subtype, description, content, (data: void) => this.dialogRef.close(1), this.newResourceForm);
|
||||
}
|
||||
onNoClick(): void {
|
||||
this.dialogRef.close();
|
||||
|
|
|
@ -137,8 +137,6 @@ export class VocabularyEditorComponent implements OnInit, AfterViewInit {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Component({
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<h2>Workflow Instances</h2>
|
||||
|
||||
<mat-tab-group animationDuration="0ms">
|
||||
<mat-tab label="First">Content 1</mat-tab>
|
||||
<mat-tab label="Second">Content 2</mat-tab>
|
||||
<mat-tab label="Third">Content 3</mat-tab>
|
||||
</mat-tab-group>
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-wf-instances',
|
||||
templateUrl: './wf-instances.component.html',
|
||||
styleUrls: ['./wf-instances.component.css']
|
||||
})
|
||||
export class WfInstancesComponent {
|
||||
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
package eu.dnetlib.data.mdstore;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -112,9 +113,9 @@ public class MDStoreService {
|
|||
private MDStoreVersion newMDStoreVersion(final MDStore md, final boolean writing) {
|
||||
final MDStoreVersion v = new MDStoreVersion();
|
||||
|
||||
final Date now = new Date();
|
||||
final LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
final String versionId = md.getId() + "-" + now.getTime();
|
||||
final String versionId = md.getId() + "-" + now.toEpochSecond(ZoneOffset.UTC);
|
||||
v.setId(versionId);
|
||||
v.setMdstore(md.getId());
|
||||
v.setLastUpdate(null);
|
||||
|
@ -189,7 +190,7 @@ public class MDStoreService {
|
|||
mdstoreCurrentVersionRepository.save(MDStoreCurrentVersion.newInstance(v));
|
||||
v.setWriting(false);
|
||||
v.setSize(size);
|
||||
v.setLastUpdate(new Date());
|
||||
v.setLastUpdate(LocalDateTime.now());
|
||||
mdstoreVersionRepository.save(v);
|
||||
|
||||
return v;
|
||||
|
@ -258,7 +259,7 @@ public class MDStoreService {
|
|||
md.setLayout(layout);
|
||||
md.setType(type);
|
||||
md.setInterpretation(interpretation);
|
||||
md.setCreationDate(new Date());
|
||||
md.setCreationDate(LocalDateTime.now());
|
||||
md.setDatasourceName(dsName);
|
||||
md.setDatasourceId(dsId);
|
||||
md.setApiId(apiId);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package eu.dnetlib.data.mdstore.backends;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -49,8 +49,8 @@ public class MockBackend implements MDStoreBackend {
|
|||
rec.setOriginalId("mck-" + i);
|
||||
rec.setId("mock________::mck-" + i);
|
||||
rec.setBody("<RECORD>" + i + "</RECORD>");
|
||||
rec.setDateOfCollection(new Date().getTime());
|
||||
rec.setDateOfTransformation(new Date().getTime());
|
||||
rec.setDateOfCollection(Instant.now().toEpochMilli());
|
||||
rec.setDateOfTransformation(Instant.now().toEpochMilli());
|
||||
rec.setEncoding("XML");
|
||||
rec.setProvenance(MOCK_PROVENANCE);
|
||||
list.add(rec);
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package eu.dnetlib.common.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "emails")
|
||||
public class EmailTemplate implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8424437958140000626L;
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
private String id;
|
||||
|
||||
@Column(name = "description")
|
||||
private String description;
|
||||
|
||||
@Column(name = "subject")
|
||||
private String subject;
|
||||
|
||||
@Column(name = "message")
|
||||
private String message;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(final String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
public void setSubject(final String subject) {
|
||||
this.subject = subject;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(final String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package eu.dnetlib.data.mdstore.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
@ -12,8 +12,6 @@ import javax.persistence.EnumType;
|
|||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
|
@ -55,8 +53,7 @@ public class MDStore implements Serializable {
|
|||
private Map<String, Object> params = new LinkedHashMap<>();
|
||||
|
||||
@Column(name = "creation_date")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date creationDate;
|
||||
private LocalDateTime creationDate;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
@ -143,11 +140,11 @@ public class MDStore implements Serializable {
|
|||
this.params = params;
|
||||
}
|
||||
|
||||
public Date getCreationDate() {
|
||||
public LocalDateTime getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
public void setCreationDate(final Date creationDate) {
|
||||
public void setCreationDate(final LocalDateTime creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package eu.dnetlib.data.mdstore.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
@ -10,8 +10,6 @@ import javax.persistence.Column;
|
|||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
|
@ -36,8 +34,7 @@ public class MDStoreVersion implements Serializable {
|
|||
private int readCount = 0;
|
||||
|
||||
@Column(name = "lastupdate")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date lastUpdate;
|
||||
private LocalDateTime lastUpdate;
|
||||
|
||||
@Column(name = "size")
|
||||
private long size = 0;
|
||||
|
@ -78,11 +75,11 @@ public class MDStoreVersion implements Serializable {
|
|||
this.readCount = readCount;
|
||||
}
|
||||
|
||||
public Date getLastUpdate() {
|
||||
public LocalDateTime getLastUpdate() {
|
||||
return lastUpdate;
|
||||
}
|
||||
|
||||
public void setLastUpdate(final Date lastUpdate) {
|
||||
public void setLastUpdate(final LocalDateTime lastUpdate) {
|
||||
this.lastUpdate = lastUpdate;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package eu.dnetlib.data.mdstore.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
@ -12,8 +12,6 @@ import javax.persistence.EnumType;
|
|||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
|
@ -54,12 +52,10 @@ public class MDStoreWithInfo implements Serializable {
|
|||
private String currentVersion;
|
||||
|
||||
@Column(name = "creation_date")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date creationDate;
|
||||
private LocalDateTime creationDate;
|
||||
|
||||
@Column(name = "lastupdate")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date lastUpdate;
|
||||
private LocalDateTime lastUpdate;
|
||||
|
||||
@Column(name = "size")
|
||||
private long size = 0;
|
||||
|
@ -143,19 +139,19 @@ public class MDStoreWithInfo implements Serializable {
|
|||
this.currentVersion = currentVersion;
|
||||
}
|
||||
|
||||
public Date getCreationDate() {
|
||||
public LocalDateTime getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
public void setCreationDate(final Date creationDate) {
|
||||
public void setCreationDate(final LocalDateTime creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
public Date getLastUpdate() {
|
||||
public LocalDateTime getLastUpdate() {
|
||||
return lastUpdate;
|
||||
}
|
||||
|
||||
public void setLastUpdate(final Date lastUpdate) {
|
||||
public void setLastUpdate(final LocalDateTime lastUpdate) {
|
||||
this.lastUpdate = lastUpdate;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package eu.dnetlib.dsm.model;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -89,7 +90,7 @@ public class Datasource implements Serializable {
|
|||
|
||||
private String registeredby;
|
||||
|
||||
private Date registrationdate;
|
||||
private LocalDateTime registrationdate;
|
||||
|
||||
private String subjects;
|
||||
|
||||
|
@ -99,10 +100,10 @@ public class Datasource implements Serializable {
|
|||
private Boolean consentTermsOfUse;
|
||||
|
||||
@Column(name = "consenttermsofusedate")
|
||||
private Date consentTermsOfUseDate;
|
||||
private LocalDateTime consentTermsOfUseDate;
|
||||
|
||||
@Column(name = "lastconsenttermsofusedate")
|
||||
private Date lastConsentTermsOfUseDate;
|
||||
private LocalDateTime lastConsentTermsOfUseDate;
|
||||
|
||||
@Column(name = "fulltextdownload")
|
||||
private Boolean fullTextDownload;
|
||||
|
@ -401,11 +402,11 @@ public class Datasource implements Serializable {
|
|||
this.registeredby = registeredby;
|
||||
}
|
||||
|
||||
public Date getRegistrationdate() {
|
||||
public LocalDateTime getRegistrationdate() {
|
||||
return registrationdate;
|
||||
}
|
||||
|
||||
public void setRegistrationdate(final Date registrationdate) {
|
||||
public void setRegistrationdate(final LocalDateTime registrationdate) {
|
||||
this.registrationdate = registrationdate;
|
||||
}
|
||||
|
||||
|
@ -433,19 +434,19 @@ public class Datasource implements Serializable {
|
|||
this.consentTermsOfUse = consentTermsOfUse;
|
||||
}
|
||||
|
||||
public Date getConsentTermsOfUseDate() {
|
||||
public LocalDateTime getConsentTermsOfUseDate() {
|
||||
return consentTermsOfUseDate;
|
||||
}
|
||||
|
||||
public void setConsentTermsOfUseDate(final Date consentTermsOfUseDate) {
|
||||
public void setConsentTermsOfUseDate(final LocalDateTime consentTermsOfUseDate) {
|
||||
this.consentTermsOfUseDate = consentTermsOfUseDate;
|
||||
}
|
||||
|
||||
public Date getLastConsentTermsOfUseDate() {
|
||||
public LocalDateTime getLastConsentTermsOfUseDate() {
|
||||
return lastConsentTermsOfUseDate;
|
||||
}
|
||||
|
||||
public void setLastConsentTermsOfUseDate(final Date lastConsentTermsOfUseDate) {
|
||||
public void setLastConsentTermsOfUseDate(final LocalDateTime lastConsentTermsOfUseDate) {
|
||||
this.lastConsentTermsOfUseDate = lastConsentTermsOfUseDate;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package eu.dnetlib.dsm.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
|
@ -34,7 +34,7 @@ public class Organization implements Serializable {
|
|||
private String country;
|
||||
private String collectedfrom;
|
||||
|
||||
private Date dateofcollection;
|
||||
private LocalDateTime dateofcollection;
|
||||
private String provenanceaction;
|
||||
|
||||
@ManyToMany(cascade = {
|
||||
|
@ -98,11 +98,11 @@ public class Organization implements Serializable {
|
|||
this.collectedfrom = collectedfrom;
|
||||
}
|
||||
|
||||
public Date getDateofcollection() {
|
||||
public LocalDateTime getDateofcollection() {
|
||||
return dateofcollection;
|
||||
}
|
||||
|
||||
public void setDateofcollection(final Date dateofcollection) {
|
||||
public void setDateofcollection(final LocalDateTime dateofcollection) {
|
||||
this.dateofcollection = dateofcollection;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package eu.dnetlib.errors;
|
||||
|
||||
public class WorkflowManagerException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -9067581185191425823L;
|
||||
|
||||
public WorkflowManagerException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public WorkflowManagerException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -1,14 +1,12 @@
|
|||
package eu.dnetlib.is.model.resource;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
@Entity
|
||||
@Table(name = "resources")
|
||||
|
@ -26,16 +24,17 @@ public class SimpleResource implements Serializable {
|
|||
@Column(name = "type")
|
||||
private String type;
|
||||
|
||||
@Column(name = "subtype")
|
||||
private String subtype;
|
||||
|
||||
@Column(name = "description")
|
||||
private String description;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(name = "creation_date")
|
||||
private Date creationDate;
|
||||
private LocalDateTime creationDate;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(name = "modification_date")
|
||||
private Date modificationDate;
|
||||
private LocalDateTime modificationDate;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
|
@ -61,6 +60,14 @@ public class SimpleResource implements Serializable {
|
|||
this.type = type;
|
||||
}
|
||||
|
||||
public String getSubtype() {
|
||||
return subtype;
|
||||
}
|
||||
|
||||
public void setSubtype(final String subtype) {
|
||||
this.subtype = subtype;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
@ -69,19 +76,19 @@ public class SimpleResource implements Serializable {
|
|||
this.description = description;
|
||||
}
|
||||
|
||||
public Date getCreationDate() {
|
||||
public LocalDateTime getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
public void setCreationDate(final Date creationDate) {
|
||||
public void setCreationDate(final LocalDateTime creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
public Date getModificationDate() {
|
||||
public LocalDateTime getModificationDate() {
|
||||
return modificationDate;
|
||||
}
|
||||
|
||||
public void setModificationDate(final Date modificationDate) {
|
||||
public void setModificationDate(final LocalDateTime modificationDate) {
|
||||
this.modificationDate = modificationDate;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
package eu.dnetlib.msro.model.history;
|
||||
package eu.dnetlib.manager.history.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.hibernate.annotations.TypeDef;
|
||||
|
@ -32,6 +30,9 @@ public class WfProcessExecution implements Serializable {
|
|||
@Column(name = "process_id")
|
||||
private String processId;
|
||||
|
||||
@Column(name = "wf_instance_id")
|
||||
private String wfInstanceId;
|
||||
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
|
||||
|
@ -41,13 +42,11 @@ public class WfProcessExecution implements Serializable {
|
|||
@Column(name = "status")
|
||||
private String status;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(name = "start_date")
|
||||
private Date startDate;
|
||||
private LocalDateTime startDate;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(name = "end_date")
|
||||
private Date endDate;
|
||||
private LocalDateTime endDate;
|
||||
|
||||
@Column(name = "ds_id")
|
||||
private String dsId;
|
||||
|
@ -70,6 +69,14 @@ public class WfProcessExecution implements Serializable {
|
|||
this.processId = processId;
|
||||
}
|
||||
|
||||
public String getWfInstanceId() {
|
||||
return wfInstanceId;
|
||||
}
|
||||
|
||||
public void setWfInstanceId(final String wfInstanceId) {
|
||||
this.wfInstanceId = wfInstanceId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
@ -94,19 +101,19 @@ public class WfProcessExecution implements Serializable {
|
|||
this.status = status;
|
||||
}
|
||||
|
||||
public Date getStartDate() {
|
||||
public LocalDateTime getStartDate() {
|
||||
return startDate;
|
||||
}
|
||||
|
||||
public void setStartDate(final Date startDate) {
|
||||
public void setStartDate(final LocalDateTime startDate) {
|
||||
this.startDate = startDate;
|
||||
}
|
||||
|
||||
public Date getEndDate() {
|
||||
public LocalDateTime getEndDate() {
|
||||
return endDate;
|
||||
}
|
||||
|
||||
public void setEndDate(final Date endDate) {
|
||||
public void setEndDate(final LocalDateTime endDate) {
|
||||
this.endDate = endDate;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package eu.dnetlib.manager.wf.model;
|
||||
|
||||
public enum NotificationCondition {
|
||||
ALWAYS, NEVER, ONLY_SUCCESS, ONLY_FAILED
|
||||
}
|
|
@ -0,0 +1,269 @@
|
|||
package eu.dnetlib.manager.wf.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
public class WorkflowGraph implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 5919290887480115842L;
|
||||
|
||||
public List<WfParam> parameters;
|
||||
public List<Node> graph;
|
||||
|
||||
public List<Node> getGraph() {
|
||||
return graph;
|
||||
}
|
||||
|
||||
public void setGraph(final List<Node> graph) {
|
||||
this.graph = graph;
|
||||
}
|
||||
|
||||
public List<WfParam> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public void setParameters(final List<WfParam> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
class WfParam implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 5885589803738655166L;
|
||||
|
||||
private String name;
|
||||
private String description;
|
||||
private String type;
|
||||
private String defaultValue;
|
||||
private boolean required;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(final String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(final String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public void setDefaultValue(final String defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public boolean isRequired() {
|
||||
return required;
|
||||
}
|
||||
|
||||
public void setRequired(final boolean required) {
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Node implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -3695762832959801906L;
|
||||
|
||||
private static final String regExRef = "\\$\\{(\\w*)\\}";
|
||||
|
||||
private String name;
|
||||
private String type;
|
||||
private boolean isStart = false;
|
||||
private boolean isJoin = false;
|
||||
private List<Arc> arcs;
|
||||
private List<NodeParam> input;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(final String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public boolean isStart() {
|
||||
return isStart;
|
||||
}
|
||||
|
||||
public void setStart(final boolean isStart) {
|
||||
this.isStart = isStart;
|
||||
}
|
||||
|
||||
public boolean isJoin() {
|
||||
return isJoin;
|
||||
}
|
||||
|
||||
public void setJoin(final boolean isJoin) {
|
||||
this.isJoin = isJoin;
|
||||
}
|
||||
|
||||
public List<Arc> getArcs() {
|
||||
return arcs;
|
||||
}
|
||||
|
||||
public void setArcs(final List<Arc> arcs) {
|
||||
this.arcs = arcs;
|
||||
}
|
||||
|
||||
public List<NodeParam> getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public void setInput(final List<NodeParam> input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public Map<String, String> findEnvParams() {
|
||||
return input.stream()
|
||||
.filter(p -> StringUtils.isNotBlank(p.getEnv()))
|
||||
.collect(Collectors.toMap(NodeParam::getName, NodeParam::getEnv));
|
||||
}
|
||||
|
||||
public Map<String, Object> calculateInitialParams(final Map<String, String> globalParams, final Environment environment) {
|
||||
final Map<String, Object> map = new HashMap<>();
|
||||
|
||||
input.stream()
|
||||
.filter(p -> StringUtils.isBlank(p.getEnv()))
|
||||
.forEach(p -> map.put(p.getName(), calculateSimpleValue(p, globalParams, environment)));
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private Object calculateSimpleValue(final NodeParam p, final Map<String, String> globalParams, final Environment environment) {
|
||||
String value = p.getValue();
|
||||
final String ref = p.getRef();
|
||||
final String prop = p.getProperty();
|
||||
|
||||
if (StringUtils.isNotBlank(ref) && StringUtils.isNotBlank(globalParams.get(ref))) {
|
||||
return globalParams.get(ref);
|
||||
} else if (StringUtils.isNotBlank(value)) {
|
||||
final Matcher matcher = Pattern.compile(regExRef, Pattern.MULTILINE).matcher(value);
|
||||
while (matcher.find()) {
|
||||
final String rName = matcher.group(1);
|
||||
final String rValue = globalParams.get(rName);
|
||||
if (StringUtils.isBlank(rValue)) { return null; }
|
||||
value = value.replaceAll(Pattern.quote(matcher.group(0)), rValue);
|
||||
System.out.println("NEW VALUE " + value);
|
||||
}
|
||||
return value;
|
||||
} else if (StringUtils.isNotBlank(prop)) {
|
||||
return environment.getProperty(prop);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Arc implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 7866138976929522262L;
|
||||
|
||||
private String to;
|
||||
private String condition;
|
||||
|
||||
public String getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
public void setTo(final String to) {
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
public String getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public void setCondition(final String condition) {
|
||||
this.condition = condition;
|
||||
}
|
||||
}
|
||||
|
||||
class NodeParam implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 7815785723401725707L;
|
||||
|
||||
private String name;
|
||||
private String value;
|
||||
private String ref;
|
||||
private String property;
|
||||
private String env;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getRef() {
|
||||
return ref;
|
||||
}
|
||||
|
||||
public void setRef(final String ref) {
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
public String getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public void setProperty(final String property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
public String getEnv() {
|
||||
return env;
|
||||
}
|
||||
|
||||
public void setEnv(final String env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
package eu.dnetlib.manager.wf.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.hibernate.annotations.TypeDef;
|
||||
import org.hibernate.annotations.TypeDefs;
|
||||
|
||||
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
|
||||
import com.vladmihalcea.hibernate.type.json.JsonStringType;
|
||||
|
||||
@Entity
|
||||
@Table(name = "workflow_instances")
|
||||
@TypeDefs({
|
||||
@TypeDef(name = "json", typeClass = JsonStringType.class),
|
||||
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
|
||||
})
|
||||
public class WorkflowInstance implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 7503841966138333044L;
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
private String id;
|
||||
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
|
||||
@Column(name = "section")
|
||||
private String section;
|
||||
|
||||
@Type(type = "jsonb")
|
||||
@Column(name = "details", columnDefinition = "jsonb")
|
||||
private Map<String, String> details = new LinkedHashMap<>();
|
||||
|
||||
@Column(name = "priority")
|
||||
private Integer priority;
|
||||
|
||||
@Column(name = "dsid")
|
||||
private String dsId;
|
||||
|
||||
@Column(name = "dsname")
|
||||
private String dsName;
|
||||
|
||||
@Column(name = "apiid")
|
||||
private String apiId;
|
||||
|
||||
@Column(name = "enabled")
|
||||
private boolean enabled;
|
||||
|
||||
@Column(name = "configured")
|
||||
private boolean configured;
|
||||
|
||||
@Column(name = "scheduling_enabled")
|
||||
private boolean schedulingEnabled;
|
||||
|
||||
@Column(name = "scheduling_cron")
|
||||
private String cronExpression;
|
||||
|
||||
@Column(name = "scheduling_min_interval")
|
||||
private int cronMinInterval;
|
||||
|
||||
@Column(name = "workflow")
|
||||
private String workflow;
|
||||
|
||||
@Column(name = "destroy_wf")
|
||||
private String destroyWf;
|
||||
|
||||
@Type(type = "jsonb")
|
||||
@Column(name = "system_params", columnDefinition = "jsonb")
|
||||
private Map<String, String> systemParams = new LinkedHashMap<>();
|
||||
|
||||
@Type(type = "jsonb")
|
||||
@Column(name = "user_params", columnDefinition = "jsonb")
|
||||
private Map<String, String> userParams = new LinkedHashMap<>();
|
||||
|
||||
@Transient
|
||||
private String parentId;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getSection() {
|
||||
return section;
|
||||
}
|
||||
|
||||
public void setSection(final String section) {
|
||||
this.section = section;
|
||||
}
|
||||
|
||||
public Map<String, String> getDetails() {
|
||||
return details;
|
||||
}
|
||||
|
||||
public void setDetails(final Map<String, String> details) {
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
public Integer getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public void setPriority(final Integer priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public String getDsId() {
|
||||
return dsId;
|
||||
}
|
||||
|
||||
public void setDsId(final String dsId) {
|
||||
this.dsId = dsId;
|
||||
}
|
||||
|
||||
public String getDsName() {
|
||||
return dsName;
|
||||
}
|
||||
|
||||
public void setDsName(final String dsName) {
|
||||
this.dsName = dsName;
|
||||
}
|
||||
|
||||
public String getApiId() {
|
||||
return apiId;
|
||||
}
|
||||
|
||||
public void setApiId(final String apiId) {
|
||||
this.apiId = apiId;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(final boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isConfigured() {
|
||||
return configured;
|
||||
}
|
||||
|
||||
public void setConfigured(final boolean configured) {
|
||||
this.configured = configured;
|
||||
}
|
||||
|
||||
public boolean isSchedulingEnabled() {
|
||||
return schedulingEnabled;
|
||||
}
|
||||
|
||||
public void setSchedulingEnabled(final boolean schedulingEnabled) {
|
||||
this.schedulingEnabled = schedulingEnabled;
|
||||
}
|
||||
|
||||
public String getCronExpression() {
|
||||
return cronExpression;
|
||||
}
|
||||
|
||||
public void setCronExpression(final String cronExpression) {
|
||||
this.cronExpression = cronExpression;
|
||||
}
|
||||
|
||||
public int getCronMinInterval() {
|
||||
return cronMinInterval;
|
||||
}
|
||||
|
||||
public void setCronMinInterval(final int cronMinInterval) {
|
||||
this.cronMinInterval = cronMinInterval;
|
||||
}
|
||||
|
||||
public String getWorkflow() {
|
||||
return workflow;
|
||||
}
|
||||
|
||||
public void setWorkflow(final String workflow) {
|
||||
this.workflow = workflow;
|
||||
}
|
||||
|
||||
public String getDestroyWf() {
|
||||
return destroyWf;
|
||||
}
|
||||
|
||||
public void setDestroyWf(final String destroyWf) {
|
||||
this.destroyWf = destroyWf;
|
||||
}
|
||||
|
||||
public Map<String, String> getSystemParams() {
|
||||
return systemParams;
|
||||
}
|
||||
|
||||
public void setSystemParams(final Map<String, String> systemParams) {
|
||||
this.systemParams = systemParams;
|
||||
}
|
||||
|
||||
public Map<String, String> getUserParams() {
|
||||
return userParams;
|
||||
}
|
||||
|
||||
public void setUserParams(final Map<String, String> userParams) {
|
||||
this.userParams = userParams;
|
||||
}
|
||||
|
||||
public String getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(final String parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package eu.dnetlib.manager.wf.model;
|
||||
|
||||
public class WorkflowParamDesc {
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package eu.dnetlib.manager.wf.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "workflow_subscriptions")
|
||||
@IdClass(WorkflowSubscriptionPK.class)
|
||||
public class WorkflowSubscription implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -3662770213782581404L;
|
||||
|
||||
@Id
|
||||
@Column(name = "wf_instance_id")
|
||||
private String wfInstanceId;
|
||||
|
||||
@Id
|
||||
@Column(name = "condition")
|
||||
@Enumerated(EnumType.STRING)
|
||||
private NotificationCondition condition;
|
||||
|
||||
@Id
|
||||
@Column(name = "email")
|
||||
private String email;
|
||||
|
||||
@Column(name = "message_id")
|
||||
private String messageId;
|
||||
|
||||
public String getWfInstanceId() {
|
||||
return wfInstanceId;
|
||||
}
|
||||
|
||||
public void setWfInstanceId(final String wfInstanceId) {
|
||||
this.wfInstanceId = wfInstanceId;
|
||||
}
|
||||
|
||||
public NotificationCondition getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public void setCondition(final NotificationCondition condition) {
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(final String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getMessageId() {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
public void setMessageId(final String messageId) {
|
||||
this.messageId = messageId;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package eu.dnetlib.manager.wf.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class WorkflowSubscriptionPK implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -7569690774071644848L;
|
||||
|
||||
private String wfInstanceId;
|
||||
|
||||
private NotificationCondition condition;
|
||||
|
||||
private String email;
|
||||
|
||||
public String getWfInstanceId() {
|
||||
return wfInstanceId;
|
||||
}
|
||||
|
||||
public void setWfInstanceId(final String wfInstanceId) {
|
||||
this.wfInstanceId = wfInstanceId;
|
||||
}
|
||||
|
||||
public NotificationCondition getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public void setCondition(final NotificationCondition condition) {
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(final String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package eu.dnetlib.utils;
|
||||
|
||||
public interface CountedValue {
|
||||
|
||||
public String getValue();
|
||||
|
||||
public void setValue();
|
||||
|
||||
public long getCount();
|
||||
|
||||
public void setCount(final long count);
|
||||
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
package eu.dnetlib.utils;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class DateUtils {
|
||||
|
||||
|
@ -12,7 +14,7 @@ public class DateUtils {
|
|||
private static final long HOUR = MINUTE * 60;
|
||||
private static final long DAY = HOUR * 24;
|
||||
private static final long YEAR = DAY * 365;
|
||||
private static final SimpleDateFormat ISO8601FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
|
||||
private static final DateTimeFormatter ISO8601FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
|
||||
|
||||
public static String elapsedTime(long t) {
|
||||
final StringWriter a = new StringWriter();
|
||||
|
@ -78,7 +80,13 @@ public class DateUtils {
|
|||
}
|
||||
|
||||
public static String calculate_ISO8601(final long l) {
|
||||
String result = ISO8601FORMAT.format(new Date(l));
|
||||
|
||||
final LocalDateTime time =
|
||||
LocalDateTime.ofInstant(Instant.ofEpochMilli(l), TimeZone
|
||||
.getDefault()
|
||||
.toZoneId());
|
||||
|
||||
String result = time.format(ISO8601FORMAT);
|
||||
// convert YYYYMMDDTHH:mm:ss+HH00 into YYYYMMDDTHH:mm:ss+HH:00
|
||||
// - note the added colon for the Timezone
|
||||
result = result.substring(0, result.length() - 2) + ":" + result.substring(result.length() - 2);
|
||||
|
@ -89,4 +97,8 @@ public class DateUtils {
|
|||
return Long.toString(Math.floorDiv(d, n));
|
||||
}
|
||||
|
||||
public static long now() {
|
||||
return Instant.now().toEpochMilli();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package eu.dnetlib.utils;
|
||||
|
||||
public interface Stoppable {
|
||||
|
||||
void stop();
|
||||
|
||||
void resume();
|
||||
|
||||
public StoppableDetails getStopDetails();
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package eu.dnetlib.utils;
|
||||
|
||||
public class StoppableDetails {
|
||||
|
||||
public enum StopStatus {
|
||||
STOPPED,
|
||||
STOPPING,
|
||||
RUNNING
|
||||
};
|
||||
|
||||
private final String title;
|
||||
private final String description;
|
||||
private final StopStatus status;
|
||||
|
||||
public StoppableDetails(final String title, final String description, final StopStatus status) {
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public StopStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
}
|
|
@ -105,16 +105,17 @@ CREATE INDEX ON context_cat_concepts_lvl_2 (parent);
|
|||
-- WF History
|
||||
|
||||
CREATE TABLE wf_history (
|
||||
process_id text PRIMARY KEY,
|
||||
name text NOT NULL,
|
||||
family text NOT NULL,
|
||||
status text NOT NULL,
|
||||
start_date timestamp NOT NULL,
|
||||
end_date timestamp NOT NULL,
|
||||
ds_id text,
|
||||
ds_name text,
|
||||
ds_api text,
|
||||
details jsonb
|
||||
process_id text PRIMARY KEY,
|
||||
wf_instance_id text NOT NULL,
|
||||
name text NOT NULL,
|
||||
family text NOT NULL,
|
||||
status text NOT NULL,
|
||||
start_date timestamp NOT NULL,
|
||||
end_date timestamp NOT NULL,
|
||||
ds_id text,
|
||||
ds_name text,
|
||||
ds_api text,
|
||||
details jsonb
|
||||
);
|
||||
|
||||
-- Other Resources
|
||||
|
@ -130,7 +131,8 @@ INSERT INTO resource_types(id, name, content_type) VALUES
|
|||
('transformation_rule_legacy', 'Transformation Rules (legacy)', 'text/plain'),
|
||||
('cleaning_rule', 'Cleaning Rules', 'application/xml'),
|
||||
('hadoop_job_configuration', 'Hadoop Job Configurations', 'application/xml')
|
||||
('dedup_configuration', 'Dedup Configurations', 'application/json');
|
||||
('dedup_configuration', 'Dedup Configurations', 'application/json')
|
||||
('workflow', 'Workflows', 'application/json');
|
||||
|
||||
CREATE TABLE resources (
|
||||
id text PRIMARY KEY,
|
||||
|
@ -138,6 +140,7 @@ CREATE TABLE resources (
|
|||
description text,
|
||||
content text NOT NULL DEFAULT '',
|
||||
type text NOT NULL REFERENCES resource_types(id),
|
||||
subtype text,
|
||||
creation_date timestamp NOT NULL DEFAULT now(),
|
||||
modification_date timestamp NOT NULL DEFAULT now()
|
||||
);
|
||||
|
@ -177,6 +180,14 @@ CREATE VIEW resource_types_view AS (
|
|||
count(*) AS count,
|
||||
false AS simple
|
||||
FROM protocols
|
||||
) UNION ALL (
|
||||
SELECT
|
||||
'email' AS id,
|
||||
'Email templates' AS name,
|
||||
'text/plain' AS content_type,
|
||||
count(*) AS count,
|
||||
false AS simple
|
||||
FROM emails
|
||||
);
|
||||
|
||||
CREATE TABLE mdstores (
|
||||
|
@ -241,3 +252,40 @@ GROUP BY md.id,
|
|||
v1.lastupdate,
|
||||
v1.size;
|
||||
|
||||
-- Email Templates
|
||||
CREATE TABLE emails (
|
||||
id text PRIMARY KEY,
|
||||
description text NOT NULL,
|
||||
subject text NOT NULL,
|
||||
message text NOT NULL
|
||||
);
|
||||
|
||||
-- Workflows
|
||||
|
||||
CREATE TABLE workflow_instances (
|
||||
id text PRIMARY KEY,
|
||||
name text NOT NULL,
|
||||
section text,
|
||||
details jsonb NOT NULL DEFAULT '{}',
|
||||
priority int,
|
||||
dsid text,
|
||||
dsname text,
|
||||
apiid text,
|
||||
enabled boolean NOT NULL DEFAULT false,
|
||||
configured boolean NOT NULL DEFAULT false,
|
||||
scheduling_enabled boolean NOT NULL DEFAULT false,
|
||||
scheduling_cron text,
|
||||
scheduling_min_interval int,
|
||||
workflow text REFERENCES resource(id),
|
||||
destroy_wf text REFERENCES resource(id),
|
||||
system_params jsonb NOT NULL DEFAULT '{}',
|
||||
user_params jsonb NOT NULL DEFAULT '{}'
|
||||
);
|
||||
|
||||
CREATE TABLE workflow_subscriptions (
|
||||
wf_instance_id text NOT NULL REFERENCES workflow_instances(id),
|
||||
condition text NOT NULL,
|
||||
email text NOT NULL,
|
||||
message_id text NOT NULL REFERENCES emails(id),
|
||||
PRIMARY KEY (wf_instance_id, condition, email)
|
||||
);
|
||||
|
|
|
@ -25,6 +25,11 @@
|
|||
<artifactId>jaxen</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Tests -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package eu.dnetlib.common.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import eu.dnetlib.common.model.EmailTemplate;
|
||||
|
||||
public interface EmailTemplateRepository extends JpaRepository<EmailTemplate, String> {
|
||||
|
||||
}
|
|
@ -9,7 +9,7 @@ import static eu.dnetlib.dsm.utils.DsmMappingUtils.createId;
|
|||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.Date;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
@ -368,7 +368,7 @@ public class DsmService {
|
|||
private void ensureRegistrationDate(final String dsId) {
|
||||
if (!dsRepository.hasRegistrationdate(dsId)) {
|
||||
log.info("setting registration date for datasource: " + dsId);
|
||||
dsRepository.setRegistrationDate(dsId, new Date(System.currentTimeMillis()));
|
||||
dsRepository.setRegistrationDate(dsId, LocalDate.now());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package eu.dnetlib.dsm.domain;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
|
@ -27,15 +27,15 @@ public class ApiDetails extends ApiIgnoredProperties {
|
|||
|
||||
private Integer lastCollectionTotal;
|
||||
|
||||
private Date lastCollectionDate;
|
||||
private LocalDateTime lastCollectionDate;
|
||||
|
||||
private Integer lastAggregationTotal;
|
||||
|
||||
private Date lastAggregationDate;
|
||||
private LocalDateTime lastAggregationDate;
|
||||
|
||||
private Integer lastDownloadTotal;
|
||||
|
||||
private Date lastDownloadDate;
|
||||
private LocalDateTime lastDownloadDate;
|
||||
|
||||
private String baseurl;
|
||||
|
||||
|
@ -71,7 +71,7 @@ public class ApiDetails extends ApiIgnoredProperties {
|
|||
return lastCollectionTotal;
|
||||
}
|
||||
|
||||
public Date getLastCollectionDate() {
|
||||
public LocalDateTime getLastCollectionDate() {
|
||||
return lastCollectionDate;
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ public class ApiDetails extends ApiIgnoredProperties {
|
|||
return lastAggregationTotal;
|
||||
}
|
||||
|
||||
public Date getLastAggregationDate() {
|
||||
public LocalDateTime getLastAggregationDate() {
|
||||
return lastAggregationDate;
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ public class ApiDetails extends ApiIgnoredProperties {
|
|||
return lastDownloadTotal;
|
||||
}
|
||||
|
||||
public Date getLastDownloadDate() {
|
||||
public LocalDateTime getLastDownloadDate() {
|
||||
return lastDownloadDate;
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ public class ApiDetails extends ApiIgnoredProperties {
|
|||
return this;
|
||||
}
|
||||
|
||||
public ApiDetails setLastCollectionDate(final Date lastCollectionDate) {
|
||||
public ApiDetails setLastCollectionDate(final LocalDateTime lastCollectionDate) {
|
||||
this.lastCollectionDate = lastCollectionDate;
|
||||
return this;
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ public class ApiDetails extends ApiIgnoredProperties {
|
|||
return this;
|
||||
}
|
||||
|
||||
public ApiDetails setLastAggregationDate(final Date lastAggregationDate) {
|
||||
public ApiDetails setLastAggregationDate(final LocalDateTime lastAggregationDate) {
|
||||
this.lastAggregationDate = lastAggregationDate;
|
||||
return this;
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ public class ApiDetails extends ApiIgnoredProperties {
|
|||
return this;
|
||||
}
|
||||
|
||||
public ApiDetails setLastDownloadDate(final Date lastDownloadDate) {
|
||||
public ApiDetails setLastDownloadDate(final LocalDateTime lastDownloadDate) {
|
||||
this.lastDownloadDate = lastDownloadDate;
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package eu.dnetlib.dsm.domain;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Transient;
|
||||
|
@ -48,12 +48,12 @@ public class DatasourceDetails extends DatasourceIgnoredProperties {
|
|||
|
||||
private String languages;
|
||||
|
||||
private Date dateofvalidation;
|
||||
private LocalDate dateofvalidation;
|
||||
|
||||
@NotBlank
|
||||
private String eoscDatasourceType;
|
||||
|
||||
private Date dateofcollection;
|
||||
private LocalDate dateofcollection;
|
||||
|
||||
private String platform;
|
||||
|
||||
|
@ -82,9 +82,9 @@ public class DatasourceDetails extends DatasourceIgnoredProperties {
|
|||
|
||||
private Boolean fullTextDownload;
|
||||
|
||||
private Date consentTermsOfUseDate;
|
||||
private LocalDate consentTermsOfUseDate;
|
||||
|
||||
private Date lastConsentTermsOfUseDate;
|
||||
private LocalDate lastConsentTermsOfUseDate;
|
||||
|
||||
private Set<OrganizationDetails> organizations;
|
||||
|
||||
|
@ -95,7 +95,7 @@ public class DatasourceDetails extends DatasourceIgnoredProperties {
|
|||
@Deprecated
|
||||
private String typology;
|
||||
|
||||
private Date registrationdate;
|
||||
private LocalDate registrationdate;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
|
@ -145,7 +145,7 @@ public class DatasourceDetails extends DatasourceIgnoredProperties {
|
|||
return namespaceprefix;
|
||||
}
|
||||
|
||||
public Date getDateofvalidation() {
|
||||
public LocalDate getDateofvalidation() {
|
||||
return dateofvalidation;
|
||||
}
|
||||
|
||||
|
@ -153,7 +153,7 @@ public class DatasourceDetails extends DatasourceIgnoredProperties {
|
|||
return eoscDatasourceType;
|
||||
}
|
||||
|
||||
public Date getDateofcollection() {
|
||||
public LocalDate getDateofcollection() {
|
||||
return dateofcollection;
|
||||
}
|
||||
|
||||
|
@ -277,7 +277,7 @@ public class DatasourceDetails extends DatasourceIgnoredProperties {
|
|||
return this;
|
||||
}
|
||||
|
||||
public DatasourceDetails setDateofvalidation(final Date dateofvalidation) {
|
||||
public DatasourceDetails setDateofvalidation(final LocalDate dateofvalidation) {
|
||||
this.dateofvalidation = dateofvalidation;
|
||||
return this;
|
||||
}
|
||||
|
@ -287,7 +287,7 @@ public class DatasourceDetails extends DatasourceIgnoredProperties {
|
|||
return this;
|
||||
}
|
||||
|
||||
public DatasourceDetails setDateofcollection(final Date dateofcollection) {
|
||||
public DatasourceDetails setDateofcollection(final LocalDate dateofcollection) {
|
||||
this.dateofcollection = dateofcollection;
|
||||
return this;
|
||||
}
|
||||
|
@ -367,11 +367,11 @@ public class DatasourceDetails extends DatasourceIgnoredProperties {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Date getConsentTermsOfUseDate() {
|
||||
public LocalDate getConsentTermsOfUseDate() {
|
||||
return consentTermsOfUseDate;
|
||||
}
|
||||
|
||||
public DatasourceDetails setConsentTermsOfUseDate(final Date consentTermsOfUseDate) {
|
||||
public DatasourceDetails setConsentTermsOfUseDate(final LocalDate consentTermsOfUseDate) {
|
||||
this.consentTermsOfUseDate = consentTermsOfUseDate;
|
||||
return this;
|
||||
}
|
||||
|
@ -396,20 +396,20 @@ public class DatasourceDetails extends DatasourceIgnoredProperties {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Date getLastConsentTermsOfUseDate() {
|
||||
public LocalDate getLastConsentTermsOfUseDate() {
|
||||
return lastConsentTermsOfUseDate;
|
||||
}
|
||||
|
||||
public DatasourceDetails setLastConsentTermsOfUseDate(final Date lastConsentTermsOfUseDate) {
|
||||
public DatasourceDetails setLastConsentTermsOfUseDate(final LocalDate lastConsentTermsOfUseDate) {
|
||||
this.lastConsentTermsOfUseDate = lastConsentTermsOfUseDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Date getRegistrationdate() {
|
||||
public LocalDate getRegistrationdate() {
|
||||
return registrationdate;
|
||||
}
|
||||
|
||||
public DatasourceDetails setRegistrationdate(final Date registrationdate) {
|
||||
public DatasourceDetails setRegistrationdate(final LocalDate registrationdate) {
|
||||
this.registrationdate = registrationdate;
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package eu.dnetlib.dsm.domain;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
|
@ -57,9 +57,9 @@ public class DatasourceDetailsUpdate {
|
|||
|
||||
private Boolean consentTermsOfUse;
|
||||
|
||||
private Date consentTermsOfUseDate;
|
||||
private LocalDate consentTermsOfUseDate;
|
||||
|
||||
private Date lastConsentTermsOfUseDate;
|
||||
private LocalDate lastConsentTermsOfUseDate;
|
||||
|
||||
private Boolean fullTextDownload;
|
||||
|
||||
|
@ -207,11 +207,11 @@ public class DatasourceDetailsUpdate {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Date getConsentTermsOfUseDate() {
|
||||
public LocalDate getConsentTermsOfUseDate() {
|
||||
return consentTermsOfUseDate;
|
||||
}
|
||||
|
||||
public DatasourceDetailsUpdate setConsentTermsOfUseDate(final Date consentTermsOfUseDate) {
|
||||
public DatasourceDetailsUpdate setConsentTermsOfUseDate(final LocalDate consentTermsOfUseDate) {
|
||||
this.consentTermsOfUseDate = consentTermsOfUseDate;
|
||||
return this;
|
||||
}
|
||||
|
@ -225,11 +225,11 @@ public class DatasourceDetailsUpdate {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Date getLastConsentTermsOfUseDate() {
|
||||
public LocalDate getLastConsentTermsOfUseDate() {
|
||||
return lastConsentTermsOfUseDate;
|
||||
}
|
||||
|
||||
public DatasourceDetailsUpdate setLastConsentTermsOfUseDate(final Date lastConsentTermsOfUseDate) {
|
||||
public DatasourceDetailsUpdate setLastConsentTermsOfUseDate(final LocalDate lastConsentTermsOfUseDate) {
|
||||
this.lastConsentTermsOfUseDate = lastConsentTermsOfUseDate;
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package eu.dnetlib.dsm.domain;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
|
@ -13,10 +13,10 @@ public abstract class DatasourceIgnoredProperties {
|
|||
protected String provenanceaction;
|
||||
|
||||
@JsonIgnore
|
||||
protected Date releasestartdate;
|
||||
protected LocalDate releasestartdate;
|
||||
|
||||
@JsonIgnore
|
||||
protected Date releaseenddate;
|
||||
protected LocalDate releaseenddate;
|
||||
|
||||
@JsonIgnore
|
||||
protected String missionstatementurl;
|
||||
|
@ -76,19 +76,19 @@ public abstract class DatasourceIgnoredProperties {
|
|||
this.provenanceaction = provenanceaction;
|
||||
}
|
||||
|
||||
public Date getReleasestartdate() {
|
||||
public LocalDate getReleasestartdate() {
|
||||
return releasestartdate;
|
||||
}
|
||||
|
||||
public void setReleasestartdate(final Date releasestartdate) {
|
||||
public void setReleasestartdate(final LocalDate releasestartdate) {
|
||||
this.releasestartdate = releasestartdate;
|
||||
}
|
||||
|
||||
public Date getReleaseenddate() {
|
||||
public LocalDate getReleaseenddate() {
|
||||
return releaseenddate;
|
||||
}
|
||||
|
||||
public void setReleaseenddate(final Date releaseenddate) {
|
||||
public void setReleaseenddate(final LocalDate releaseenddate) {
|
||||
this.releaseenddate = releaseenddate;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package eu.dnetlib.dsm.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
|
@ -28,7 +28,7 @@ public class DatasourceSnippetExtended {
|
|||
@Email
|
||||
private String registeredby;
|
||||
|
||||
private Date registrationdate;
|
||||
private LocalDateTime registrationdate;
|
||||
|
||||
private String eoscDatasourceType;
|
||||
|
||||
|
@ -38,9 +38,9 @@ public class DatasourceSnippetExtended {
|
|||
|
||||
private Boolean consentTermsOfUse;
|
||||
|
||||
private Date consentTermsOfUseDate;
|
||||
private LocalDateTime consentTermsOfUseDate;
|
||||
|
||||
private Date lastConsentTermsOfUseDate;
|
||||
private LocalDateTime lastConsentTermsOfUseDate;
|
||||
|
||||
private Boolean fullTextDownload;
|
||||
|
||||
|
@ -89,11 +89,11 @@ public class DatasourceSnippetExtended {
|
|||
this.registeredby = registeredby;
|
||||
}
|
||||
|
||||
public Date getRegistrationdate() {
|
||||
public LocalDateTime getRegistrationdate() {
|
||||
return registrationdate;
|
||||
}
|
||||
|
||||
public void setRegistrationdate(final Date registrationdate) {
|
||||
public void setRegistrationdate(final LocalDateTime registrationdate) {
|
||||
this.registrationdate = registrationdate;
|
||||
}
|
||||
|
||||
|
@ -118,11 +118,11 @@ public class DatasourceSnippetExtended {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Date getConsentTermsOfUseDate() {
|
||||
public LocalDateTime getConsentTermsOfUseDate() {
|
||||
return consentTermsOfUseDate;
|
||||
}
|
||||
|
||||
public DatasourceSnippetExtended setConsentTermsOfUseDate(final Date consentTermsOfUseDate) {
|
||||
public DatasourceSnippetExtended setConsentTermsOfUseDate(final LocalDateTime consentTermsOfUseDate) {
|
||||
this.consentTermsOfUseDate = consentTermsOfUseDate;
|
||||
return this;
|
||||
}
|
||||
|
@ -170,11 +170,11 @@ public class DatasourceSnippetExtended {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Date getLastConsentTermsOfUseDate() {
|
||||
public LocalDateTime getLastConsentTermsOfUseDate() {
|
||||
return lastConsentTermsOfUseDate;
|
||||
}
|
||||
|
||||
public DatasourceSnippetExtended setLastConsentTermsOfUseDate(final Date lastConsentTermsOfUseDate) {
|
||||
public DatasourceSnippetExtended setLastConsentTermsOfUseDate(final LocalDateTime lastConsentTermsOfUseDate) {
|
||||
this.lastConsentTermsOfUseDate = lastConsentTermsOfUseDate;
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package eu.dnetlib.dsm.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
@ -14,7 +14,7 @@ public class OrganizationIgnoredProperties {
|
|||
protected String collectedfrom;
|
||||
|
||||
@JsonIgnore
|
||||
protected Date dateofcollection;
|
||||
protected LocalDateTime dateofcollection;
|
||||
|
||||
@JsonIgnore
|
||||
protected String provenanceaction;
|
||||
|
@ -38,11 +38,11 @@ public class OrganizationIgnoredProperties {
|
|||
this.collectedfrom = collectedfrom;
|
||||
}
|
||||
|
||||
public Date getDateofcollection() {
|
||||
public LocalDateTime getDateofcollection() {
|
||||
return dateofcollection;
|
||||
}
|
||||
|
||||
public void setDateofcollection(final Date dateofcollection) {
|
||||
public void setDateofcollection(final LocalDateTime dateofcollection) {
|
||||
this.dateofcollection = dateofcollection;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package eu.dnetlib.dsm.repository;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
|
@ -64,7 +64,7 @@ public interface DatasourceRepository extends JpaRepository<Datasource, String>,
|
|||
@Modifying
|
||||
@Transactional
|
||||
@Query("update #{#entityName} d set d.registrationdate = ?2 where d.id = ?1")
|
||||
void setRegistrationDate(String id, Date registrationdate);
|
||||
void setRegistrationDate(String id, LocalDate registrationdate);
|
||||
|
||||
@Modifying
|
||||
@Transactional
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package eu.dnetlib.dsm.utils;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -98,7 +98,7 @@ public class DsmMappingUtils {
|
|||
final String prefix = StringUtils.isNotBlank(dbe.getNamespaceprefix()) ? dbe.getNamespaceprefix() : dbe.getId();
|
||||
o.setId(prefix + ID_SEPARATOR + o.getLegalname());
|
||||
if (o.getDateofcollection() == null) {
|
||||
o.setDateofcollection(new Date(System.currentTimeMillis()));
|
||||
o.setDateofcollection(LocalDateTime.now());
|
||||
}
|
||||
o.setCollectedfrom(dbe.getCollectedfrom());
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package eu.dnetlib.is.resource;
|
||||
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -60,17 +60,19 @@ public class SimpleResourceService {
|
|||
@Transactional
|
||||
public SimpleResource saveNewResource(final String name,
|
||||
final String type,
|
||||
final String subtype,
|
||||
final String description,
|
||||
final String content) throws InformationServiceException {
|
||||
|
||||
resourceValidator.validate(type, content);
|
||||
|
||||
final Date now = new Date();
|
||||
final LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
final SimpleResource res = new SimpleResource();
|
||||
res.setId(UUID.randomUUID().toString());
|
||||
res.setName(name);
|
||||
res.setType(type);
|
||||
res.setSubtype(subtype);
|
||||
res.setDescription(description);
|
||||
res.setCreationDate(now);
|
||||
res.setModificationDate(now);
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package eu.dnetlib.manager.history;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import eu.dnetlib.manager.history.model.WfProcessExecution;
|
||||
import eu.dnetlib.manager.history.repository.WfProcessExecutionRepository;
|
||||
|
||||
@Service
|
||||
public class WorkflowLogger {
|
||||
|
||||
@Autowired
|
||||
private WfProcessExecutionRepository wfProcessExecutionRepository;
|
||||
|
||||
public List<WfProcessExecution> history(final int total, final Long from, final Long to) {
|
||||
if (from == null && to == null) {
|
||||
return wfProcessExecutionRepository.findAll(PageRequest.of(0, total, Sort.by("endDate").descending())).toList();
|
||||
} else {
|
||||
|
||||
final LocalDateTime fromTime = from != null ? LocalDateTime.ofInstant(Instant.ofEpochMilli(from), TimeZone
|
||||
.getDefault()
|
||||
.toZoneId()) : LocalDateTime.MIN;
|
||||
final LocalDateTime toTime = to != null ? LocalDateTime.ofInstant(Instant.ofEpochMilli(to), TimeZone
|
||||
.getDefault()
|
||||
.toZoneId()) : LocalDateTime.MAX;
|
||||
|
||||
return wfProcessExecutionRepository.findByEndDateBetweenOrderByEndDateDesc(fromTime, toTime);
|
||||
}
|
||||
}
|
||||
|
||||
public WfProcessExecution getProcessExecution(final String processId) {
|
||||
return wfProcessExecutionRepository.findById(processId).get();
|
||||
}
|
||||
|
||||
public void saveProcessExecution(final WfProcessExecution pe) {
|
||||
wfProcessExecutionRepository.save(pe);
|
||||
}
|
||||
|
||||
public Optional<WfProcessExecution> getLastExecutionForInstance(final String id) {
|
||||
return wfProcessExecutionRepository.findOneByWfInstanceIdOrderByEndDateAsc(id);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package eu.dnetlib.manager.history.repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import eu.dnetlib.manager.history.model.WfProcessExecution;
|
||||
|
||||
public interface WfProcessExecutionRepository extends JpaRepository<WfProcessExecution, String> {
|
||||
|
||||
List<WfProcessExecution> findByEndDateBetweenOrderByEndDateDesc(LocalDateTime start, LocalDateTime end);
|
||||
|
||||
Optional<WfProcessExecution> findOneByWfInstanceIdOrderByEndDateAsc(String id);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package eu.dnetlib.manager.wf.repository;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
import eu.dnetlib.manager.wf.model.WorkflowInstance;
|
||||
import eu.dnetlib.utils.CountedValue;
|
||||
|
||||
public interface WorkflowInstanceRepository extends JpaRepository<WorkflowInstance, String> {
|
||||
|
||||
@Query(value = "select section as value, count(*) as count "
|
||||
+ "from workflow_instances "
|
||||
+ "group by section "
|
||||
+ "order by count desc;", nativeQuery = true)
|
||||
Stream<CountedValue> streamSections();
|
||||
|
||||
Stream<WorkflowInstance> findBySection(String section);
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package eu.dnetlib.manager.wf.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import eu.dnetlib.manager.wf.model.WorkflowSubscription;
|
||||
import eu.dnetlib.manager.wf.model.WorkflowSubscriptionPK;
|
||||
|
||||
public interface WorkflowSubscriptionRepository extends JpaRepository<WorkflowSubscription, WorkflowSubscriptionPK> {
|
||||
|
||||
List<WorkflowSubscription> findByWfInstanceId(String wfInstanceId);
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package eu.dnetlib.msro.history.repository;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import eu.dnetlib.msro.model.history.WfProcessExecution;
|
||||
|
||||
public interface WfProcessExecutionRepository extends JpaRepository<WfProcessExecution, String> {
|
||||
|
||||
List<WfProcessExecution> findByEndDateBetweenOrderByEndDateDesc(Date start, Date end);
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
package eu.dnetlib.notifications.mail;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.mail.Authenticator;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.PasswordAuthentication;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Transport;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
import eu.dnetlib.common.model.EmailTemplate;
|
||||
import eu.dnetlib.common.repository.EmailTemplateRepository;
|
||||
|
||||
@Service
|
||||
public class EmailService {
|
||||
|
||||
private static final Log log = LogFactory.getLog(EmailService.class);
|
||||
private final BlockingQueue<Message> queue = new LinkedBlockingQueue<>();
|
||||
|
||||
@Value("${dnet.configuration.mail.sender.email}")
|
||||
private String from;
|
||||
@Value("${dnet.configuration.mail.sender.name}")
|
||||
private String fromName;
|
||||
@Value("${dnet.configuration.mail.cc}")
|
||||
private String cc;
|
||||
@Value("${dnet.configuration.mail.smtp.host}")
|
||||
private String smtpHost;
|
||||
@Value("${dnet.configuration.mail.smtp.port}")
|
||||
private final int smtpPort = 587;
|
||||
@Value("${dnet.configuration.mail.smtp.user}")
|
||||
private String smtpUser;
|
||||
@Value("${dnet.configuration.mail.smtp.password}")
|
||||
private String smtpPassword;
|
||||
@Value("${server.public_url}")
|
||||
private String baseUrl;
|
||||
@Value("${dnet.configuration.infrastructure}")
|
||||
private String infrastructure;
|
||||
|
||||
@Autowired
|
||||
private EmailTemplateRepository emailTemplateRepository;
|
||||
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
new Thread(() -> {
|
||||
while (true) {
|
||||
try {
|
||||
final Message message = this.queue.take();
|
||||
if (message != null) {
|
||||
try {
|
||||
log.info("Sending mail...");
|
||||
Transport.send(message);
|
||||
log.info("...sent");
|
||||
} catch (final MessagingException e) {
|
||||
log.error("Error sending email", e);
|
||||
this.queue.add(message);
|
||||
}
|
||||
}
|
||||
} catch (final InterruptedException e1) {
|
||||
throw new RuntimeException(e1);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public List<EmailTemplate> listEmailTemplates() {
|
||||
return emailTemplateRepository.findAll();
|
||||
}
|
||||
|
||||
public void saveEmailTemplate(final EmailTemplate email) {
|
||||
if (StringUtils.isBlank(email.getId()) || email.getId().length() < 10) {
|
||||
email.setId("email-" + UUID.randomUUID());
|
||||
log.info("Saving new email with id: " + email.getId());
|
||||
}
|
||||
emailTemplateRepository.save(email);
|
||||
}
|
||||
|
||||
public void deleteEmailTemplate(final String id) {
|
||||
emailTemplateRepository.deleteById(id);
|
||||
}
|
||||
|
||||
public void sendMail(final String to, final String subject, final String message) {
|
||||
try {
|
||||
final Session session = Session.getInstance(obtainProperties(), obtainAuthenticator());
|
||||
|
||||
final MimeMessage mimeMessage = new MimeMessage(session);
|
||||
mimeMessage.setFrom(new InternetAddress(this.from, this.fromName));
|
||||
mimeMessage.setSubject(subject);
|
||||
mimeMessage.setContent(message, "text/html; charset=utf-8");
|
||||
mimeMessage.setSentDate(new Date());
|
||||
|
||||
mimeMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
|
||||
|
||||
if (this.cc != null && !this.cc.isEmpty()) {
|
||||
for (final String aCC : Splitter.on(",").omitEmptyStrings().trimResults().split(cc)) {
|
||||
mimeMessage.addRecipient(Message.RecipientType.CC, new InternetAddress(aCC));
|
||||
}
|
||||
}
|
||||
|
||||
this.queue.add(mimeMessage);
|
||||
|
||||
log.info("Mail to " + to + " in queue");
|
||||
} catch (final Exception e) {
|
||||
log.error("Error sending mail", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendStoredMail(final String to, final String emailId, final Map<String, Object> params) {
|
||||
|
||||
// TODO use a real template library
|
||||
emailTemplateRepository.findById(emailId).ifPresent(tmpl -> {
|
||||
String msg = tmpl.getMessage();
|
||||
String subject = tmpl.getSubject();
|
||||
|
||||
for (final Entry<String, Object> e : params.entrySet()) {
|
||||
msg = msg.replaceAll("{" + e.getKey() + "}", e.getValue().toString());
|
||||
subject = subject.replaceAll("{" + e.getKey() + "}", e.getValue().toString());
|
||||
}
|
||||
sendMail(to, subject, msg);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private Properties obtainProperties() {
|
||||
final Properties props = new Properties();
|
||||
props.put("mail.transport.protocol", "smtp");
|
||||
props.put("mail.smtp.host", this.smtpHost);
|
||||
props.put("mail.smtp.port", this.smtpPort);
|
||||
props.put("mail.smtp.auth", Boolean.toString(this.smtpUser != null && !this.smtpUser.isEmpty()));
|
||||
return props;
|
||||
}
|
||||
|
||||
private Authenticator obtainAuthenticator() {
|
||||
if (this.smtpUser == null || this.smtpUser.isEmpty()) { return null; }
|
||||
|
||||
final String user = this.smtpUser;
|
||||
final String passwd = this.smtpPassword;
|
||||
|
||||
return new Authenticator() {
|
||||
|
||||
private final PasswordAuthentication authentication = new PasswordAuthentication(user, passwd);
|
||||
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return this.authentication;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>eu.dnetlib.dhp</groupId>
|
||||
<artifactId>libs</artifactId>
|
||||
<version>3.3.3-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>dnet-wf-service</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>eu.dnetlib.dhp</groupId>
|
||||
<artifactId>dnet-is-services</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>eu.dnetlib.dhp</groupId>
|
||||
<artifactId>dnet-data-services</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Tests -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,26 @@
|
|||
package eu.dnetlib.manager.wf;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class NodeInfo {
|
||||
|
||||
private String name;
|
||||
private Map<String, String> params = new LinkedHashMap<>();
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Map<String, String> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setParams(final Map<String, String> params) {
|
||||
this.params = params;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package eu.dnetlib.manager.wf;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class WfManager {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
/*
|
||||
* public Object obtainBaseNode(final String name) { return applicationContext.getBean(name); }
|
||||
*
|
||||
* public NodeInfo obtainInfo(final BaseNode<?, ?> node) { final NodeInfo info = new NodeInfo(); final WfNode annotation =
|
||||
* node.getClass().getAnnotation(WfNode.class); info.setName(annotation.name()); for (final WfParam p : annotation.inputParams()) {
|
||||
* info.getParams().put(p.name(), p.type()); } return info; }
|
||||
*/
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
package eu.dnetlib.manager.wf;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import eu.dnetlib.dsm.DsmService;
|
||||
import eu.dnetlib.errors.DsmException;
|
||||
import eu.dnetlib.errors.WorkflowManagerException;
|
||||
import eu.dnetlib.is.model.resource.SimpleResource;
|
||||
import eu.dnetlib.is.resource.repository.SimpleResourceRepository;
|
||||
import eu.dnetlib.manager.wf.model.WorkflowGraph;
|
||||
import eu.dnetlib.manager.wf.model.WorkflowInstance;
|
||||
import eu.dnetlib.manager.wf.repository.WorkflowInstanceRepository;
|
||||
import eu.dnetlib.manager.wf.workflows.procs.ProcessEngine;
|
||||
import eu.dnetlib.manager.wf.workflows.procs.ProcessFactory;
|
||||
import eu.dnetlib.manager.wf.workflows.procs.ProcessRegistry;
|
||||
import eu.dnetlib.manager.wf.workflows.procs.WorkflowProcess;
|
||||
import eu.dnetlib.manager.wf.workflows.util.ExecutionCallback;
|
||||
import eu.dnetlib.manager.wf.workflows.util.WorkflowsConstants;
|
||||
import eu.dnetlib.utils.CountedValue;
|
||||
import eu.dnetlib.utils.Stoppable;
|
||||
import eu.dnetlib.utils.StoppableDetails;
|
||||
|
||||
@Service
|
||||
public class WorkflowManagerService implements Stoppable {
|
||||
|
||||
private static final Log log = LogFactory.getLog(WorkflowManagerService.class);
|
||||
|
||||
@Autowired
|
||||
private ProcessRegistry processRegistry;
|
||||
@Autowired
|
||||
private ProcessFactory processFactory;
|
||||
@Autowired
|
||||
private ProcessEngine processEngine;
|
||||
@Autowired
|
||||
private DsmService dsmService;
|
||||
|
||||
@Autowired
|
||||
private SimpleResourceRepository simpleResourceRepository;
|
||||
@Autowired
|
||||
private WorkflowInstanceRepository workflowInstanceRepository;
|
||||
|
||||
private boolean paused = false;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
|
||||
if (isPaused() || processRegistry.countRunningWfs() >= WorkflowsConstants.MAX_RUNNING_PROCS_SIZE) { return; }
|
||||
|
||||
final WorkflowProcess process = processRegistry.nextProcessToStart();
|
||||
if (process != null) {
|
||||
processEngine.startProcess(process);
|
||||
} else {
|
||||
log.debug("WorkflowProcess queue is empty");
|
||||
}
|
||||
}, 10, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public WorkflowInstance findWorkflowInstance(final String id) throws WorkflowManagerException {
|
||||
return workflowInstanceRepository.findById(id).orElseThrow(() -> new WorkflowManagerException("WF instance not found: " + id));
|
||||
}
|
||||
|
||||
public String startRepoHiWorkflow(final String wfId,
|
||||
final String dsId,
|
||||
final String apiId,
|
||||
final ExecutionCallback<WorkflowProcess> callback)
|
||||
throws WorkflowManagerException {
|
||||
|
||||
if (isPaused()) {
|
||||
log.warn("Wf " + wfId + " not launched, because WorkflowExecutor is preparing for shutdown");
|
||||
throw new WorkflowManagerException("WorkflowExecutor is preparing for shutdown");
|
||||
}
|
||||
|
||||
try {
|
||||
final String dsName = dsmService.getDs(dsId).getOfficialname();
|
||||
|
||||
final WorkflowInstance instance = new WorkflowInstance();
|
||||
instance.setId("REPO_HI_" + UUID.randomUUID());
|
||||
instance.setDetails(new HashMap<>());
|
||||
instance.setPriority(100);
|
||||
instance.setDsId(dsId);
|
||||
instance.setDsName(dsName);
|
||||
instance.setApiId(apiId);
|
||||
instance.setEnabled(true);
|
||||
instance.setConfigured(true);
|
||||
instance.setSchedulingEnabled(false);
|
||||
instance.setCronExpression("");
|
||||
instance.setCronMinInterval(0);
|
||||
instance.setWorkflow(wfId);
|
||||
instance.setDestroyWf(null);
|
||||
instance.setSystemParams(new HashMap<>());
|
||||
instance.setUserParams(new HashMap<>());
|
||||
|
||||
return startWorkflowInstance(instance, callback);
|
||||
} catch (final DsmException e) {
|
||||
throw new WorkflowManagerException("Invalid datasource: " + dsId, e);
|
||||
}
|
||||
}
|
||||
|
||||
public String startWorkflowInstance(final String wfInstanceId,
|
||||
final String parent,
|
||||
final ExecutionCallback<WorkflowProcess> callback) throws Exception {
|
||||
|
||||
if (isPaused()) {
|
||||
log.warn("Wf instance " + wfInstanceId + " not launched, because WorkflowExecutor is preparing for shutdown");
|
||||
throw new WorkflowManagerException("WorkflowExecutor is preparing for shutdown");
|
||||
}
|
||||
|
||||
final WorkflowInstance instance = findWorkflowInstance(wfInstanceId);
|
||||
|
||||
return startWorkflowInstance(instance, callback);
|
||||
}
|
||||
|
||||
public String startWorkflowInstance(final WorkflowInstance wfInstance,
|
||||
final ExecutionCallback<WorkflowProcess> callback)
|
||||
throws WorkflowManagerException {
|
||||
|
||||
if (!wfInstance.isEnabled() || !wfInstance.isConfigured()) {
|
||||
log.warn("Wf instance " + wfInstance.getId() + " is not ready to start");
|
||||
throw new WorkflowManagerException("Wf instance " + wfInstance.getId() + " is not ready to start");
|
||||
}
|
||||
|
||||
final SimpleResource wfMetadata = simpleResourceRepository
|
||||
.findById(wfInstance.getWorkflow())
|
||||
.filter(r -> r.getType().equals("workflows"))
|
||||
.orElseThrow(() -> new WorkflowManagerException("WF not found: " + wfInstance.getWorkflow()));
|
||||
|
||||
final WorkflowGraph wfGraph = simpleResourceRepository.findContentById(wfMetadata.getId())
|
||||
.map(s -> {
|
||||
try {
|
||||
return new ObjectMapper().readValue(s, WorkflowGraph.class);
|
||||
} catch (final Exception e) {
|
||||
return (WorkflowGraph) null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.orElseThrow(() -> new WorkflowManagerException("Invalid wf: " + wfMetadata.getId()));
|
||||
|
||||
final WorkflowProcess process =
|
||||
processFactory.newProcess(wfMetadata, wfGraph, wfInstance, callback);
|
||||
|
||||
return processRegistry.registerProcess(process, wfInstance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
paused = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume() {
|
||||
paused = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoppableDetails getStopDetails() {
|
||||
final int count = processRegistry.countRunningWfs();
|
||||
|
||||
final StoppableDetails.StopStatus status =
|
||||
isPaused() ? count == 0 ? StoppableDetails.StopStatus.STOPPED : StoppableDetails.StopStatus.STOPPING : StoppableDetails.StopStatus.RUNNING;
|
||||
|
||||
return new StoppableDetails("D-NET workflow manager", "Running workflows: " + count, status);
|
||||
}
|
||||
|
||||
public ProcessRegistry getProcessRegistry() {
|
||||
return processRegistry;
|
||||
}
|
||||
|
||||
public boolean isPaused() {
|
||||
return paused;
|
||||
}
|
||||
|
||||
public void setPaused(final boolean paused) {
|
||||
this.paused = paused;
|
||||
}
|
||||
|
||||
public Stream<CountedValue> streamSections() {
|
||||
return workflowInstanceRepository.streamSections();
|
||||
}
|
||||
|
||||
public Stream<WorkflowInstance> streamWfInstancesBySection(final String section) {
|
||||
return workflowInstanceRepository.findBySection(section);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package eu.dnetlib.manager.wf.annotations;
|
||||
|
||||
public enum StreamMimeType {
|
||||
XML,
|
||||
JSON,
|
||||
TEXT,
|
||||
UNDEFINED
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package eu.dnetlib.manager.wf.annotations;
|
||||
|
||||
public @interface WfNode {
|
||||
|
||||
String name();
|
||||
|
||||
WfNodeOperation operation();
|
||||
|
||||
Class<?> inputStreamType() default void.class;
|
||||
|
||||
StreamMimeType inputStreamMimeType() default StreamMimeType.UNDEFINED;
|
||||
|
||||
Class<?> outputStreamType() default void.class;
|
||||
|
||||
StreamMimeType outputStreamMimeType() default StreamMimeType.UNDEFINED;
|
||||
|
||||
WfParam[] inputParams() default {};
|
||||
|
||||
WfParam[] outputParams() default {};
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package eu.dnetlib.manager.wf.annotations;
|
||||
|
||||
public enum WfNodeOperation {
|
||||
CREATE,
|
||||
DROP,
|
||||
READ,
|
||||
WRITE,
|
||||
PRODUCER,
|
||||
TRANSFORM,
|
||||
SETENV
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package eu.dnetlib.manager.wf.annotations;
|
||||
|
||||
public @interface WfParam {
|
||||
|
||||
String name();
|
||||
|
||||
String type();
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
package eu.dnetlib.manager.wf.cron;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.scheduling.support.CronExpression;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import eu.dnetlib.manager.history.WorkflowLogger;
|
||||
import eu.dnetlib.manager.wf.WorkflowManagerService;
|
||||
import eu.dnetlib.manager.wf.model.WorkflowInstance;
|
||||
import eu.dnetlib.manager.wf.repository.WorkflowInstanceRepository;
|
||||
import eu.dnetlib.manager.wf.workflows.procs.ProcessRegistry;
|
||||
import eu.dnetlib.manager.wf.workflows.procs.WorkflowProcess;
|
||||
|
||||
@Service
|
||||
public class ScheduledWorkflowLauncher {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ScheduledWorkflowLauncher.class);
|
||||
|
||||
@Autowired
|
||||
private WorkflowManagerService wfManagerService;
|
||||
|
||||
@Autowired
|
||||
private ProcessRegistry processRegistry;
|
||||
|
||||
@Autowired
|
||||
private WorkflowInstanceRepository workflowInstanceRepository;
|
||||
|
||||
@Autowired
|
||||
private WorkflowLogger logger;
|
||||
|
||||
@Value("${dnet.workflow.scheduler.windowSize:1800000}")
|
||||
private int windowSize; // 1800000 are 30 minutes
|
||||
|
||||
@Scheduled(fixedRateString = "${dnet.workflow.scheduler.fixedRate:900000}") // 900000 are 5 minutes
|
||||
public void verifySheduledWorkflows() {
|
||||
log.debug("Verifying scheduled workflows - START");
|
||||
|
||||
workflowInstanceRepository.findAll()
|
||||
.stream()
|
||||
.filter(WorkflowInstance::isEnabled)
|
||||
.filter(WorkflowInstance::isConfigured)
|
||||
.filter(WorkflowInstance::isSchedulingEnabled)
|
||||
.filter(this::isNotRunning)
|
||||
.filter(this::isReady)
|
||||
.forEach(instance -> {
|
||||
try {
|
||||
wfManagerService.startWorkflowInstance(instance, null);
|
||||
} catch (final Exception e) {
|
||||
log.error("Error launching scheduled wf instance: " + instance.getId(), e);
|
||||
}
|
||||
});
|
||||
log.debug("Verifying scheduled workflows - END");
|
||||
}
|
||||
|
||||
private boolean isReady(final WorkflowInstance instance) {
|
||||
final LocalDateTime lastExecutionDate = calculateLastExecutionDate(instance.getId());
|
||||
|
||||
final LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
final String cron = instance.getCronExpression();
|
||||
|
||||
if (CronExpression.isValidExpression(cron)) {
|
||||
final int minInterval = instance.getCronMinInterval(); // in minutes
|
||||
|
||||
final boolean res;
|
||||
if (lastExecutionDate != null) {
|
||||
final long elapsed = ChronoUnit.MINUTES.between(lastExecutionDate, now);
|
||||
res = elapsed > minInterval && verifyCron(cron, now);
|
||||
} else {
|
||||
res = verifyCron(cron, now);
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("**************************************************************");
|
||||
log.debug("WORKFLOW INSTANCE ID : " + instance.getId());
|
||||
log.debug("NOW : " + now);
|
||||
log.debug("LAST EXECUTION DATE : " + lastExecutionDate);
|
||||
log.debug("MIN INTERVAL (minutes) : " + minInterval);
|
||||
log.debug("WINDOW SIZE (ms) : " + windowSize);
|
||||
log.debug("MUST BE EXECUTED : " + res);
|
||||
log.debug("**************************************************************");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private LocalDateTime calculateLastExecutionDate(final String id) {
|
||||
return logger.getLastExecutionForInstance(id)
|
||||
.map(e -> e.getEndDate())
|
||||
.orElse(LocalDateTime.MIN);
|
||||
}
|
||||
|
||||
private boolean verifyCron(final String cronExpression, final LocalDateTime now) {
|
||||
try {
|
||||
final CronExpression cron = CronExpression.parse(cronExpression);
|
||||
|
||||
final LocalDateTime date = now.minus(windowSize, ChronoUnit.MINUTES);
|
||||
final LocalDateTime nextDate = cron.next(date);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("NEXT EXECUTION DATE: " + nextDate);
|
||||
log.debug("FIRED : " + nextDate.isBefore(now));
|
||||
}
|
||||
return nextDate.isBefore(now);
|
||||
} catch (final Exception e) {
|
||||
log.error("Error calculating next cron event: " + cronExpression, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isNotRunning(final WorkflowInstance instance) {
|
||||
final WorkflowProcess p = processRegistry.findProcsByInstanceId(instance.getId());
|
||||
|
||||
if (p != null) {
|
||||
switch (p.getStatus()) {
|
||||
case CREATED:
|
||||
return false;
|
||||
case EXECUTING:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package eu.dnetlib.manager.wf.nodes;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import eu.dnetlib.manager.wf.workflows.procs.Token;
|
||||
import eu.dnetlib.manager.wf.workflows.util.ExecutionCallback;
|
||||
|
||||
public abstract class AbstractJobNode extends ProcessNode {
|
||||
|
||||
private static final Log log = LogFactory.getLog(AbstractJobNode.class);
|
||||
|
||||
private final boolean async;
|
||||
|
||||
public AbstractJobNode(final boolean async) {
|
||||
this.async = async;
|
||||
}
|
||||
|
||||
private final ExecutorService executor = Executors.newCachedThreadPool();
|
||||
|
||||
@Override
|
||||
public final void execute(final Token token, final ExecutionCallback<Token> callback) {
|
||||
try {
|
||||
log.debug("START NODE: " + getBeanName());
|
||||
token.setProgressMessage(getNodeName());
|
||||
|
||||
beforeStart(token);
|
||||
if (isAsync()) {
|
||||
executor.execute(() -> doExecute(token, callback));
|
||||
} else {
|
||||
doExecute(token, callback);
|
||||
}
|
||||
|
||||
log.debug("END NODE (SUCCESS): " + getBeanName());
|
||||
} catch (final Throwable e) {
|
||||
log.error("got exception while executing workflow node", e);
|
||||
log.debug("END NODE (FAILED): " + getBeanName());
|
||||
beforeFailed(token);
|
||||
callback.onFail(token);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final void doExecute(final Token token, final ExecutionCallback<Token> callback) {
|
||||
execute(token);
|
||||
beforeCompleted(token);
|
||||
callback.onSuccess(token);
|
||||
}
|
||||
|
||||
protected abstract void execute(Token token);
|
||||
|
||||
public final boolean isAsync() {
|
||||
return async;
|
||||
}
|
||||
|
||||
protected void beforeStart(final Token token) {
|
||||
// For optional overwrites
|
||||
}
|
||||
|
||||
protected void beforeCompleted(final Token token) {
|
||||
// For optional overwrites
|
||||
}
|
||||
|
||||
protected void beforeFailed(final Token token) {
|
||||
// For optional overwrites
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package eu.dnetlib.manager.wf.nodes;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import eu.dnetlib.manager.wf.annotations.StreamMimeType;
|
||||
import eu.dnetlib.manager.wf.annotations.WfNode;
|
||||
import eu.dnetlib.manager.wf.annotations.WfNodeOperation;
|
||||
import eu.dnetlib.manager.wf.annotations.WfParam;
|
||||
|
||||
@Component("oai_collect")
|
||||
@Scope("prototype")
|
||||
@WfNode(name = "oai_collect", operation = WfNodeOperation.PRODUCER, inputParams = {
|
||||
@WfParam(name = "configuration", type = "ApiDescriptor.class"),
|
||||
}, outputStreamType = String.class, outputStreamMimeType = StreamMimeType.XML)
|
||||
public class CollectOAINode implements Supplier<Stream<String>> {
|
||||
|
||||
private String datasourceID;
|
||||
|
||||
@Override
|
||||
public Stream<String> get() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package eu.dnetlib.manager.wf.nodes;
|
||||
|
||||
import eu.dnetlib.manager.wf.workflows.procs.Token;
|
||||
|
||||
/**
|
||||
* Created by michele on 26/11/15.
|
||||
*/
|
||||
public final class DefaultJobNode extends AbstractJobNode {
|
||||
|
||||
public DefaultJobNode(final String name) {
|
||||
super(false);
|
||||
setNodeName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(final Token token) {}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package eu.dnetlib.manager.wf.nodes;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import eu.dnetlib.manager.wf.WorkflowManagerService;
|
||||
import eu.dnetlib.manager.wf.model.WorkflowInstance;
|
||||
import eu.dnetlib.manager.wf.workflows.procs.ProcessAware;
|
||||
import eu.dnetlib.manager.wf.workflows.procs.Token;
|
||||
import eu.dnetlib.manager.wf.workflows.procs.WorkflowProcess;
|
||||
import eu.dnetlib.manager.wf.workflows.util.ExecutionCallback;
|
||||
|
||||
/**
|
||||
* Created by michele on 18/11/15.
|
||||
*/
|
||||
public class LaunchWorkflowJobNode extends ProcessNode implements ProcessAware {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LaunchWorkflowJobNode.class);
|
||||
|
||||
private String wfId;
|
||||
|
||||
@Autowired
|
||||
private WorkflowManagerService wfManagerService;
|
||||
|
||||
private WorkflowProcess process;
|
||||
|
||||
@Override
|
||||
public final void execute(final Token token, final ExecutionCallback<Token> callback) {
|
||||
|
||||
try {
|
||||
final WorkflowInstance instance = new WorkflowInstance();
|
||||
instance.setId("CHILD_" + UUID.randomUUID());
|
||||
instance.setParentId(process.getWfInstanceId());
|
||||
instance.setDetails(new HashMap<>());
|
||||
instance.setPriority(100);
|
||||
instance.setDsId(process.getDsId());
|
||||
instance.setDsName(process.getDsName());
|
||||
instance.setApiId(process.getDsInterface());
|
||||
instance.setEnabled(true);
|
||||
instance.setConfigured(true);
|
||||
instance.setSchedulingEnabled(false);
|
||||
instance.setCronExpression("");
|
||||
instance.setCronMinInterval(0);
|
||||
instance.setWorkflow(wfId);
|
||||
instance.setDestroyWf(null);
|
||||
instance.setSystemParams(process.getGlobalParams());
|
||||
instance.setUserParams(new HashMap<>());
|
||||
|
||||
final String procId = wfManagerService.startWorkflowInstance(instance, new ExecutionCallback<WorkflowProcess>() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(final WorkflowProcess t) {
|
||||
log.debug("Child workflow has been completed successfully");
|
||||
token.release();
|
||||
callback.onSuccess(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFail(final WorkflowProcess t) {
|
||||
log.error("Child workflow is failed");
|
||||
token.releaseAsFailed("Child workflow is failed");
|
||||
callback.onFail(token);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("The child workflow [instance: " + instance.getId() + "] is starting with procId: " + procId);
|
||||
}
|
||||
|
||||
token.setProgressMessage("Launched sub workflow, proc: " + procId);
|
||||
|
||||
} catch (final Throwable e) {
|
||||
log.error("got exception while launching child workflow", e);
|
||||
callback.onFail(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProcess(final WorkflowProcess process) {
|
||||
this.process = process;
|
||||
}
|
||||
|
||||
public String getWfId() {
|
||||
return wfId;
|
||||
}
|
||||
|
||||
public void setWfId(final String wfId) {
|
||||
this.wfId = wfId;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package eu.dnetlib.manager.wf.nodes;
|
||||
|
||||
public enum NodeStatus {
|
||||
CONFIGURED,
|
||||
NOT_CONFIGURED,
|
||||
DISABLED,
|
||||
SYSTEM
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package eu.dnetlib.manager.wf.nodes;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
|
||||
import eu.dnetlib.manager.wf.workflows.procs.Token;
|
||||
import eu.dnetlib.manager.wf.workflows.util.ExecutionCallback;
|
||||
|
||||
public abstract class ProcessNode implements BeanNameAware {
|
||||
|
||||
private String beanName;
|
||||
|
||||
private String nodeName;
|
||||
|
||||
public abstract void execute(final Token token, ExecutionCallback<Token> callback);
|
||||
|
||||
public String getBeanName() {
|
||||
return this.beanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanName(final String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
public String getNodeName() {
|
||||
return this.nodeName;
|
||||
}
|
||||
|
||||
public void setNodeName(final String nodeName) {
|
||||
this.nodeName = nodeName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[node beanName=%s, name=%s]", this.beanName, this.nodeName);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package eu.dnetlib.manager.wf.nodes;
|
||||
|
||||
public abstract class SimpleJobNode extends AbstractJobNode {
|
||||
|
||||
public SimpleJobNode() {
|
||||
super(false);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package eu.dnetlib.manager.wf.nodes;
|
||||
|
||||
import eu.dnetlib.manager.wf.workflows.procs.Token;
|
||||
|
||||
/**
|
||||
* Created by michele on 26/11/15.
|
||||
*/
|
||||
public class SuccessNode extends AbstractJobNode {
|
||||
|
||||
public SuccessNode() {
|
||||
super(false);
|
||||
setNodeName("success");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(final Token token) {}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package eu.dnetlib.manager.wf.notification;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import eu.dnetlib.manager.wf.model.NotificationCondition;
|
||||
import eu.dnetlib.manager.wf.repository.WorkflowSubscriptionRepository;
|
||||
import eu.dnetlib.manager.wf.workflows.procs.WorkflowProcess;
|
||||
import eu.dnetlib.manager.wf.workflows.procs.WorkflowProcess.Status;
|
||||
import eu.dnetlib.notifications.mail.EmailService;
|
||||
|
||||
@Service
|
||||
public class EmailSender {
|
||||
|
||||
private static final Log log = LogFactory.getLog(EmailSender.class);
|
||||
|
||||
@Autowired
|
||||
private WorkflowSubscriptionRepository wfSubscriptionRepository;
|
||||
|
||||
@Autowired
|
||||
private EmailService emailService;
|
||||
|
||||
public void sendMails(final WorkflowProcess proc) {
|
||||
|
||||
wfSubscriptionRepository.findByWfInstanceId(proc.getWfInstanceId()).forEach(s -> {
|
||||
if (s.getCondition() == NotificationCondition.ALWAYS ||
|
||||
s.getCondition() == NotificationCondition.ONLY_FAILED && proc.getStatus() == Status.FAILURE ||
|
||||
s.getCondition() == NotificationCondition.ONLY_SUCCESS && proc.getStatus() == Status.SUCCESS) {
|
||||
try {
|
||||
final Map<String, Object> params = new HashMap<>();
|
||||
|
||||
emailService.sendStoredMail(s.getEmail(), s.getMessageId(), params);
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Error sending mail to " + s.getEmail(), e);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package eu.dnetlib.manager.wf.workflows.graph;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import eu.dnetlib.manager.wf.workflows.procs.Env;
|
||||
|
||||
public class Arc {
|
||||
|
||||
private final String from;
|
||||
private final String to;
|
||||
private final Function<Env, Boolean> condFunction;
|
||||
|
||||
public Arc(final String from, final String to, final Function<Env, Boolean> condFunction) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.condFunction = condFunction;
|
||||
}
|
||||
|
||||
public String getFrom() {
|
||||
return this.from;
|
||||
}
|
||||
|
||||
public String getTo() {
|
||||
return this.to;
|
||||
}
|
||||
|
||||
public boolean isValid(final Env env) {
|
||||
if (condFunction != null) {
|
||||
return condFunction.apply(env);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[ %s -> %s, %s ]", this.from, this.to, this.condFunction != null ? "with cond" : "without cond");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package eu.dnetlib.manager.wf.workflows.graph;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import eu.dnetlib.manager.wf.workflows.procs.Env;
|
||||
|
||||
public class Graph {
|
||||
|
||||
private final Map<String, GraphNode> nodes = new HashMap<>();
|
||||
private List<Arc> arcs = new ArrayList<>();
|
||||
|
||||
public void addArc(final Arc arc) {
|
||||
this.arcs.add(arc);
|
||||
}
|
||||
|
||||
public void addNode(final GraphNode node) {
|
||||
this.nodes.put(node.getName(), node);
|
||||
}
|
||||
|
||||
public Set<String> nodeNames() {
|
||||
return this.nodes.keySet();
|
||||
}
|
||||
|
||||
public Collection<GraphNode> nodes() {
|
||||
return this.nodes.values();
|
||||
}
|
||||
|
||||
public GraphNode getNode(final String name) {
|
||||
return this.nodes.get(name);
|
||||
}
|
||||
|
||||
public List<Arc> getArcs() {
|
||||
return this.arcs;
|
||||
}
|
||||
|
||||
public void setArcs(final List<Arc> arcs) {
|
||||
this.arcs = arcs;
|
||||
}
|
||||
|
||||
public Set<GraphNode> startNodes() {
|
||||
final Set<GraphNode> res = new HashSet<>();
|
||||
for (final GraphNode n : this.nodes.values()) {
|
||||
if (n.isStart()) {
|
||||
res.add(n);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public Set<GraphNode> nextNodes(final GraphNode current, final Env env) {
|
||||
return arcs.stream()
|
||||
.filter(arc -> StringUtils.equals(arc.getFrom(), current.getName()))
|
||||
.filter(arc -> arc.isValid(env))
|
||||
.map(arc -> arc.getTo())
|
||||
.distinct()
|
||||
.map(to -> nodes.get(to))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
}
|
||||
|
||||
public int getNumberOfIncomingArcs(final GraphNode node) {
|
||||
int count = 0;
|
||||
for (final Arc arc : this.arcs) {
|
||||
if (arc.getTo().equals(node.getName())) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "\n************************\nNodes: " + this.nodes + "\nArcs: " + this.arcs + "\n************************\n";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
package eu.dnetlib.manager.wf.workflows.graph;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.expression.MapAccessor;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import eu.dnetlib.errors.WorkflowManagerException;
|
||||
import eu.dnetlib.manager.wf.model.WorkflowGraph;
|
||||
import eu.dnetlib.manager.wf.workflows.procs.Env;
|
||||
import eu.dnetlib.manager.wf.workflows.util.NodeHelper;
|
||||
|
||||
@Service
|
||||
public class GraphLoader {
|
||||
|
||||
@Autowired
|
||||
private NodeHelper nodeHelper;
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
public Graph loadGraph(final WorkflowGraph workflowGraph, final Map<String, String> globalParams)
|
||||
throws WorkflowManagerException {
|
||||
final Graph graph = new Graph();
|
||||
|
||||
for (final WorkflowGraph.Node node : workflowGraph.getGraph()) {
|
||||
final String nodeName = node.getName();
|
||||
final String nodeType = node.getType();
|
||||
final boolean isStart = node.isStart();
|
||||
final boolean isJoin = node.isJoin();
|
||||
|
||||
final Map<String, Object> params = node.calculateInitialParams(globalParams, environment);
|
||||
final Map<String, String> envParams = node.findEnvParams();
|
||||
|
||||
if (isStart) {
|
||||
graph.addNode(GraphNode.newStartNode(nodeName, nodeType, params, envParams));
|
||||
} else if (isJoin) {
|
||||
graph.addNode(GraphNode.newJoinNode(nodeName, nodeType, params, envParams));
|
||||
} else {
|
||||
graph.addNode(GraphNode.newNode(nodeName, nodeType, params, envParams));
|
||||
}
|
||||
|
||||
if (node.getArcs() != null) {
|
||||
for (final WorkflowGraph.Arc a : node.getArcs()) {
|
||||
final String to = a.getTo();
|
||||
final Function<Env, Boolean> condFunction = generateFunction(a.getCondition());
|
||||
graph.addArc(new Arc(nodeName, to, condFunction));
|
||||
}
|
||||
}
|
||||
|
||||
graph.addNode(GraphNode.newSuccessNode());
|
||||
}
|
||||
|
||||
checkValidity(graph);
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
private Function<Env, Boolean> generateFunction(final String condition) {
|
||||
return env -> {
|
||||
final ExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
final StandardEvaluationContext context = new StandardEvaluationContext(env.getAttributes());
|
||||
context.addPropertyAccessor(new MapAccessor());
|
||||
|
||||
return parser.parseExpression(condition).getValue(context, Boolean.class);
|
||||
};
|
||||
}
|
||||
|
||||
private void checkValidity(final Graph graph) throws WorkflowManagerException {
|
||||
|
||||
final Set<String> nodesFromArcs = new HashSet<>();
|
||||
|
||||
boolean foundSuccess = false;
|
||||
boolean foundStart = false;
|
||||
|
||||
for (final Arc arc : graph.getArcs()) {
|
||||
if (StringUtils.isBlank(arc.getFrom()) || StringUtils.isBlank(arc.getFrom())) {
|
||||
throw new WorkflowManagerException("Invalid arc: missing from e/o to");
|
||||
}
|
||||
if (StringUtils.equals(arc.getTo(), GraphNode.SUCCESS_NODE)) {
|
||||
foundSuccess = true;
|
||||
}
|
||||
nodesFromArcs.add(arc.getFrom());
|
||||
nodesFromArcs.add(arc.getTo());
|
||||
}
|
||||
|
||||
if (!foundSuccess) { throw new WorkflowManagerException("Arc to success not found"); }
|
||||
|
||||
final Set<String> diff = Sets.symmetricDifference(graph.nodeNames(), nodesFromArcs);
|
||||
if (!diff.isEmpty()) { throw new WorkflowManagerException("Missing or invalid nodes in arcs: " + diff); }
|
||||
|
||||
for (final GraphNode n : graph.nodes()) {
|
||||
if (StringUtils.isBlank(n.getName())) { throw new WorkflowManagerException("Invalid node: missing name"); }
|
||||
if (n.isStart()) {
|
||||
foundStart = true;
|
||||
}
|
||||
if (!this.nodeHelper.isValidType(n.getType())) { throw new WorkflowManagerException("Invalid node type: " + n.getType()); }
|
||||
}
|
||||
if (!foundStart) { throw new WorkflowManagerException("Start node not found"); }
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
package eu.dnetlib.manager.wf.workflows.graph;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import eu.dnetlib.manager.wf.workflows.procs.Env;
|
||||
|
||||
public class GraphNode {
|
||||
|
||||
public static final String SUCCESS_NODE = "success";
|
||||
|
||||
private final String name;
|
||||
private final String type;
|
||||
private final boolean isStart;
|
||||
private final boolean isJoin;
|
||||
private final boolean isSucessNode;
|
||||
private final Map<String, Object> params;
|
||||
private final Map<String, String> envParams;
|
||||
|
||||
private GraphNode(final String name,
|
||||
final String type,
|
||||
final boolean isStart,
|
||||
final boolean isJoin,
|
||||
final boolean isSuccessNode,
|
||||
final Map<String, Object> params,
|
||||
final Map<String, String> envParams) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.isStart = isStart;
|
||||
this.isJoin = isJoin;
|
||||
this.isSucessNode = isSuccessNode;
|
||||
this.params = params;
|
||||
this.envParams = envParams;
|
||||
}
|
||||
|
||||
public static GraphNode newNode(final String name,
|
||||
final String type,
|
||||
final Map<String, Object> params,
|
||||
final Map<String, String> envParams) {
|
||||
return new GraphNode(name, type, false, false, false, params, envParams);
|
||||
}
|
||||
|
||||
public static GraphNode newStartNode(final String name,
|
||||
final String type,
|
||||
final Map<String, Object> params,
|
||||
final Map<String, String> envParams) {
|
||||
return new GraphNode(name, type, true, false, false, params, envParams);
|
||||
}
|
||||
|
||||
public static GraphNode newJoinNode(final String name,
|
||||
final String type,
|
||||
final Map<String, Object> params,
|
||||
final Map<String, String> envParams) {
|
||||
return new GraphNode(name, type, false, true, false, params, envParams);
|
||||
}
|
||||
|
||||
public static GraphNode newSuccessNode() {
|
||||
return new GraphNode(SUCCESS_NODE, null, false, true, true, new HashMap<>(), new HashMap<>());
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public boolean isStart() {
|
||||
return this.isStart;
|
||||
}
|
||||
|
||||
public boolean isJoin() {
|
||||
return this.isJoin;
|
||||
}
|
||||
|
||||
public boolean isSucessNode() {
|
||||
return this.isSucessNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringWriter sw = new StringWriter();
|
||||
sw.append("[ name: ");
|
||||
sw.append(this.name);
|
||||
if (StringUtils.isNotBlank(this.type)) {
|
||||
sw.append(", type: ");
|
||||
sw.append(this.type);
|
||||
}
|
||||
if (isStart()) {
|
||||
sw.append(" - isStart");
|
||||
}
|
||||
if (isJoin()) {
|
||||
sw.append(" - isJoin");
|
||||
}
|
||||
sw.append(" ]");
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
public Map<String, Object> getParams() {
|
||||
return this.params;
|
||||
}
|
||||
|
||||
public Map<String, String> getEnvParams() {
|
||||
return this.envParams;
|
||||
}
|
||||
|
||||
public Map<String, Object> resolveParamsWithNoEnv() {
|
||||
return resolveParams(null);
|
||||
}
|
||||
|
||||
public Map<String, Object> resolveParams(final Env env) {
|
||||
final Map<String, Object> map = new HashMap<>();
|
||||
|
||||
if (this.params != null) {
|
||||
this.params.forEach((k, v) -> map.put(k, v));
|
||||
}
|
||||
|
||||
if (this.envParams != null && env != null) {
|
||||
this.envParams.forEach((k, v) -> map.put(k, env.getAttribute(v)));
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package eu.dnetlib.manager.wf.workflows.procs;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by michele on 23/11/15.
|
||||
*/
|
||||
public class Env {
|
||||
|
||||
private final Map<String, Object> attrs;
|
||||
|
||||
public Env() {
|
||||
this.attrs = new HashMap<>();
|
||||
}
|
||||
|
||||
public Env(final Map<String, Object> attrs) {
|
||||
this.attrs = attrs;
|
||||
}
|
||||
|
||||
public Map<String, Object> getAttributes() {
|
||||
return attrs;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
attrs.clear();
|
||||
}
|
||||
|
||||
public void addAttributes(final Map<String, Object> map) {
|
||||
if (map != null) {
|
||||
attrs.putAll(map);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAttribute(final String name, final Object value) {
|
||||
attrs.put(name, value);
|
||||
}
|
||||
|
||||
public Object getAttribute(final String name) {
|
||||
return attrs.get(name);
|
||||
}
|
||||
|
||||
public <T> T getAttribute(final String name, Class<T> clazz) {
|
||||
return clazz.cast(attrs.get(name));
|
||||
}
|
||||
|
||||
public boolean hasAttribute(final String name) {
|
||||
return attrs.containsKey(name);
|
||||
}
|
||||
|
||||
public Object removeAttribute(final String name) {
|
||||
return attrs.remove(name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package eu.dnetlib.manager.wf.workflows.procs;
|
||||
|
||||
/**
|
||||
* Created by michele on 24/11/15.
|
||||
*/
|
||||
public interface ProcessAware {
|
||||
|
||||
void setProcess(WorkflowProcess process);
|
||||
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package eu.dnetlib.manager.wf.workflows.procs;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import eu.dnetlib.manager.history.WorkflowLogger;
|
||||
import eu.dnetlib.manager.wf.nodes.ProcessNode;
|
||||
import eu.dnetlib.manager.wf.notification.EmailSender;
|
||||
import eu.dnetlib.manager.wf.workflows.graph.GraphNode;
|
||||
import eu.dnetlib.manager.wf.workflows.util.ExecutionCallback;
|
||||
import eu.dnetlib.manager.wf.workflows.util.NodeHelper;
|
||||
|
||||
@Service
|
||||
public class ProcessEngine {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ProcessEngine.class);
|
||||
|
||||
@Autowired
|
||||
private NodeHelper nodeHelper;
|
||||
@Autowired
|
||||
private EmailSender emailSender;
|
||||
@Autowired
|
||||
private WorkflowLogger wfLogger;
|
||||
|
||||
public void startProcess(final WorkflowProcess process) {
|
||||
log.info(process.getGraph());
|
||||
|
||||
log.info("Starting workflow: " + process);
|
||||
|
||||
final LocalDateTime now = LocalDateTime.now();
|
||||
process.setStatus(WorkflowProcess.Status.EXECUTING);
|
||||
process.setStartDate(now);
|
||||
process.setLastActivityDate(now);
|
||||
|
||||
try {
|
||||
for (final GraphNode node : process.getGraph().startNodes()) {
|
||||
final ProcessNode pNode = nodeHelper.newProcessNode(node, process, process.getEnv());
|
||||
final Token token = new Token();
|
||||
token.getEnv().addAttributes(process.getEnv().getAttributes());
|
||||
process.getTokens().add(token);
|
||||
|
||||
pNode.execute(token, newNodeCallback(process, node));
|
||||
}
|
||||
} catch (final Throwable e) {
|
||||
log.error("WorkflowProcess node instantiation failed", e);
|
||||
process.setStatus(WorkflowProcess.Status.FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
private ExecutionCallback<Token> newNodeCallback(final WorkflowProcess process, final GraphNode node) {
|
||||
return new ExecutionCallback<Token>() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(final Token t) {
|
||||
releaseToken(process, node, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFail(final Token t) {
|
||||
completeProcess(process, t);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void releaseToken(final WorkflowProcess process, final GraphNode oldGraphNode, final Token oldToken) {
|
||||
process.setLastActivityDate(LocalDateTime.now());
|
||||
|
||||
try {
|
||||
for (final GraphNode node : process.getGraph().nextNodes(oldGraphNode, oldToken.getEnv())) {
|
||||
if (node.isJoin() || node.isSucessNode()) {
|
||||
if (!process.getPausedJoinNodeTokens().containsKey(node.getName())) {
|
||||
process.getPausedJoinNodeTokens().put(node.getName(), new ArrayList<Token>());
|
||||
}
|
||||
|
||||
final List<Token> list = process.getPausedJoinNodeTokens().get(node.getName());
|
||||
|
||||
list.add(oldToken);
|
||||
|
||||
if (list.size() == process.getGraph().getNumberOfIncomingArcs(node)) {
|
||||
final Token token = new Token();
|
||||
token.getEnv().addAttributes(mergeEnvParams(list.toArray(new Token[list.size()])));
|
||||
final ProcessNode pNode = nodeHelper.newProcessNode(node, process, token.getEnv());
|
||||
|
||||
process.getTokens().add(token);
|
||||
process.setLastActivityDate(LocalDateTime.now());
|
||||
|
||||
if (node.isSucessNode()) {
|
||||
completeProcess(process, token);
|
||||
} else {
|
||||
pNode.execute(token, newNodeCallback(process, node));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final Token token = new Token();
|
||||
token.getEnv().addAttributes(oldToken.getEnv().getAttributes());
|
||||
final ProcessNode pNode = nodeHelper.newProcessNode(node, process, token.getEnv());
|
||||
|
||||
process.getTokens().add(token);
|
||||
process.setLastActivityDate(LocalDateTime.now());
|
||||
pNode.execute(token, newNodeCallback(process, node));
|
||||
}
|
||||
}
|
||||
} catch (final Throwable e) {
|
||||
log.error("WorkflowProcess node instantiation failed", e);
|
||||
process.setStatus(WorkflowProcess.Status.FAILURE);
|
||||
process.setError(e.getMessage());
|
||||
process.setErrorStacktrace(Throwables.getStackTraceAsString(e));
|
||||
process.setLastActivityDate(LocalDateTime.now());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Map<String, Object> mergeEnvParams(final Token... tokens) {
|
||||
final Map<String, Object> map = new HashMap<>();
|
||||
Arrays.stream(tokens).forEach(t -> map.putAll(t.getEnv().getAttributes()));
|
||||
return map;
|
||||
}
|
||||
|
||||
private void completeProcess(final WorkflowProcess process, final Token token) {
|
||||
token.checkStatus();
|
||||
process.complete(token);
|
||||
wfLogger.saveProcessExecution(process.asLog());
|
||||
emailSender.sendMails(process);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package eu.dnetlib.manager.wf.workflows.procs;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import eu.dnetlib.errors.WorkflowManagerException;
|
||||
import eu.dnetlib.is.model.resource.SimpleResource;
|
||||
import eu.dnetlib.manager.wf.model.WorkflowGraph;
|
||||
import eu.dnetlib.manager.wf.model.WorkflowInstance;
|
||||
import eu.dnetlib.manager.wf.workflows.graph.Graph;
|
||||
import eu.dnetlib.manager.wf.workflows.graph.GraphLoader;
|
||||
import eu.dnetlib.manager.wf.workflows.util.ExecutionCallback;
|
||||
|
||||
@Component
|
||||
public class ProcessFactory {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ProcessFactory.class);
|
||||
|
||||
private String oldGeneratedId = "";
|
||||
|
||||
private final DateTimeFormatter processIdFormatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss_S");
|
||||
|
||||
@Autowired
|
||||
private GraphLoader graphLoader;
|
||||
|
||||
public WorkflowProcess newProcess(final SimpleResource wfMetadata,
|
||||
final WorkflowGraph wfGraph,
|
||||
final WorkflowInstance wfInstance,
|
||||
final ExecutionCallback<WorkflowProcess> callback) throws WorkflowManagerException {
|
||||
|
||||
final Map<String, String> globalParams = new HashMap<>();
|
||||
globalParams.putAll(wfInstance.getSystemParams());
|
||||
globalParams.putAll(wfInstance.getUserParams());
|
||||
|
||||
final Graph graph = graphLoader.loadGraph(wfGraph, globalParams);
|
||||
|
||||
return new WorkflowProcess(generateProcessId(), wfMetadata, wfInstance, graph, globalParams, callback);
|
||||
|
||||
}
|
||||
|
||||
private synchronized String generateProcessId() {
|
||||
String id = "";
|
||||
do {
|
||||
id = "wf_" + LocalDateTime.now().format(processIdFormatter);
|
||||
log.info("Generated processID " + id);
|
||||
} while (id.equals(oldGeneratedId));
|
||||
|
||||
oldGeneratedId = id;
|
||||
|
||||
return id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package eu.dnetlib.manager.wf.workflows.procs;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.PriorityBlockingQueue;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import eu.dnetlib.errors.WorkflowManagerException;
|
||||
import eu.dnetlib.manager.wf.model.WorkflowInstance;
|
||||
import eu.dnetlib.manager.wf.workflows.util.WorkflowsConstants;
|
||||
|
||||
@Service
|
||||
public class ProcessRegistry {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ProcessRegistry.class);
|
||||
private final Map<String, WorkflowProcess> procs = new HashMap<>();
|
||||
private final Map<String, WorkflowProcess> byInstanceId = new HashMap<>();
|
||||
|
||||
private final PriorityBlockingQueue<WorkflowProcess> pendingProcs = new PriorityBlockingQueue<>();
|
||||
|
||||
@Value("${dnet.wf.registry.size:100}")
|
||||
private int maxSize;
|
||||
|
||||
synchronized public int countRunningWfs() {
|
||||
int count = 0;
|
||||
for (final Map.Entry<String, WorkflowProcess> e : this.procs.entrySet()) {
|
||||
final WorkflowProcess proc = e.getValue();
|
||||
if (!proc.isTerminated()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public WorkflowProcess findProcess(final String procId) {
|
||||
return this.procs.get(procId);
|
||||
}
|
||||
|
||||
public Collection<WorkflowProcess> listProcesses() {
|
||||
return this.procs.values();
|
||||
}
|
||||
|
||||
public WorkflowProcess findProcsByInstanceId(final String id) {
|
||||
return this.byInstanceId.get(id);
|
||||
}
|
||||
|
||||
public String registerProcess(final WorkflowProcess process, final WorkflowInstance wfInstance) throws WorkflowManagerException {
|
||||
if (this.procs.containsValue(process) || this.procs.containsKey(process.getId())) {
|
||||
log.error("Already registerd process: " + process);
|
||||
throw new WorkflowManagerException("Already registerd process: " + process);
|
||||
}
|
||||
|
||||
if (this.procs.size() >= this.maxSize) {
|
||||
removeOldestProcess();
|
||||
}
|
||||
|
||||
this.procs.put(process.getId(), process);
|
||||
this.byInstanceId.put(wfInstance.getId(), process);
|
||||
|
||||
synchronized (this.pendingProcs) {
|
||||
if (this.pendingProcs.size() > WorkflowsConstants.MAX_PENDING_PROCS_SIZE) {
|
||||
log.warn("Wf [" + process.getName() + "] not launched, Max number of pending procs reached: " + WorkflowsConstants.MAX_PENDING_PROCS_SIZE);
|
||||
throw new WorkflowManagerException("Max number of pending procs reached: " + WorkflowsConstants.MAX_PENDING_PROCS_SIZE);
|
||||
}
|
||||
this.pendingProcs.put(process);
|
||||
|
||||
log.info("WorkflowProcess [" + process + "] in queue, priority=" + process.getPriority());
|
||||
}
|
||||
|
||||
return process.getId();
|
||||
}
|
||||
|
||||
private void removeOldestProcess() {
|
||||
LocalDateTime oldDate = LocalDateTime.now();
|
||||
String oldId = null;
|
||||
|
||||
for (final Map.Entry<String, WorkflowProcess> e : this.procs.entrySet()) {
|
||||
final WorkflowProcess proc = e.getValue();
|
||||
|
||||
if (proc.isTerminated()) {
|
||||
final LocalDateTime date = proc.getLastActivityDate();
|
||||
if (date.isBefore(oldDate)) {
|
||||
oldDate = date;
|
||||
oldId = e.getKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (oldId != null) {
|
||||
unregisterProcess(oldId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void unregisterProcess(final String procId) {
|
||||
synchronized (this) {
|
||||
final WorkflowProcess process = this.procs.remove(procId);
|
||||
if (process != null) {
|
||||
final Optional<String> instanceId = this.byInstanceId.entrySet()
|
||||
.stream()
|
||||
.filter(e -> e.getValue().getId().equals(process.getId()))
|
||||
.map(e -> e.getKey())
|
||||
.findFirst();
|
||||
if (instanceId.isPresent()) {
|
||||
this.byInstanceId.remove(instanceId, process);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public WorkflowProcess nextProcessToStart() {
|
||||
synchronized (this.pendingProcs) {
|
||||
return this.pendingProcs.poll();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
package eu.dnetlib.manager.wf.workflows.procs;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
/**
|
||||
* Created by michele on 19/11/15.
|
||||
*/
|
||||
public class Token {
|
||||
|
||||
private final String id;
|
||||
private final Env env = new Env();
|
||||
|
||||
private String progressMessage;
|
||||
private final LocalDateTime startDate;
|
||||
private LocalDateTime endDate;
|
||||
|
||||
private boolean failed;
|
||||
private boolean active;
|
||||
|
||||
private String error = "";
|
||||
private String errorStackTrace = "";
|
||||
|
||||
public Token() {
|
||||
this.id = "token-" + UUID.randomUUID();
|
||||
this.startDate = LocalDateTime.now();
|
||||
this.failed = false;
|
||||
this.active = true;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public Env getEnv() {
|
||||
return this.env;
|
||||
}
|
||||
|
||||
public LocalDateTime getStartDate() {
|
||||
return this.startDate;
|
||||
}
|
||||
|
||||
public LocalDateTime getEndDate() {
|
||||
return this.endDate;
|
||||
}
|
||||
|
||||
public void setEndDate(final LocalDateTime endDate) {
|
||||
this.endDate = endDate;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return this.active;
|
||||
}
|
||||
|
||||
public void setActive(final boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public boolean isFailed() {
|
||||
return this.failed;
|
||||
}
|
||||
|
||||
public void setFailed(final boolean failed) {
|
||||
this.failed = failed;
|
||||
}
|
||||
|
||||
public void release() {
|
||||
setEndDate(LocalDateTime.now());
|
||||
setActive(false);
|
||||
}
|
||||
|
||||
public void releaseAsFailed(final Throwable e) {
|
||||
setEndDate(LocalDateTime.now());
|
||||
setActive(false);
|
||||
setFailed(true);
|
||||
setError(e.getMessage());
|
||||
setErrorStackTrace(Throwables.getStackTraceAsString(e));
|
||||
}
|
||||
|
||||
public void releaseAsFailed(final String error) {
|
||||
setEndDate(LocalDateTime.now());
|
||||
setActive(false);
|
||||
setFailed(true);
|
||||
setError(error);
|
||||
}
|
||||
|
||||
public void checkStatus() {
|
||||
if (isActive()) {
|
||||
if (StringUtils.isNotBlank(error)) {
|
||||
releaseAsFailed(error);
|
||||
} else {
|
||||
release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getProgressMessage() {
|
||||
return progressMessage;
|
||||
}
|
||||
|
||||
public void setProgressMessage(final String progressMessage) {
|
||||
this.progressMessage = progressMessage;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return this.error;
|
||||
}
|
||||
|
||||
public void setError(final String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public String getErrorStackTrace() {
|
||||
return this.errorStackTrace;
|
||||
}
|
||||
|
||||
public void setErrorStackTrace(final String errorStackTrace) {
|
||||
this.errorStackTrace = errorStackTrace;
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue