001 /**
002 * $RCSfile: MCRClassificationEditor.java,v $
003 * $Revision: 15496 $ $Date: 2009-07-10 16:28:14 +0200 (Fri, 10 Jul 2009) $
004 *
005 * This file is part of *** M y C o R e ***
006 * See http://www.mycore.de/ for details.
007 *
008 * This program is free software; you can use it, redistribute it
009 * and / or modify it under the terms of the GNU General Public License
010 * (GPL) as published by the Free Software Foundation; either version 2
011 * of the License or (at your option) any later version.
012 *
013 * This program is distributed in the hope that it will be useful, but
014 * WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program, in a file called gpl.txt or license.txt.
020 * If not, write to the Free Software Foundation Inc.,
021 * 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
022 *
023 **/
024
025 package org.mycore.datamodel.classifications;
026
027 import static org.jdom.Namespace.XML_NAMESPACE;
028 import static org.mycore.common.MCRConstants.XSI_NAMESPACE;
029
030 import java.io.File;
031 import java.io.FileOutputStream;
032 import java.util.Collection;
033 import java.util.List;
034
035 import org.apache.commons.fileupload.FileItem;
036 import org.apache.log4j.Logger;
037 import org.jdom.Document;
038 import org.jdom.Element;
039 import org.jdom.output.XMLOutputter;
040 import org.mycore.common.MCRConfiguration;
041 import org.mycore.common.MCRException;
042 import org.mycore.common.MCRSessionMgr;
043 import org.mycore.common.MCRUtils;
044 import org.mycore.common.xml.MCRXMLHelper;
045 import org.mycore.datamodel.classifications2.MCRCategLinkServiceFactory;
046 import org.mycore.datamodel.classifications2.MCRCategory;
047 import org.mycore.datamodel.classifications2.MCRCategoryDAO;
048 import org.mycore.datamodel.classifications2.MCRCategoryDAOFactory;
049 import org.mycore.datamodel.classifications2.MCRCategoryID;
050 import org.mycore.datamodel.classifications2.MCRLabel;
051 import org.mycore.datamodel.classifications2.utils.MCRXMLTransformer;
052
053 /**
054 * This class implements all methods for a edit, modify delete categories in
055 * classification and the classification itself
056 *
057 * @author Anja Schaar
058 * @author Jens Kupferschmidt
059 * @version
060 */
061
062 public class MCRClassificationEditor {
063
064 // logger
065 private static Logger LOGGER = Logger.getLogger(MCRClassificationEditor.class);
066
067 private MCRCategory classif;
068
069 private static MCRCategoryDAO DAO = MCRCategoryDAOFactory.getInstance();
070
071 private MCRConfiguration CONFIG;
072
073 private File fout;
074
075 public MCRClassificationEditor() {
076 CONFIG = MCRConfiguration.instance();
077 }
078
079 /**
080 * Create an new category in the category path.
081 *
082 * @param indoc
083 * the output from the editor dialogue
084 * @param clid
085 * the classification ID
086 * @param categid
087 * the category ID to add after it
088 * @return
089 */
090 public boolean createCategoryInClassification(org.jdom.Document indoc, MCRCategoryID id) {
091
092 try {
093 Element clroot = indoc.getRootElement();
094 if (clroot == null) {
095 return false;
096 }
097 Element categories = (Element) clroot.getChild("categories");
098 if (categories == null)
099 return false;
100
101 Element newCateg = (Element) categories.getChild("category").clone();
102 MCRCategoryID newID = new MCRCategoryID(id.getRootID(), newCateg.getAttributeValue("ID"));
103 classif = MCRClassificationBrowserData.getClassificationPool().getClassificationAsPojo(MCRCategoryID.rootID(id.getRootID()),
104 true);
105
106 // check the new category entry
107 if (newID.getID().equalsIgnoreCase(id.getID())) {
108 LOGGER.error("The category ID's are not different.");
109 return false;
110 }
111
112 final MCRCategory findCategory = findCategory(classif, newID);
113 if (findCategory == null) {
114 if (!id.getID().equals("empty")) {
115
116 MCRCategory prevCateg = findCategory(classif, id);
117 LOGGER.debug("Previous Category: " + prevCateg.getId() + " found.");
118
119 MCRXMLTransformer.buildCategory(id.getRootID(), newCateg, prevCateg);
120 MCRClassificationBrowserData.getClassificationPool().updateClassification(classif);
121 String sessionID = MCRSessionMgr.getCurrentSession().getID();
122 MCRClassificationBrowserData.ClassUserTable.put(classif.getId().getRootID(), sessionID);
123 return true;
124 } else {
125 MCRCategory newCategory = MCRXMLTransformer.buildCategory(id.getRootID(), newCateg, classif);
126 LOGGER.debug("Adding category:" + newCategory.getId() + " to classification: " + classif.getId());
127 MCRClassificationBrowserData.getClassificationPool().updateClassification(classif);
128 String sessionID = MCRSessionMgr.getCurrentSession().getID();
129 MCRClassificationBrowserData.ClassUserTable.put(classif.getId().getRootID(), sessionID);
130 return true;
131 }
132 } else {
133 LOGGER.error("The category " + newID + " does already exist.");
134 return false;
135 }
136 } catch (Exception e1) {
137 e1.printStackTrace();
138 LOGGER.error("Classification creation fails. Reason is:" + e1.getMessage());
139 return false;
140 }
141
142 }
143
144 /**
145 * Replace category data like label(s) and url.
146 *
147 * @param indoc
148 * the output from the editor dialogue
149 * @param clid
150 * the classification ID
151 * @param categid
152 * the category ID
153 * @return true if all it's okay, else return false
154 */
155 public final boolean modifyCategoryInClassification(org.jdom.Document indoc, MCRCategoryID id) {
156 try {
157 LOGGER.debug("Start modify category in classification " + id.getRootID() + " with categid " + id.getID());
158 Element clroot = indoc.getRootElement();
159 Element newCateg = (Element) clroot.getChild("categories").getChild("category").clone();
160 String newID = newCateg.getAttributeValue("ID");
161 classif = MCRClassificationBrowserData.getClassificationPool().getClassificationAsPojo(MCRCategoryID.rootID(id.getRootID()),
162 true);
163 // check the category entry
164 if (!newID.equalsIgnoreCase(id.getID())) {
165 LOGGER.error("The category ID's are different.");
166 return false;
167 }
168
169 MCRCategory oldCategory = findCategory(classif, id);
170 if (oldCategory == null) {
171 LOGGER.error("The category ID " + id.getID() + " does not exist in classification " + id.getRootID());
172 return false;
173 }
174
175 MCRCategory newCategory = MCRXMLTransformer.buildCategory(id.getRootID(), newCateg, oldCategory.getParent());
176 //copy new values to old copy of category
177 oldCategory.setURI(newCategory.getURI());
178 oldCategory.getLabels().clear();
179 Collection<MCRLabel> labels = newCategory.getLabels();
180 oldCategory.getLabels().addAll(labels);
181
182 MCRClassificationBrowserData.getClassificationPool().updateClassification(classif);
183 String sessionID = MCRSessionMgr.getCurrentSession().getID();
184 MCRClassificationBrowserData.ClassUserTable.put(classif.getId().getRootID(), sessionID);
185
186 return true;
187 } catch (Exception e1) {
188 LOGGER.error("Category modify fails. Reason is:");
189 e1.printStackTrace();
190 return false;
191 }
192 }
193
194 public boolean isLocked(String classid) {
195 if (MCRClassificationBrowserData.ClassUserTable.containsKey(classid)) {
196 String lockedSessionID = MCRClassificationBrowserData.ClassUserTable.get(classid);
197 String currentSessionID = MCRSessionMgr.getCurrentSession().getID();
198 if (!lockedSessionID.equals(currentSessionID)) {
199 return true;
200 }
201 }
202 return false;
203 }
204
205 /**
206 * Create or update a classification form import.
207 *
208 * @param bUpdate
209 * true if this operation should be a update, else false
210 * @param fileName
211 * the name of classification file
212 * @return true if all it's okay, else return false
213 */
214 public boolean importClassification(boolean bUpdate, String fileName) {
215 LOGGER.debug("Start importNewClassification.");
216 try {
217 try {
218 File file = new File(fileName);
219 LOGGER.info("Reading file " + file + " ...\n");
220 Document jdom = MCRXMLHelper.parseURI(file.toURI());
221 MCRCategory classification = MCRXMLTransformer.getCategory(jdom);
222
223 MCRClassificationBrowserData.getClassificationPool().updateClassification(classification);
224
225 return true;
226 } catch (MCRException ex) {
227 LOGGER.error("Exception while loading from file " + fileName, ex);
228 return false;
229 }
230 } catch (Exception e1) {
231 LOGGER.error("Classification import fails. Reason is:" + e1.getMessage());
232 return false;
233 }
234
235 }
236
237 /**
238 * Create a new classification with the data from the editor dialogue.
239 *
240 * @param indoc
241 * the output from the editor dialogue
242 * @return true if all it's okay, else return false
243 */
244 public final boolean createNewClassification(org.jdom.Document indoc) {
245 try {
246 LOGGER.debug("Start create a new classification.");
247 Element clroot = indoc.getRootElement();
248 XMLOutputter out = new XMLOutputter();
249 out.output(indoc, System.out);
250
251 Element mycoreclass = new Element("mycoreclass");
252 Element categories = new Element("categories");
253 Element category = new Element("category");
254 category.setAttribute("ID", "empty");
255 Element label = new Element("label");
256 label.setAttribute("text", "empty");
257 label.setAttribute("description", "empty");
258 label.setAttribute("lang", CONFIG.getString("MCR.Metadata.DefaultLang"), XML_NAMESPACE);
259 category.addContent(label);
260 categories.addContent(category);
261
262 String submittedID = indoc.getRootElement().getAttributeValue("ID");
263 MCRCategoryID cli = null;
264
265 if (!MCRClassificationBrowserData.getClassificationPool().getAllIDs().contains(MCRCategoryID.rootID(submittedID))) {
266 cli = MCRCategoryID.rootID(submittedID);
267 } else {
268 LOGGER.error("Create an unique ID failed. " + submittedID);
269 return false;
270 }
271
272 mycoreclass.addNamespaceDeclaration(XSI_NAMESPACE);
273 mycoreclass.setAttribute("noNamespaceSchemaLocation", "MCRClassification.xsd", XSI_NAMESPACE);
274 mycoreclass.setAttribute("ID", cli.getRootID());
275 mycoreclass.setAttribute("counter", "0");
276 @SuppressWarnings("unchecked")
277 List<Element> tagList = clroot.getChildren("label");
278 for (Element element : tagList) {
279 Element newE = new Element("label");
280 newE.setAttribute("lang", element.getAttributeValue("lang"), XML_NAMESPACE);
281 newE.setAttribute("text", element.getAttributeValue("text"));
282 if (element.getAttributeValue("description") != null) {
283 newE.setAttribute("description", element.getAttributeValue("description"));
284 }
285 mycoreclass.addContent(newE);
286 }
287 mycoreclass.addContent(categories);
288 Document cljdom = new Document();
289 cljdom.addContent(mycoreclass);
290 out.output(cljdom, System.out);
291 MCRCategory classif = MCRXMLTransformer.getCategory(cljdom);
292 MCRClassificationBrowserData.getClassificationPool().updateClassification(classif);
293 LOGGER.debug("Classification " + cli.toString() + " successfully created!");
294 return true;
295
296 } catch (Exception e1) {
297 LOGGER.error("Classification creation fails. Reason is:" + e1.getMessage());
298 return false;
299 }
300 }
301
302 /**
303 * Change the description data of a classification.
304 *
305 * @param indoc
306 * the output from the editor dialogue
307 * @param clid
308 * the classification ID
309 * @return true if all it's okay, else return false
310 */
311 public final boolean modifyClassificationDescription(org.jdom.Document indoc, String clid) {
312 try {
313 LOGGER.debug("Start modify classification description for " + clid);
314 Element clroot = indoc.getRootElement();
315 classif = MCRClassificationBrowserData.getClassificationPool().getClassificationAsPojo(MCRCategoryID.rootID(clid), true);
316 classif.getLabels().clear();
317
318 @SuppressWarnings("unchecked")
319 List<Element> tagList = clroot.getChildren("label");
320 for (Element element : tagList) {
321 MCRLabel label = new MCRLabel();
322 label.setLang(element.getAttributeValue("lang"));
323 label.setText(element.getAttributeValue("text"));
324 label.setDescription(element.getAttributeValue("description"));
325 classif.getLabels().add(label);
326 }
327
328 MCRClassificationBrowserData.getClassificationPool().updateClassification(classif);
329 String sessionID = MCRSessionMgr.getCurrentSession().getID();
330 MCRClassificationBrowserData.ClassUserTable.put(classif.getId().getRootID(), sessionID);
331 return true;
332 } catch (Exception e1) {
333 LOGGER.error("Classification modify fails. Reason is:" + e1.getMessage());
334 return false;
335 }
336 }
337
338 /**
339 * Move a category in a classification.
340 *
341 * @param categid
342 * the category ID
343 * @param clid
344 * the classification ID
345 * @param way
346 * the way to move
347 * @return true if all it's okay, else return false
348 */
349 public boolean moveCategoryInClassification(String categid, String clid, String way) {
350 try {
351 LOGGER.debug("Start move in classification " + clid + " the category " + categid + " in direction: " + way);
352 boolean bret = false;
353
354 MCRCategoryID categoryId = new MCRCategoryID(clid, categid);
355 classif = MCRClassificationBrowserData.getClassificationPool().getClassificationAsPojo(MCRCategoryID.rootID(clid), true);
356
357 if (way.equalsIgnoreCase("up")) {
358 MCRCategory categ = findCategory(classif, categoryId);
359 bret = moveUp(categ);
360 } else if (way.equalsIgnoreCase("down")) {
361 MCRCategory categ = findCategory(classif, categoryId);
362 bret = moveDown(categ);
363 } else if (way.equalsIgnoreCase("right")) {
364 MCRCategory categ = findCategory(classif, categoryId);
365 bret = moveRight(categ);
366 } else if (way.equalsIgnoreCase("left")) {
367 MCRCategory categ = findCategory(classif, categoryId);
368 bret = moveLeft(categ);
369 }
370
371 if (bret) {
372 MCRClassificationBrowserData.getClassificationPool().updateClassification(classif);
373 String sessionID = MCRSessionMgr.getCurrentSession().getID();
374 MCRClassificationBrowserData.ClassUserTable.put(classif.getId().getRootID(), sessionID);
375 bret = true;
376 }
377 return bret;
378 } catch (Exception e1) {
379 LOGGER.error("Classification modify failed - the Reason is:" + e1.getMessage(), e1);
380 return false;
381 }
382 }
383
384 private boolean moveUp(MCRCategory cat) {
385 MCRCategory parent = cat.getParent();
386 int index = parent.getChildren().indexOf(cat);
387 if (index > 0) {
388 parent.getChildren().remove(index);
389 parent.getChildren().add(index - 1, cat);
390 return true;
391 } else {
392 return false;
393 }
394 }
395
396 private boolean moveDown(MCRCategory cat) {
397 MCRCategory parent = cat.getParent();
398 int index = parent.getChildren().indexOf(cat);
399 if (index < (parent.getChildren().size() - 1)) {
400 parent.getChildren().remove(index);
401 parent.getChildren().add(index + 1, cat);
402 return true;
403 } else {
404 return false;
405 }
406 }
407
408 private boolean moveRight(MCRCategory cat) {
409 MCRCategory parent = cat.getParent();
410 if (parent.getChildren().size() == 1) {
411 return false;
412 }
413 int index = parent.getChildren().indexOf(cat);
414 parent.getChildren().remove(index);
415 if (index > 0) {
416 index--;
417 }
418 parent.getChildren().get(index).getChildren().add(cat);
419 MCRClassificationBrowserData.getClassificationPool().getMovedCategories().add(cat.getId());
420 return true;
421 }
422
423 private boolean moveLeft(MCRCategory cat) {
424 MCRCategory parent = cat.getParent();
425
426 if ((!parent.isCategory()) || parent == null) {
427 return false;
428 }
429
430 MCRCategory grandParent = parent.getParent();
431 if (grandParent == null) {
432 grandParent = classif;
433 }
434
435 int oldIndex = parent.getChildren().indexOf(cat);
436 int newIndex = grandParent.getChildren().indexOf(parent);
437 parent.getChildren().remove(oldIndex);
438
439 grandParent.getChildren().add(newIndex + 1, cat);
440 MCRClassificationBrowserData.getClassificationPool().getMovedCategories().add(cat.getId());
441 return true;
442 }
443
444 public boolean saveAll() {
445 final boolean saveAll = MCRClassificationBrowserData.getClassificationPool().saveAll();
446 MCRClassificationBrowserData.clearUserClassTable(MCRSessionMgr.getCurrentSession());
447 return saveAll;
448 }
449
450 public boolean purgeAll() {
451 MCRClassificationBrowserData.clearUserClassTable(MCRSessionMgr.getCurrentSession());
452 return MCRClassificationBrowserData.getClassificationPool().purgeAll();
453 }
454
455 /**
456 * Delete a category from a classification.
457 *
458 * @param clid
459 * the classification ID
460 * @param categid
461 * the category ID
462 * @return true if all it's okay, else return false
463 */
464 public final int deleteCategoryInClassification(String clid, String categid) {
465 try {
466 LOGGER.debug("Start delete in classification " + clid + " the category: " + categid);
467 int cnt = 0;
468
469 classif = MCRClassificationBrowserData.getClassificationPool().getClassificationAsPojo(MCRCategoryID.rootID(clid), true);
470 MCRCategoryID id = new MCRCategoryID(clid, categid);
471 MCRCategory categToDelete = findCategory(classif, id);
472 MCRCategory parent = categToDelete.getParent();
473
474 if (parent != null) {
475 Collection<String> links = MCRCategLinkServiceFactory.getInstance().getLinksFromCategory(id);
476 if (links.isEmpty()) {
477 parent.getChildren().remove(categToDelete);
478 MCRClassificationBrowserData.getClassificationPool().updateClassification(classif);
479 String sessionID = MCRSessionMgr.getCurrentSession().getID();
480 MCRClassificationBrowserData.ClassUserTable.put(classif.getId().getRootID(), sessionID);
481 cnt = links.size();
482 LOGGER.info("Classif: " + classif.getId().getRootID());
483 }
484 } else {
485 LOGGER.warn("Category " + categid + " in classification: " + clid + " not found! - nothing todo");
486 }
487
488 return cnt;
489 } catch (Exception e1) {
490 LOGGER.error("Categorie delete failed - the Reason is:" + e1.getMessage() + " " + e1.toString());
491 e1.printStackTrace();
492 return 1;
493 }
494 }
495
496 /**
497 * Delete a classification from the system.
498 *
499 * @param clid
500 * the classification ID
501 * @return
502 */
503 public final boolean deleteClassification(String clid) {
504 LOGGER.debug("Start delete classification " + clid);
505 try {
506 MCRCategoryID mcrclid = MCRCategoryID.rootID(clid);
507 //only delete with DAO if Classification really exists.
508 if (DAO.exist(mcrclid)) {
509 DAO.deleteCategory(mcrclid);
510 }
511 MCRClassificationBrowserData.getClassificationPool().deleteClassification(mcrclid);
512 LOGGER.debug("Classification: " + clid + " deleted.");
513 return true;
514 } catch (Exception e) {
515 LOGGER.error("Classification delete failed - the Reason is:" + e.getMessage() + " .");
516 return false;
517 }
518 }
519
520 /**
521 * Here come private methods
522 */
523
524 public MCRCategory findCategory(MCRCategory classification, MCRCategoryID ID) {
525 MCRCategory found = null;
526 for (MCRCategory cat : classification.getChildren()) {
527 if (cat.getId().equals(ID)) {
528 found = cat;
529 break;
530 }
531 MCRCategory rFound = findCategory(cat, ID);
532 if (rFound != null) {
533 found = rFound;
534 break;
535 }
536 }
537
538 return found;
539 }
540
541 public final void deleteTempFile() {
542 if (fout != null && fout.isFile())
543 fout.delete();
544 fout = null;
545 }
546
547 public final String setTempFile(String name, FileItem fi) {
548 String fname = name;
549 fname.replace(' ', '_');
550 try {
551 fout = new File(CONFIG.getString("MCR.Editor.FileUpload.TempStoragePath"), fname);
552 FileOutputStream fouts = new FileOutputStream(fout);
553 MCRUtils.copyStream(fi.getInputStream(), fouts);
554 fouts.close();
555 fname = fout.getPath();
556 LOGGER.info("Classification temporary stored under " + name);
557 } catch (Exception allE) {
558 LOGGER.info("Error storing under " + fname + " Error: " + allE.getMessage());
559 fname = null;
560 }
561 return fname;
562 }
563
564 }