Project

General

Profile

1
package eu.dnetlib.functionality.modular.ui.repositories;
2

    
3
import java.io.IOException;
4
import java.util.Date;
5
import java.util.List;
6
import java.util.Map;
7

    
8
import javax.annotation.Resource;
9
import javax.servlet.http.HttpServletRequest;
10
import javax.servlet.http.HttpServletResponse;
11

    
12
import org.apache.commons.io.IOUtils;
13
import org.apache.commons.lang.exception.ExceptionUtils;
14
import org.apache.commons.lang3.StringUtils;
15
import org.apache.commons.logging.Log;
16
import org.apache.commons.logging.LogFactory;
17
import org.codehaus.jackson.JsonNode;
18
import org.codehaus.jackson.map.ObjectMapper;
19
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
20
import org.codehaus.jackson.node.ObjectNode;
21
import org.springframework.beans.factory.annotation.Autowired;
22
import org.springframework.beans.factory.annotation.Value;
23
import org.springframework.cache.annotation.CacheEvict;
24
import org.springframework.cache.annotation.Cacheable;
25
import org.springframework.http.HttpStatus;
26
import org.springframework.stereotype.Controller;
27
import org.springframework.ui.ModelMap;
28
import org.springframework.web.bind.annotation.ExceptionHandler;
29
import org.springframework.web.bind.annotation.RequestBody;
30
import org.springframework.web.bind.annotation.RequestMapping;
31
import org.springframework.web.bind.annotation.RequestMethod;
32
import org.springframework.web.bind.annotation.RequestParam;
33
import org.springframework.web.bind.annotation.ResponseBody;
34
import org.springframework.web.bind.annotation.ResponseStatus;
35
import org.springframework.web.client.RestTemplate;
36

    
37
import com.google.common.collect.Maps;
38
import com.google.gson.Gson;
39
import com.google.gson.reflect.TypeToken;
40

    
41
import eu.dnetlib.data.collector.rmi.CollectorService;
42
import eu.dnetlib.data.collector.rmi.CollectorServiceException;
43
import eu.dnetlib.data.collector.rmi.ProtocolParameterValue;
44
import eu.dnetlib.enabling.datasources.common.Api;
45
import eu.dnetlib.enabling.datasources.common.ApiParam;
46
import eu.dnetlib.enabling.datasources.common.ApiParamImpl;
47
import eu.dnetlib.enabling.datasources.common.BrowsableField;
48
import eu.dnetlib.enabling.datasources.common.BrowseTerm;
49
import eu.dnetlib.enabling.datasources.common.Datasource;
50
import eu.dnetlib.enabling.datasources.common.DsmException;
51
import eu.dnetlib.enabling.datasources.common.Identity;
52
import eu.dnetlib.enabling.datasources.common.LocalDatasourceManager;
53
import eu.dnetlib.enabling.datasources.common.Organization;
54
import eu.dnetlib.enabling.datasources.common.PidSystem;
55
import eu.dnetlib.enabling.datasources.common.SearchApisEntry;
56
import eu.dnetlib.enabling.datasources.common.SimpleDatasource;
57
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
58
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
59
import eu.dnetlib.enabling.locators.UniqueServiceLocator;
60
import eu.dnetlib.functionality.modular.ui.error.ErrorMessage;
61
import eu.dnetlib.functionality.modular.ui.repositories.objects.RepoInterfaceEntry;
62
import eu.dnetlib.functionality.modular.ui.workflows.objects.sections.WorkflowSectionGrouper;
63
import eu.dnetlib.msro.workflows.sarasvati.loader.WorkflowExecutor;
64
import eu.dnetlib.msro.workflows.util.WorkflowsConstants;
65

    
66
@Controller
67
public class RepoInternalController {
68

    
69
	@Autowired
70
	private LocalDatasourceManager<Datasource<?, ?, ?>, Api<?>> dsManager;
71

    
72
	@Resource
73
	private UniqueServiceLocator serviceLocator;
74

    
75
	@Resource
76
	private WorkflowSectionGrouper workflowSectionGrouper;
77

    
78
	@Resource
79
	private WorkflowExecutor workflowExecutor;
80

    
81
	@Resource
82
	private RepoUIUtils repoUIUtils;
83

    
84
	@Value("${repo.ui.mdstore.sync.button}")
85
	private String syncButton;
86

    
87
	@Value("${repo.ui.mdstore.sync.remote.desc}")
88
	private String syncDesc;
89

    
90
	@Value("${repo.ui.mdstore.sync.remote.api.baseUrl}")
91
	private String syncApiBaseUrl;
92

    
93
	@Value("${repo.ui.mdstore.sync.remote.is.baseUrl}")
94
	private String syncISBaseUrl;
95

    
96
	@Value("${repo.ui.mdstore.sync.local.mongodb.url}")
97
	private String mongoUrl;
98

    
99
	@Value("${services.mdstore.mongodb.db}")
100
	private String mongoDb;
101

    
102
	private static final Log log = LogFactory.getLog(RepoInternalController.class);
103

    
104
	@RequestMapping(value = "/ui/browseRepoField.do")
105
	public @ResponseBody List<? extends BrowseTerm> browseRepoField(@RequestParam(value = "field", required = true) final String field) throws Exception {
106
		return dsManager.browseField(field);
107
	}
108

    
109
	@Cacheable(cacheNames = "repoUIJsonCache", key = "#param, #value", condition = "#refresh == false")
110
	@RequestMapping(value = "/ui/listApis.do")
111
	public @ResponseBody List<? extends SearchApisEntry> listApis(
112
		@RequestParam(value = "param", required = true) final String param,
113
		@RequestParam(value = "value", required = true) final String value,
114
		@RequestParam(value = "refresh", required = false) final String refresh) throws Exception {
115

    
116
		return dsManager.searchApis(param, value);
117
	}
118

    
119
	@RequestMapping(value = "/ui/listRepositories.json")
120
	public @ResponseBody List<SimpleDatasource> listRepositories(@RequestParam(value = "type", required = true) final String type) throws Exception {
121
		return dsManager.searchDatasourcesByType(type);
122
	}
123

    
124
	@CacheEvict("repoUIJsonCache")
125
	@RequestMapping(value = "/ui/validateRepo.do")
126
	public @ResponseBody String listRepositories(@RequestParam(value = "id", required = true) final String id,
127
		@RequestParam(value = "b", required = true) final boolean b) throws Exception {
128

    
129
		final String query = "count(/*[.//RESOURCE_TYPE/@value='MetaWorkflowDSResourceType' and .//DATAPROVIDER/@id='" + id + "'])";
130
		if (!b && Integer.parseInt(serviceLocator.getService(ISLookUpService.class).getResourceProfileByQuery(query)) > 0) {
131
			throw new Exception("Repo " + id
132
				+ " can be invalidated: it is related to some metawfs");
133
		}
134

    
135
		final String newId = b ? serviceLocator.getService(ISRegistryService.class).validateProfile(id)
136
			: serviceLocator.getService(ISRegistryService.class).invalidateProfile(id);
137

    
138
		return newId;
139
	}
140

    
141
	@RequestMapping(value = "/ui/getRepoDetails.do")
142
	public void getRepoDetails(final HttpServletResponse response, @RequestParam(value = "id", required = true) final String id)
143
		throws Exception {
144
		final Datasource<?, ?, ?> ds = dsManager.getDs(id);
145
		final List<? extends Api<?>> apis = dsManager.getApis(id);
146

    
147
		final ObjectMapper mapper = new ObjectMapper();
148
		mapper.setSerializationInclusion(Inclusion.NON_EMPTY);
149

    
150
		final JsonNode jsonDs = mapper.valueToTree(ds);
151
		((ObjectNode) jsonDs).put("apis", mapper.valueToTree(apis));
152

    
153
		response.setContentType("application/json;charset=UTF-8");
154

    
155
		IOUtils.write(jsonDs.toString(), response.getOutputStream());
156
	}
157

    
158
	@RequestMapping("/ui/repoMetaWf.new")
159
	public @ResponseBody String newDataProviderWorkflow(@RequestParam(value = "id", required = true) final String repoId,
160
		@RequestParam(value = "name", required = true) final String repoName,
161
		@RequestParam(value = "iface", required = true) final String ifaceId,
162
		@RequestParam(value = "wf", required = true) final String wfId) throws Exception {
163

    
164
		final Map<String, Object> params = Maps.newHashMap();
165
		params.put(WorkflowsConstants.DATAPROVIDER_ID, repoId);
166
		params.put(WorkflowsConstants.DATAPROVIDER_NAME, repoName);
167
		params.put(WorkflowsConstants.DATAPROVIDER_INTERFACE, ifaceId);
168

    
169
		return workflowExecutor.startProcess(wfId, params);
170
	}
171

    
172
	@RequestMapping("/ui/repoMetaWf.destroy")
173
	public @ResponseBody String destroyDataProviderWorkflow(@RequestParam(value = "destroyWf", required = true) final String destroyWfId)
174
		throws Exception {
175
		return workflowExecutor.startProcess(destroyWfId, null);
176
	}
177

    
178
	@RequestMapping("/ui/repoApi.get")
179
	public @ResponseBody RepoInterfaceEntry getRepoApi(@RequestParam(value = "repoId", required = true) final String repoId,
180
		@RequestParam(value = "ifaceId", required = true) final String ifaceId) throws Exception {
181

    
182
		return repoUIUtils.getApi(repoId, ifaceId);
183
	}
184

    
185
	@RequestMapping("/ui/repoApi.update")
186
	public @ResponseBody boolean updateRepoApi(
187
		@RequestParam(value = "id", required = true) final String repoId,
188
		@RequestParam(value = "iface", required = true) final String ifaceId,
189
		@RequestParam(value = "accessParams", required = false) final String accessParamsJson,
190
		@RequestParam(value = "mdIdPath", required = false) final String mdIdPath) throws Exception {
191

    
192
		if (!StringUtils.isEmpty(accessParamsJson)) {
193
			final Map<String, String> params = new Gson().fromJson(accessParamsJson, new TypeToken<Map<String, String>>() {}.getType());
194
			final String baseUrl = params.remove("baseUrl");
195
			dsManager.updateApiDetails(repoId, ifaceId, mdIdPath, baseUrl, params);
196
		}
197

    
198
		return true;
199
	}
200

    
201
	@RequestMapping("/ui/repoApi.delete")
202
	public @ResponseBody boolean deleteRepoApi(
203
		@RequestParam(value = "repo", required = true) final String repoId,
204
		@RequestParam(value = "iface", required = true) final String ifaceId) throws Exception {
205
		dsManager.deleteApi(repoId, ifaceId);
206
		return true;
207
	}
208

    
209
	@CacheEvict("repoUIJsonCache")
210
	@RequestMapping("/ui/repoApiCompliance.update")
211
	public @ResponseBody boolean updateRepoApiCompliance(@RequestParam(value = "id", required = true) final String repoId,
212
		@RequestParam(value = "iface", required = true) final String ifaceId,
213
		@RequestParam(value = "compliance", required = true) final String compliance) throws Exception {
214

    
215
		log.debug("SET COMPLIANCE TO " + compliance);
216

    
217
		dsManager.updateCompliance(repoId, ifaceId, compliance, true);
218

    
219
		return true;
220
	}
221

    
222
	@CacheEvict("repoUIJsonCache")
223
	@RequestMapping("/ui/repoApiCompliance.reset")
224
	public @ResponseBody boolean resetRepoApiCompliance(@RequestParam(value = "id", required = true) final String repoId,
225
		@RequestParam(value = "iface", required = true) final String ifaceId) throws Exception {
226

    
227
		log.debug("RESET COMPLIANCE");
228

    
229
		dsManager.updateCompliance(repoId, ifaceId, null, true);
230

    
231
		return true;
232
	}
233

    
234
	@RequestMapping("/ui/repos/repoApi.html")
235
	public void repoApiHtml(final ModelMap map) throws Exception {
236
		if (StringUtils.isNoneBlank(syncButton, syncDesc, syncApiBaseUrl, syncISBaseUrl)) {
237
			map.addAttribute("syncButton", syncButton);
238
			map.addAttribute("syncDesc", syncDesc);
239
			map.addAttribute("syncISBaseUrl", syncISBaseUrl);
240
			map.addAttribute("mongoDB", mongoDb);
241
			map.addAttribute("mongoUrl", mongoUrl);
242
		}
243
	}
244

    
245
	@RequestMapping("/ui/repoApi.new")
246
	public @ResponseBody boolean addRepoApi(@RequestParam(value = "repoId", required = true) final String repoId,
247
		@RequestParam(value = "iface", required = true) final String ifaceJson) throws DsmException {
248
		final Api<ApiParam> iface = new Gson().fromJson(ifaceJson, new TypeToken<Api<ApiParamImpl>>() {}.getType());
249

    
250
		iface.setDatasource(repoId);
251

    
252
		log.info("Adding api " + iface.getId() + " to repository " + repoId);
253

    
254
		dsManager.addApi(iface);
255

    
256
		return true;
257
	}
258

    
259
	@RequestMapping("/ui/repo.new")
260
	public @ResponseBody boolean addRepoApi(@RequestParam(value = "repo", required = true) final String repoJson) throws DsmException {
261
		final Datasource<Organization<?>, Identity, PidSystem> ds =
262
			new Gson().fromJson(repoJson, new TypeToken<Datasource<Organization<?>, Identity, PidSystem>>() {}.getType());
263
		final Date now = new Date();
264
		ds.setDateofcollection(new java.sql.Date(now.getTime()));
265

    
266
		if (StringUtils.isBlank(ds.getEnglishname())) {
267
			ds.setEnglishname(ds.getOfficialname());
268
		}
269

    
270
		if (StringUtils.isBlank(ds.getProvenanceaction())) {
271
			ds.setProvenanceaction("user:insert");
272
		}
273

    
274
		log.info("Adding datasource " + ds.getId() + " - name " + ds.getOfficialname());
275

    
276
		dsManager.saveDs(ds);
277

    
278
		return true;
279
	}
280

    
281
	@RequestMapping("/ui/listValidValuesForParam.do")
282
	public @ResponseBody List<ProtocolParameterValue> listValidValuesForParam(
283
		@RequestParam(value = "protocol", required = true) final String protocol,
284
		@RequestParam(value = "param", required = true) final String param,
285
		@RequestParam(value = "baseUrl", required = true) final String baseUrl) throws CollectorServiceException {
286

    
287
		return serviceLocator.getService(CollectorService.class).listValidValuesForParam(protocol, baseUrl, param, null);
288
	}
289

    
290
	@RequestMapping(value = "/ui/remoteDatasource/apis", method = RequestMethod.GET)
291
	public void listRemoteApis(@RequestParam(value = "repo", required = true) final String repoId,
292
		final HttpServletResponse response) throws IOException {
293

    
294
		final RestTemplate restTemplate = new RestTemplate();
295

    
296
		final String res = restTemplate.getForObject(syncApiBaseUrl + "/ds/api/" + repoId, String.class);
297

    
298
		response.setContentType("application/json;charset=UTF-8");
299

    
300
		IOUtils.write(res, response.getOutputStream());
301
	}
302

    
303
	@RequestMapping(value = "/ui/remoteDatasource/api", method = RequestMethod.POST)
304
	public void saveRemoteApi(@RequestBody final Api<ApiParamImpl> api, final HttpServletResponse response) throws IOException {
305

    
306
		final String url = syncApiBaseUrl + "/ds/api/add";
307

    
308
		log.info("Adding new remote API:");
309
		log.info(" - repo id: " + api.getDatasource());
310
		log.info(" - api id: " + api.getId());
311
		log.info(" - rest call: " + url);
312
		log.info(" - json: " + new Gson().toJson(api));
313

    
314
		final RestTemplate restTemplate = new RestTemplate();
315

    
316
		restTemplate.postForObject(url, api, Void.class);
317

    
318
		listRemoteApis(api.getDatasource(), response);
319
	}
320

    
321
	@ResponseBody
322
	@RequestMapping(value = "/ui/updateRepoTickets.do", method = RequestMethod.POST)
323
	public List<BrowsableField> updateRepoTickets(@RequestParam(name = "id", required = true) final String repoId, @RequestBody final List<Integer> tickets) {
324
		return repoUIUtils.updateTicketsForDatasource(repoId, tickets);
325
	}
326

    
327
	@ExceptionHandler(Exception.class)
328
	@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
329
	public @ResponseBody ErrorMessage handleException(final HttpServletRequest req, final Exception e) {
330
		log.error("Error processing " + req.getRequestURI(), e);
331
		return new ErrorMessage(e.getMessage(), ExceptionUtils.getStackTrace(e));
332
	}
333

    
334
}
(5-5/6)