Project

General

Profile

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.lang.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.escapeHtml(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.escapeHtml(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
}
(6-6/9)