1
|
package eu.dnetlib.enabling.inspector;
|
2
|
|
3
|
import java.io.File;
|
4
|
import java.io.IOException;
|
5
|
import java.io.StringReader;
|
6
|
import java.util.ArrayList;
|
7
|
import java.util.Collection;
|
8
|
import java.util.Collections;
|
9
|
import java.util.HashMap;
|
10
|
import java.util.List;
|
11
|
import java.util.Map;
|
12
|
|
13
|
import javax.annotation.Resource;
|
14
|
import javax.servlet.ServletOutputStream;
|
15
|
import javax.servlet.http.HttpServletRequest;
|
16
|
import javax.servlet.http.HttpServletResponse;
|
17
|
|
18
|
import org.apache.commons.io.IOUtils;
|
19
|
import org.apache.commons.lang3.StringEscapeUtils;
|
20
|
import org.apache.commons.logging.Log;
|
21
|
import org.apache.commons.logging.LogFactory;
|
22
|
import org.dom4j.DocumentException;
|
23
|
import org.springframework.stereotype.Controller;
|
24
|
import org.springframework.ui.Model;
|
25
|
import org.springframework.web.bind.annotation.RequestMapping;
|
26
|
import org.springframework.web.bind.annotation.RequestParam;
|
27
|
import org.xmldb.api.base.XMLDBException;
|
28
|
|
29
|
import com.google.common.collect.Lists;
|
30
|
|
31
|
import eu.dnetlib.miscutils.collections.MappedCollection;
|
32
|
import eu.dnetlib.miscutils.functional.UnaryFunction;
|
33
|
import eu.dnetlib.xml.database.XMLDatabase;
|
34
|
|
35
|
/**
|
36
|
* test controller.
|
37
|
*
|
38
|
* @author marko
|
39
|
*/
|
40
|
@Controller
|
41
|
public class ResourceTreeController extends AbstractInspectorController { // NOPMD
|
42
|
|
43
|
/**
|
44
|
* The list view uses this model to represent a collection
|
45
|
*
|
46
|
* @author marko
|
47
|
*/
|
48
|
public class CollectionModel {
|
49
|
|
50
|
/**
|
51
|
* absolute path used to query the xmldb.
|
52
|
*/
|
53
|
private String path;
|
54
|
/**
|
55
|
* relative path, used to construct the uri used by the view.
|
56
|
*/
|
57
|
private String rel;
|
58
|
|
59
|
/**
|
60
|
* the collection name.
|
61
|
*/
|
62
|
private String name;
|
63
|
|
64
|
public CollectionModel(final String path, final String rel, final String name) {
|
65
|
super();
|
66
|
this.path = path;
|
67
|
this.rel = rel;
|
68
|
this.name = name;
|
69
|
}
|
70
|
|
71
|
/**
|
72
|
* We want to be able to skip useless collections which have only one child collection etc etc.
|
73
|
* <p>
|
74
|
* <p>
|
75
|
* This method returns us the deepest path containing only one collection at each level
|
76
|
* </p>
|
77
|
*
|
78
|
* @return list of collection names to be displayed in one "row"
|
79
|
*/
|
80
|
public Collection<CollectionModel> getCollectionPath() {
|
81
|
final ArrayList<CollectionModel> res = Lists.newArrayList(this);
|
82
|
|
83
|
try {
|
84
|
List<String> children = xmlDatabase.listChildCollections(path + '/' + name);
|
85
|
if (children.size() == 1) {
|
86
|
res.addAll(new CollectionModel(path + '/' + name, rel + '/' + name, children.get(0)).getCollectionPath());
|
87
|
}
|
88
|
|
89
|
return res;
|
90
|
} catch (XMLDBException e) {
|
91
|
return res;
|
92
|
}
|
93
|
}
|
94
|
|
95
|
/**
|
96
|
* Uri is computed from relative base path.
|
97
|
*
|
98
|
* @return
|
99
|
*/
|
100
|
public String getUrl() {
|
101
|
return (rel + '/' + getName());
|
102
|
}
|
103
|
|
104
|
public String getPath() {
|
105
|
return path;
|
106
|
}
|
107
|
|
108
|
public void setPath(final String path) {
|
109
|
this.path = path;
|
110
|
}
|
111
|
|
112
|
public String getName() {
|
113
|
return name;
|
114
|
}
|
115
|
|
116
|
public void setName(final String name) {
|
117
|
this.name = name;
|
118
|
}
|
119
|
|
120
|
}
|
121
|
|
122
|
/**
|
123
|
* base index.do path.
|
124
|
*/
|
125
|
private static final String INDEX_DO = "/inspector/index.do";
|
126
|
|
127
|
/**
|
128
|
* logger.
|
129
|
*/
|
130
|
private static final Log log = LogFactory.getLog(ResourceTreeController.class); // NOPMD by marko on 11/24/08 5:02 PM
|
131
|
|
132
|
/**
|
133
|
* xml database.
|
134
|
*/
|
135
|
@Resource(name = "existDatabase")
|
136
|
private transient XMLDatabase xmlDatabase;
|
137
|
|
138
|
/**
|
139
|
* utility to parse resource ids and allows to navigate them.
|
140
|
*/
|
141
|
@Resource(name = "resourcelinkTool")
|
142
|
private ResourceLinkTool linkTool;
|
143
|
|
144
|
/**
|
145
|
* debug.
|
146
|
*/
|
147
|
public ResourceTreeController() {
|
148
|
super();
|
149
|
log.info("ResourceTreeController created");
|
150
|
}
|
151
|
|
152
|
/**
|
153
|
* handles relative paths.
|
154
|
*
|
155
|
* @return redirect
|
156
|
*/
|
157
|
// @RequestMapping("/inspector/")
|
158
|
// String indexSlash() {
|
159
|
// return "redirect:index.do/db/list";
|
160
|
// }
|
161
|
|
162
|
/**
|
163
|
* handles relative paths.
|
164
|
*
|
165
|
* @return redirect
|
166
|
*/
|
167
|
@RequestMapping("/inspector/index.do")
|
168
|
String indexDo() {
|
169
|
return "redirect:index.do/db/list";
|
170
|
}
|
171
|
|
172
|
/**
|
173
|
* index.
|
174
|
*
|
175
|
* @param model model
|
176
|
* @param request http request
|
177
|
* @throws XMLDBException happens
|
178
|
*/
|
179
|
@RequestMapping("/inspector/index.do/**/list")
|
180
|
String list(final Model model, final HttpServletRequest request) throws XMLDBException {
|
181
|
final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/list", "");
|
182
|
|
183
|
log.debug("xml db: " + xmlDatabase);
|
184
|
|
185
|
final Collection<String> children = xmlDatabase.listChildCollections(path);
|
186
|
final Collection<String> files = xmlDatabase.list(path);
|
187
|
|
188
|
Collections.sort((List<String>) children);
|
189
|
Collections.sort((List<String>) files);
|
190
|
|
191
|
UnaryFunction<CollectionModel, String> mapper = new UnaryFunction<CollectionModel, String>() {
|
192
|
|
193
|
@Override
|
194
|
public CollectionModel evaluate(final String name) {
|
195
|
return new CollectionModel(path, ".", name);
|
196
|
}
|
197
|
};
|
198
|
final Collection<CollectionModel> richChildren = Lists.newArrayList(new MappedCollection<CollectionModel, String>(children, mapper));
|
199
|
|
200
|
model.addAttribute("path", path);
|
201
|
model.addAttribute("pathComponents", extractPathComponents(path, ""));
|
202
|
model.addAttribute("collections", richChildren);
|
203
|
model.addAttribute("files", files);
|
204
|
model.addAttribute("title", "Title");
|
205
|
|
206
|
return "inspector/index";
|
207
|
}
|
208
|
|
209
|
/**
|
210
|
* return a list of pairs (name, relative url bases) for each path component.
|
211
|
*
|
212
|
* @param path slash separated path
|
213
|
* @param base prepend this to all paths
|
214
|
* @return list of path components
|
215
|
*/
|
216
|
private List<Map<String, String>> extractPathComponents(final String path, final String base) {
|
217
|
final String[] rawPathComponents = path.split("/");
|
218
|
final List<Map<String, String>> pathComponents = new ArrayList<Map<String, String>>();
|
219
|
for (String rawPathComponent : rawPathComponents) {
|
220
|
final Map<String, String> pathElement = new HashMap<String, String>(); // NOPMD
|
221
|
pathElement.put("name", rawPathComponent);
|
222
|
|
223
|
pathComponents.add(pathElement);
|
224
|
}
|
225
|
Collections.reverse(pathComponents);
|
226
|
final StringBuffer current = new StringBuffer(base); // NOPMD
|
227
|
for (Map<String, String> pathComponent : pathComponents) {
|
228
|
pathComponent.put("url", current.toString());
|
229
|
current.append("../");
|
230
|
}
|
231
|
Collections.reverse(pathComponents);
|
232
|
return pathComponents;
|
233
|
}
|
234
|
|
235
|
/**
|
236
|
* show a file.
|
237
|
*
|
238
|
* @param model model
|
239
|
* @param request request
|
240
|
* @return view name
|
241
|
* @throws XMLDBException happens
|
242
|
*/
|
243
|
@RequestMapping("/inspector/index.do/**/show")
|
244
|
String show(final Model model, final HttpServletRequest request) throws XMLDBException {
|
245
|
|
246
|
final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/show", "");
|
247
|
log.info("index: " + path);
|
248
|
|
249
|
final File fileHelper = new File(path);
|
250
|
final String collection = fileHelper.getParent();
|
251
|
final String fileName = fileHelper.getName();
|
252
|
final TouchUtils touch = new TouchUtils();
|
253
|
|
254
|
String file = xmlDatabase.read(fileName, collection);
|
255
|
if (file == null) {
|
256
|
file = "no such file, click on edit to create";
|
257
|
}
|
258
|
|
259
|
file = touch.spanize(file);
|
260
|
file = StringEscapeUtils.escapeHtml4(file);
|
261
|
file = touch.escape(file);
|
262
|
// log.info("XML ESCAPED:" + file);
|
263
|
|
264
|
model.addAttribute("file", linkTool.linkfyToHtml(file));
|
265
|
model.addAttribute("pathComponents", extractPathComponents(collection, "../"));
|
266
|
|
267
|
return "inspector/show";
|
268
|
}
|
269
|
|
270
|
@RequestMapping("/inspector/index.do/**/touch")
|
271
|
public void updateDate(@RequestParam(value = "xpath", required = true) final String xpath,
|
272
|
final HttpServletRequest request,
|
273
|
final HttpServletResponse response) throws XMLDBException {
|
274
|
|
275
|
final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/touch", "");
|
276
|
final File fileHelper = new File(path);
|
277
|
final String collection = fileHelper.getParent();
|
278
|
final String fileName = fileHelper.getName();
|
279
|
final TouchUtils touch = new TouchUtils();
|
280
|
|
281
|
String file = xmlDatabase.read(fileName, collection);
|
282
|
if (file != null) {
|
283
|
String updatedProfile;
|
284
|
try {
|
285
|
updatedProfile = touch.updateProfile(file, xpath);
|
286
|
xmlDatabase.update(fileName, collection, updatedProfile);
|
287
|
} catch (DocumentException e) {
|
288
|
log.warn(e);
|
289
|
}
|
290
|
|
291
|
}
|
292
|
}
|
293
|
|
294
|
/**
|
295
|
* Show raw profile.
|
296
|
*
|
297
|
* @param request servlet request
|
298
|
* @param response servlet response
|
299
|
* @throws XMLDBException could happen
|
300
|
* @throws IOException
|
301
|
*/
|
302
|
@RequestMapping("/inspector/index.do/**/raw")
|
303
|
public void raw(final HttpServletRequest request, final HttpServletResponse response) throws XMLDBException, IOException {
|
304
|
|
305
|
final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/raw", "");
|
306
|
// log.info("index: " + path);
|
307
|
|
308
|
final File fileHelper = new File(path);
|
309
|
final String collection = fileHelper.getParent();
|
310
|
final String fileName = fileHelper.getName();
|
311
|
|
312
|
String file = xmlDatabase.read(fileName, collection);
|
313
|
if (file == null) {
|
314
|
file = "no such file to show";
|
315
|
}
|
316
|
|
317
|
response.setContentType("text/xml");
|
318
|
ServletOutputStream out = response.getOutputStream();
|
319
|
IOUtils.copy(new StringReader(file), out);
|
320
|
out.flush();
|
321
|
out.close();
|
322
|
}
|
323
|
|
324
|
/**
|
325
|
* show a file editor.
|
326
|
*
|
327
|
* @param model model
|
328
|
* @param request request
|
329
|
* @return view name
|
330
|
* @throws XMLDBException happens
|
331
|
*/
|
332
|
@RequestMapping("/inspector/index.do/**/edit")
|
333
|
public String edit(final Model model, final HttpServletRequest request) throws XMLDBException {
|
334
|
|
335
|
final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/edit", "");
|
336
|
|
337
|
final File fileHelper = new File(path);
|
338
|
final String collection = fileHelper.getParent();
|
339
|
final String fileName = fileHelper.getName();
|
340
|
|
341
|
final String file = xmlDatabase.read(fileName, collection);
|
342
|
if (file == null) {
|
343
|
model.addAttribute("creating", "true");
|
344
|
}
|
345
|
|
346
|
model.addAttribute("file", StringEscapeUtils.escapeHtml4(file));
|
347
|
model.addAttribute("pathComponents", extractPathComponents(collection, "../"));
|
348
|
|
349
|
return "inspector/edit";
|
350
|
}
|
351
|
|
352
|
/**
|
353
|
* update or create a file.
|
354
|
*
|
355
|
* @param model model
|
356
|
* @param request request
|
357
|
* @return view name
|
358
|
* @throws XMLDBException happens
|
359
|
*/
|
360
|
@RequestMapping("/inspector/index.do/**/save")
|
361
|
public String save(final Model model, final HttpServletRequest request) throws XMLDBException {
|
362
|
|
363
|
final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/save", "");
|
364
|
|
365
|
final File fileHelper = new File(path);
|
366
|
final String collection = fileHelper.getParent();
|
367
|
final String fileName = fileHelper.getName();
|
368
|
|
369
|
log.info("saving: " + path);
|
370
|
final String source = request.getParameter("source");
|
371
|
|
372
|
if ("true".equals(request.getParameter("creating"))) {
|
373
|
xmlDatabase.create(fileName, collection, source);
|
374
|
} else {
|
375
|
xmlDatabase.update(fileName, collection, source);
|
376
|
}
|
377
|
|
378
|
return "redirect:show";
|
379
|
}
|
380
|
|
381
|
/**
|
382
|
* delete a file.
|
383
|
*
|
384
|
* @param model model
|
385
|
* @param request request
|
386
|
* @return view name
|
387
|
* @throws XMLDBException happens
|
388
|
*/
|
389
|
@RequestMapping("/inspector/index.do/**/delete")
|
390
|
public String delete(final Model model, final HttpServletRequest request) throws XMLDBException {
|
391
|
|
392
|
final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/delete", "");
|
393
|
|
394
|
final File fileHelper = new File(path);
|
395
|
final String collection = fileHelper.getParent();
|
396
|
final String fileName = fileHelper.getName();
|
397
|
|
398
|
log.info("deleting: " + path);
|
399
|
xmlDatabase.remove(fileName, collection);
|
400
|
|
401
|
return "redirect:../list";
|
402
|
}
|
403
|
|
404
|
/**
|
405
|
* delete a collection.
|
406
|
*
|
407
|
* @param model model
|
408
|
* @param request request
|
409
|
* @return view name
|
410
|
* @throws XMLDBException happens
|
411
|
*/
|
412
|
@RequestMapping("/inspector/index.do/**/deleteCollection")
|
413
|
public String deleteCollection(final Model model, final HttpServletRequest request) throws XMLDBException {
|
414
|
|
415
|
final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/deleteCollection", "");
|
416
|
|
417
|
xmlDatabase.removeCollection(path);
|
418
|
|
419
|
return "redirect:../list";
|
420
|
}
|
421
|
|
422
|
/**
|
423
|
* present a create form for new subcollection
|
424
|
*
|
425
|
* @param model model
|
426
|
* @param request request
|
427
|
* @return view name
|
428
|
* @throws XMLDBException happens
|
429
|
*/
|
430
|
@RequestMapping("/inspector/index.do/**/createsubcoll")
|
431
|
public String createSubCollection(final Model model, final HttpServletRequest request) throws XMLDBException {
|
432
|
return "inspector/createsubcoll";
|
433
|
}
|
434
|
|
435
|
/**
|
436
|
* @param request request
|
437
|
* @return view name
|
438
|
* @throws XMLDBException happens
|
439
|
*/
|
440
|
@RequestMapping("/inspector/index.do/**/savesubcoll")
|
441
|
public String saveSubCollection(final HttpServletRequest request, @RequestParam("collectionPath") final String collectionPath)
|
442
|
throws XMLDBException {
|
443
|
final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/savesubcoll", "");
|
444
|
String fullPath = path + "/" + collectionPath;
|
445
|
log.info("Creating subcollection: " + fullPath);
|
446
|
if (!xmlDatabase.collectionExists(fullPath)) {
|
447
|
xmlDatabase.createCollection(fullPath);
|
448
|
} else {
|
449
|
log.info("Subcollection: " + fullPath + " already exists");
|
450
|
}
|
451
|
return "redirect:../list";
|
452
|
}
|
453
|
|
454
|
/**
|
455
|
* present a create form which will redirect to the edit form.
|
456
|
*
|
457
|
* @param model model
|
458
|
* @param request request
|
459
|
* @return view name
|
460
|
* @throws XMLDBException happens
|
461
|
*/
|
462
|
@RequestMapping("/inspector/index.do/**/create")
|
463
|
public String create(final Model model, final HttpServletRequest request) throws XMLDBException {
|
464
|
return "inspector/create";
|
465
|
}
|
466
|
|
467
|
/**
|
468
|
* sample controller.
|
469
|
*
|
470
|
* @param model model
|
471
|
*/
|
472
|
@RequestMapping("/inspector/gadget.do")
|
473
|
public void gadget(final Model model) {
|
474
|
log.info("GADGED CALLED");
|
475
|
|
476
|
model.addAttribute("items", new String[] { "one", "two", "three" });
|
477
|
}
|
478
|
|
479
|
}
|