Project

General

Profile

1
package eu.dnetlib.services;
2

    
3
import java.io.File;
4
import java.lang.annotation.Annotation;
5
import java.util.ArrayList;
6
import java.util.HashMap;
7
import java.util.List;
8
import java.util.Map;
9
import java.util.UUID;
10

    
11
import javax.annotation.PostConstruct;
12

    
13
import org.apache.commons.lang3.StringUtils;
14
import org.apache.commons.logging.Log;
15
import org.apache.commons.logging.LogFactory;
16
import org.dom4j.Element;
17
import org.springframework.beans.factory.annotation.Autowired;
18
import org.springframework.context.Lifecycle;
19
import org.springframework.web.bind.annotation.PathVariable;
20
import org.springframework.web.bind.annotation.RequestBody;
21
import org.springframework.web.bind.annotation.RequestMapping;
22
import org.springframework.web.bind.annotation.RequestMethod;
23
import org.springframework.web.bind.annotation.RequestParam;
24
import org.springframework.web.bind.annotation.RestController;
25
import org.springframework.web.client.RestTemplate;
26

    
27
import eu.dnetlib.conf.DnetGenericApplicationProperties;
28
import eu.dnetlib.enabling.annotations.DnetService;
29
import eu.dnetlib.enabling.annotations.DnetServiceType;
30
import eu.dnetlib.exceptions.DnetGenericException;
31
import eu.dnetlib.services.async.AsyncClientUtils;
32
import eu.dnetlib.services.async.AsyncResponse;
33
import eu.dnetlib.services.async.AsyncRunnable;
34
import eu.dnetlib.services.async.AsyncServerCallback;
35
import eu.dnetlib.services.async.HasAsyncMethods;
36
import eu.dnetlib.services.async.ResponseAck;
37
import eu.dnetlib.services.async.ResponseAck.ResponseAckStatus;
38

    
39
public abstract class BaseService implements Lifecycle {
40

    
41
	private static final Log log = LogFactory.getLog(BaseService.class);
42

    
43
	private boolean started = false;
44

    
45
	private String profileId;
46

    
47
	private String baseUrl;
48

    
49
	private Map<String, String> serviceProperties = new HashMap<>();
50

    
51
	private Map<String, String> extraProtocols = new HashMap<>();
52

    
53
	private DnetServiceType serviceType;
54

    
55
	@Autowired
56
	private DnetGenericApplicationProperties containerConfiguration;
57

    
58
	@Autowired
59
	private AsyncClientUtils asyncClientUtils;
60

    
61
	@PostConstruct
62
	public void init() throws DnetGenericException {
63

    
64
		verifyRequiredAnnotations(DnetService.class);
65
		verifyRequiredAnnotations(RestController.class);
66
		verifyRequiredAnnotations(RequestMapping.class);
67

    
68
		serviceType = getClass().getAnnotation(DnetService.class).value();
69
		baseUrl = containerConfiguration.getUrl() + getClass().getAnnotation(RequestMapping.class).value()[0];
70

    
71
		final File dir = new File(containerConfiguration.getBaseDir());
72
		if (!dir.exists()) {
73
			dir.mkdirs();
74
		}
75
	}
76

    
77
	private void verifyRequiredAnnotations(final Class<? extends Annotation> a) throws DnetGenericException {
78
		if (!getClass().isAnnotationPresent(a)) {
79
			final String message = "A required annotation is missing (@" + a.getSimpleName() + ") in class " + getClass();
80
			log.error(message);
81
			throw new DnetGenericException(message);
82
		}
83
	}
84

    
85
	@Override
86
	public void start() {
87
		log.info("Starting service " + serviceType);
88
		if (started) {
89
			log.warn("Service " + this + "already started, check bean initializations!");
90
		}
91
		started = true;
92
	}
93

    
94
	@Override
95
	public boolean isRunning() {
96
		log.debug("called isRunning " + this);
97
		return false;
98
	}
99

    
100
	@Override
101
	public void stop() {
102
		log.info("Stopping service " + this);
103
	}
104

    
105
	@RequestMapping(value = "", method = RequestMethod.GET)
106
	public ServiceRunningInstance getStatus() {
107
		return ServiceRunningInstance.newInstance(profileId, baseUrl, baseDir());
108
	}
109

    
110
	@RequestMapping(value = "async/response/{id}", method = RequestMethod.POST)
111
	public final ResponseAck asyncResponse(@PathVariable final String id, @RequestBody final AsyncResponse response) {
112
		return asyncClientUtils.processResponse(id, response) ? ResponseAck.OK : ResponseAck.IGNORED;
113
	}
114

    
115
	@RequestMapping(value = "async/method/{method}", method = RequestMethod.POST)
116
	public final AsyncInvocation asyncMethod(@PathVariable final String method,
117
			@RequestParam(required = false) final String caller,
118
			@RequestBody final String jsonParams)
119
			throws DnetGenericException {
120

    
121
		log.info("Starting async method: " + method);
122

    
123
		if (this instanceof HasAsyncMethods) {
124

    
125
			final AsyncInvocation async = new AsyncInvocation("invocation-" + UUID.randomUUID());
126

    
127
			log.info("Async invocation:" + async.getId());
128

    
129
			final AsyncServerCallback callback =
130
					StringUtils.isNotBlank(caller) ? res -> sendResponse(caller + "/async/response/" + async.getId(), res) : res -> {};
131

    
132
			final AsyncRunnable runnable = ((HasAsyncMethods) this).createAsyncJob(method, jsonParams, callback);
133

    
134
			async.setInfo(runnable.prepare());
135

    
136
			(new Thread(runnable)).start();
137

    
138
			return async;
139

    
140
		} else {
141
			log.error("Service " + getServiceType() + " does not implement HasAsyncMethods interface");
142
			throw new DnetGenericException("Service " + getServiceType() + " does not implement HasAsyncMethods interface");
143
		}
144

    
145
	}
146

    
147
	private ResponseAckStatus sendResponse(final String url, final AsyncResponse res) {
148
		log.info("***************************************************");
149
		log.info("* Sending response to : " + url);
150
		log.info("* Status              : " + res.getStatus());
151
		log.info("* Message             : " + res.getResponseJson());
152
		log.info("***************************************************");
153

    
154
		return (new RestTemplate()).postForObject(url, res, ResponseAck.class).getStatus();
155
	}
156

    
157
	protected String baseDir() {
158
		return containerConfiguration.getBaseDir();
159
	}
160

    
161
	public String getProfileId() {
162
		return profileId;
163
	}
164

    
165
	public void setProfileId(final String profileId) {
166
		this.profileId = profileId;
167
	}
168

    
169
	public Map<String, String> getServiceProperties() {
170
		return serviceProperties;
171
	}
172

    
173
	public List<Element> geXmlProfileSections() {
174
		return new ArrayList<>();
175
	}
176

    
177
	public void setServiceProperties(final Map<String, String> serviceProperties) {
178
		this.serviceProperties = serviceProperties;
179
	}
180

    
181
	public Map<String, String> getExtraProtocols() {
182
		return extraProtocols;
183
	}
184

    
185
	public void setExtraProtocols(final Map<String, String> extraProtocols) {
186
		this.extraProtocols = extraProtocols;
187
	}
188

    
189
	public DnetServiceType getServiceType() {
190
		return serviceType;
191
	}
192

    
193
	public void setServiceType(final DnetServiceType serviceType) {
194
		this.serviceType = serviceType;
195
	}
196

    
197
	public String getBaseUrl() {
198
		return baseUrl;
199
	}
200

    
201
	public void setBaseUrl(final String baseUrl) {
202
		this.baseUrl = baseUrl;
203
	}
204

    
205
}
(4-4/7)