001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2008
005: * UCS - unique computing solutions gmbh (http://www.ucs.at)
006: * All rights reserved
007: *
008: * The [fleXive](R) project is free software; you can redistribute
009: * it and/or modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation;
011: * either version 2 of the License, or (at your option) any
012: * later version.
013: *
014: * The GNU General Public License can be found at
015: * http://www.gnu.org/copyleft/gpl.html.
016: * A copy is found in the textfile GPL.txt and important notices to the
017: * license from the author are found in LICENSE.txt distributed with
018: * these libraries.
019: *
020: * This library is distributed in the hope that it will be useful,
021: * but WITHOUT ANY WARRANTY; without even the implied warranty of
022: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023: * GNU General Public License for more details.
024: *
025: * For further information about UCS - unique computing solutions gmbh,
026: * please see the company website: http://www.ucs.at
027: *
028: * For further information about [fleXive](R), please see the
029: * project website: http://www.flexive.org
030: *
031: *
032: * This copyright notice MUST APPEAR in all copies of the file!
033: ***************************************************************/package com.flexive.ejb.beans;
034:
035: import com.flexive.core.Database;
036: import com.flexive.core.storage.StorageManager;
037: import com.flexive.core.storage.TreeStorage;
038: import com.flexive.shared.CacheAdmin;
039: import com.flexive.shared.EJBLookup;
040: import com.flexive.shared.FxContext;
041: import com.flexive.shared.FxLanguage;
042: import com.flexive.shared.configuration.SystemParameters;
043: import com.flexive.shared.content.FxContent;
044: import com.flexive.shared.content.FxPK;
045: import com.flexive.shared.exceptions.*;
046: import com.flexive.shared.interfaces.*;
047: import com.flexive.shared.security.UserTicket;
048: import com.flexive.shared.structure.FxPropertyAssignment;
049: import com.flexive.shared.structure.FxType;
050: import com.flexive.shared.tree.FxTreeMode;
051: import static com.flexive.shared.tree.FxTreeMode.Live;
052: import com.flexive.shared.tree.FxTreeNode;
053: import com.flexive.shared.tree.FxTreeNodeEdit;
054: import com.flexive.shared.value.FxReference;
055: import com.flexive.shared.value.FxString;
056: import org.apache.commons.lang.StringUtils;
057: import org.apache.commons.logging.Log;
058: import org.apache.commons.logging.LogFactory;
059:
060: import javax.annotation.Resource;
061: import javax.ejb.*;
062: import java.sql.Connection;
063: import java.util.ArrayList;
064: import java.util.Arrays;
065: import java.util.List;
066:
067: /**
068: * Flexive Tree implementation
069: *
070: * @author Markus Plesser (markus.plesser@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
071: */
072: @Stateless(name="TreeEngine")
073: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
074: @TransactionManagement(TransactionManagementType.CONTAINER)
075: public class TreeEngineBean implements TreeEngine, TreeEngineLocal {
076: private static transient Log LOG = LogFactory
077: .getLog(TreeEngineBean.class);
078:
079: @Resource
080: javax.ejb.SessionContext ctx;
081:
082: @EJB
083: LanguageEngineLocal languageEngine;
084: @EJB
085: ContentEngineLocal contentEngine;
086: @EJB
087: SequencerEngineLocal seq;
088:
089: public TreeEngineBean() {
090: // nothing to do
091: }
092:
093: /**
094: * Get the caption property id
095: *
096: * @return caption property id
097: * @throws FxApplicationException on errors
098: */
099: private long getCaptionPropertyId() throws FxApplicationException {
100: //TODO: cache me!
101: return EJBLookup.getConfigurationEngine().get(
102: SystemParameters.TREE_CAPTION_PROPERTY);
103: }
104:
105: final static boolean PARTIAL_LOADING = true;
106:
107: /**
108: * {@inheritDoc}
109: */
110: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
111: public FxTreeNode getTree(FxTreeMode mode, long nodeId, int depth)
112: throws FxApplicationException {
113: Connection con = null;
114: try {
115: con = Database.getDbConnection();
116: return StorageManager.getTreeStorage().getTree(con,
117: contentEngine, mode, nodeId, depth,
118: PARTIAL_LOADING,
119: FxContext.get().getTicket().getLanguage());
120: } catch (FxApplicationException fx) {
121: throw fx;
122: } catch (Throwable t) {
123: throw new FxLoadException(LOG, t,
124: "ex.tree.load.failed.node", nodeId, mode, t
125: .getMessage());
126: } finally {
127: Database.closeObjects(TreeEngineBean.class, con, null);
128: }
129: }
130:
131: /**
132: * {@inheritDoc}
133: */
134: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
135: public long getIdByPath(FxTreeMode mode, String path)
136: throws FxApplicationException {
137: return getIdByFQNPath(mode, FxTreeNode.ROOT_NODE, path);
138: }
139:
140: /**
141: * {@inheritDoc}
142: */
143: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
144: public long getIdByFQNPath(FxTreeMode mode, long startNode,
145: String path) throws FxApplicationException {
146: Connection con = null;
147: try {
148: con = Database.getDbConnection();
149: return StorageManager.getTreeStorage().getIdByFQNPath(con,
150: mode, startNode, path);
151: } catch (FxApplicationException ae) {
152: throw ae;
153: } catch (Throwable t) {
154: throw new FxTreeException(LOG, t,
155: "ex.tree.getIdByPath.failed", path, mode);
156: } finally {
157: Database.closeObjects(TreeEngineBean.class, con, null);
158: }
159: }
160:
161: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
162: public long getIdByLabelPath(FxTreeMode mode, long startNode,
163: String path) throws FxApplicationException {
164: Connection con = null;
165: try {
166: con = Database.getDbConnection();
167: return StorageManager.getTreeStorage().getIdByLabelPath(
168: con, mode, startNode, path);
169: } catch (FxApplicationException ae) {
170: throw ae;
171: } catch (Throwable t) {
172: throw new FxTreeException(LOG, t,
173: "ex.tree.getIdByPath.failed", path, mode);
174: } finally {
175: Database.closeObjects(TreeEngineBean.class, con, null);
176: }
177: }
178:
179: /**
180: * {@inheritDoc}
181: */
182: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
183: public String getPathById(FxTreeMode mode, long nodeId)
184: throws FxApplicationException {
185: Connection con = null;
186: try {
187: con = Database.getDbConnection();
188: return StorageManager.getTreeStorage().getPathById(con,
189: mode, nodeId);
190: } catch (FxApplicationException ae) {
191: throw ae;
192: } catch (Throwable t) {
193: throw new FxTreeException(LOG, t,
194: "ex.tree.getPathById.failed", nodeId, mode);
195: } finally {
196: Database.closeObjects(TreeEngineBean.class, con, null);
197: }
198: }
199:
200: /**
201: * {@inheritDoc}
202: */
203: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
204: public long[] getIdChain(FxTreeMode mode, long nodeId)
205: throws FxApplicationException {
206: Connection con = null;
207: try {
208: con = Database.getDbConnection();
209: return StorageManager.getTreeStorage().getIdChain(con,
210: mode, nodeId);
211: } catch (FxApplicationException ae) {
212: throw ae;
213: } catch (Throwable t) {
214: throw new FxTreeException(LOG, t,
215: "ex.tree.getIdChain.failed", nodeId, mode);
216: } finally {
217: Database.closeObjects(TreeEngineBean.class, con, null);
218: }
219: }
220:
221: /**
222: * Create a new node
223: *
224: * @param mode tree mode
225: * @param parentNodeId id of the parent node
226: * @param name name (will only be used if no FQN property is available in the reference)
227: * @param label label for Caption property (only used if new reference is created)
228: * @param position position
229: * @param reference referenced content id
230: * @param template optional template to assign @return id of the created node
231: * @return id of the node created
232: * @throws FxApplicationException on errors
233: */
234: public long createNode(long parentNodeId, String name,
235: FxString label, int position, FxPK reference,
236: String template, FxTreeMode mode)
237: throws FxApplicationException {
238: Connection con = null;
239: try {
240: FxContext.get().setTreeWasModified();
241: con = Database.getDbConnection();
242: try {
243: return StorageManager.getTreeStorage().createNode(con,
244: seq, contentEngine, mode, -1, parentNodeId,
245: name, label, position, reference, template);
246: } finally {
247: StorageManager.getTreeStorage().checkTreeIfEnabled(con,
248: mode);
249: }
250: } catch (FxApplicationException ae) {
251: throw ae;
252: } catch (Throwable t) {
253: throw new FxCreateException(LOG, t,
254: "ex.tree.create.failed", name);
255: } finally {
256: Database.closeObjects(TreeEngineBean.class, con, null);
257: }
258: }
259:
260: /**
261: * {@inheritDoc}
262: */
263: @TransactionAttribute(TransactionAttributeType.REQUIRED)
264: public long[] createNodes(FxTreeMode mode, long parentNodeId,
265: int position, String path) throws FxApplicationException {
266: Connection con = null;
267: try {
268: FxContext.get().setTreeWasModified();
269: con = Database.getDbConnection();
270: try {
271: return StorageManager.getTreeStorage().createNodes(con,
272: seq, contentEngine, mode, parentNodeId, path,
273: position);
274: } finally {
275: StorageManager.getTreeStorage().checkTreeIfEnabled(con,
276: mode);
277: }
278: } catch (FxApplicationException ae) {
279: ctx.setRollbackOnly();
280: throw ae;
281: } catch (Throwable t) {
282: ctx.setRollbackOnly();
283: throw new FxCreateException(LOG, t,
284: "ex.tree.create.failed", path);
285: } finally {
286: Database.closeObjects(TreeEngineBean.class, con, null);
287: }
288: }
289:
290: /**
291: * {@inheritDoc}
292: */
293: @TransactionAttribute(TransactionAttributeType.REQUIRED)
294: public void clear(FxTreeMode mode) throws FxApplicationException {
295: Connection con = null;
296: try {
297: FxContext.get().setTreeWasModified();
298: con = Database.getDbConnection();
299: UserTicket ticket = FxContext.get().getTicket();
300: if (FxContext.get().getRunAsSystem()
301: || ticket.isGlobalSupervisor())
302: StorageManager.getTreeStorage().clearTree(con,
303: contentEngine, mode);
304: else
305: throw new FxApplicationException(
306: "ex.tree.clear.notAllowed", mode.name());
307: } catch (FxApplicationException ae) {
308: ctx.setRollbackOnly();
309: throw ae;
310: } catch (Throwable t) {
311: ctx.setRollbackOnly();
312: throw new FxCreateException(LOG, t,
313: "FxTree.err.clear.failed", mode);
314: } finally {
315: Database.closeObjects(TreeEngineBean.class, con, null);
316: }
317: }
318:
319: /**
320: * {@inheritDoc}
321: */
322: @TransactionAttribute(TransactionAttributeType.REQUIRED)
323: public void renameNode(long nodeId, FxTreeMode mode, String name,
324: FxString label) throws FxApplicationException {
325: Connection con = null;
326: // boolean setInContent = false;
327: try {
328: FxContext.get().setTreeWasModified();
329: con = Database.getDbConnection();
330: FxTreeNode node = getNode(mode, nodeId);
331: boolean nameChanged = false;
332: if (!node.getName().equals(name)
333: && !StringUtils.isEmpty(name)) {
334: StorageManager.getTreeStorage().updateName(con, mode,
335: contentEngine, nodeId, name);
336: nameChanged = true;
337: }
338:
339: if (label != null) {
340: // Load the content and its type
341: FxPK pk = new FxPK(node.getReference().getId(),
342: mode == Live ? FxPK.LIVE : FxPK.MAX);
343: FxContent co = contentEngine.load(pk);
344: FxType type = CacheAdmin.getEnvironment().getType(
345: co.getTypeId());
346: //noinspection LoopStatementThatDoesntLoop
347: for (FxPropertyAssignment pa : type
348: .getAssignmentsForProperty(getCaptionPropertyId())) {
349: if (pa.isMultiLang() == label.isMultiLanguage()) {
350: co.setValue(pa.getXPath(), label);
351: } else {
352: if (pa.isMultiLang()
353: && !label.isMultiLanguage()) {
354: FxString org = (FxString) co.getValue(pa
355: .getXPath());
356: org.setDefaultTranslation(label
357: .getDefaultTranslation());
358: co.setValue(pa.getXPath(), org);
359: } else if (!pa.isMultiLang()
360: && label.isMultiLanguage()) {
361: co.setValue(pa.getXPath(), new FxString(
362: false, label.getBestTranslation()));
363: }
364: }
365: contentEngine.save(co);
366: FxContext.get().setTreeWasModified();
367: return; //just change first occurance
368: }
369: //if we reach this, no caption property exists
370: if (!nameChanged && !label.equals(node.getLabel())) {
371: StorageManager.getTreeStorage().updateName(con,
372: mode, contentEngine, nodeId,
373: node.getLabel().getBestTranslation());
374: }
375: }
376: StorageManager.getTreeStorage().checkTreeIfEnabled(con,
377: mode);
378: } catch (Exception t) {
379: ctx.setRollbackOnly();
380: throw new FxUpdateException(LOG, t,
381: "ex.tree.rename.failed", nodeId);
382: } finally {
383: Database.closeObjects(TreeEngineBean.class, con, null);
384: }
385: }
386:
387: /**
388: * Deletes the given node.
389: *
390: * @param mode tree mode to use (Live or Edit tree)
391: * @param nodeId the node to delete
392: * @param deleteReferencedContent delete referenced content
393: * @param deleteChildren if true all nodes that are inside the subtree of the given node are
394: * deleted as well, if false the subtree is moved one level up (to the parent of the specified
395: * node)
396: * @throws FxApplicationException on errors
397: */
398: public void removeNode(FxTreeMode mode, long nodeId,
399: boolean deleteReferencedContent, boolean deleteChildren)
400: throws FxApplicationException {
401: Connection con = null;
402: FxPK ref = null;
403: try {
404: FxContext.get().setTreeWasModified();
405: con = Database.getDbConnection();
406: if (deleteReferencedContent)
407: ref = getNode(mode, nodeId).getReference();
408: StorageManager.getTreeStorage().removeNode(con, mode,
409: contentEngine, nodeId, deleteChildren);
410: if (ref != null)
411: contentEngine.remove(ref);
412: StorageManager.getTreeStorage().checkTreeIfEnabled(con,
413: mode);
414: } catch (FxNotFoundException nf) {
415: // Node does not exist and we wanted to delete it anyway .. so this is no error
416: } catch (FxApplicationException ae) {
417: ctx.setRollbackOnly();
418: throw ae;
419: } catch (Throwable t) {
420: ctx.setRollbackOnly();
421: throw new FxRemoveException(LOG, t,
422: "ex.tree.delete.failed", nodeId, t.getMessage());
423: } finally {
424: Database.closeObjects(TreeEngineBean.class, con, null);
425: }
426: }
427:
428: /**
429: * {@inheritDoc}
430: */
431: @TransactionAttribute(TransactionAttributeType.REQUIRED)
432: public void move(FxTreeMode mode, long nodeId, long destinationId,
433: int newPosition) throws FxApplicationException {
434: Connection con = null;
435: try {
436: con = Database.getDbConnection();
437: StorageManager.getTreeStorage().move(con, seq, mode,
438: nodeId, destinationId, newPosition);
439: StorageManager.getTreeStorage().checkTreeIfEnabled(con,
440: mode);
441: FxContext.get().setTreeWasModified();
442: } catch (FxApplicationException ae) {
443: ctx.setRollbackOnly();
444: throw ae;
445: } catch (Throwable t) {
446: ctx.setRollbackOnly();
447: throw new FxUpdateException(LOG, t, "ex.tree.move.failed",
448: nodeId, destinationId, newPosition);
449: } finally {
450: Database.closeObjects(TreeEngineBean.class, con, null);
451: }
452: }
453:
454: /**
455: * {@inheritDoc}
456: */
457: @TransactionAttribute(TransactionAttributeType.REQUIRED)
458: public long copy(FxTreeMode mode, long source, long destination,
459: int destinationPosition) throws FxApplicationException {
460: FxContext.get().setTreeWasModified();
461: Connection con = null;
462: try {
463: con = Database.getDbConnection();
464: try {
465: return StorageManager.getTreeStorage().copy(con, seq,
466: mode, source, destination, destinationPosition,
467: false, "CopyOf_");
468: } finally {
469: StorageManager.getTreeStorage().checkTreeIfEnabled(con,
470: mode);
471: }
472: } catch (FxApplicationException ae) {
473: ctx.setRollbackOnly();
474: throw ae;
475: } catch (Throwable t) {
476: ctx.setRollbackOnly();
477: throw new FxUpdateException(LOG, t, "ex.tree.copy.failed",
478: source, destination, destinationPosition);
479: } finally {
480: Database.closeObjects(TreeEngineBean.class, con, null);
481: }
482: }
483:
484: /**
485: * {@inheritDoc}
486: */
487: @TransactionAttribute(TransactionAttributeType.REQUIRED)
488: public void activate(FxTreeMode mode, long nodeId,
489: boolean includeChildren) throws FxApplicationException {
490: Connection con = null;
491: try {
492: if (mode == FxTreeMode.Live)
493: return;
494: con = Database.getDbConnection();
495: if (!includeChildren) {
496: //if the node is a leaf node, always activate with children to propagate removed subnodes
497: if (StorageManager.getTreeStorage().getNode(con, mode,
498: nodeId).isLeaf())
499: includeChildren = true;
500: }
501: if (includeChildren)
502: StorageManager.getTreeStorage().activateSubtree(con,
503: seq, contentEngine, mode, nodeId);
504: else
505: StorageManager.getTreeStorage().activateNode(con, seq,
506: contentEngine, mode, nodeId);
507: StorageManager.getTreeStorage().checkTreeIfEnabled(con,
508: mode);
509: StorageManager.getTreeStorage().checkTreeIfEnabled(con,
510: FxTreeMode.Live);
511: FxContext.get().setTreeWasModified();
512: } catch (FxApplicationException ae) {
513: ctx.setRollbackOnly();
514: throw ae;
515: } catch (Throwable t) {
516: ctx.setRollbackOnly();
517: throw new FxUpdateException(LOG, t,
518: "ex.tree.activate.failed", nodeId, includeChildren,
519: t.getMessage());
520: } finally {
521: Database.closeObjects(TreeEngineBean.class, con, null);
522: }
523: }
524:
525: /**
526: * {@inheritDoc}
527: */
528: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
529: public List<FxTreeNode> getNodesWithReference(FxTreeMode mode,
530: long reference) throws FxApplicationException {
531: Connection con = null;
532: try {
533: con = Database.getDbConnection();
534: return StorageManager.getTreeStorage()
535: .getNodesWithReference(con, mode, reference);
536: } catch (FxApplicationException ae) {
537: throw ae;
538: } catch (Throwable t) {
539: throw new FxUpdateException(LOG, t,
540: "ex.tree.getNodesWithReference.failed", mode,
541: reference);
542: } finally {
543: Database.closeObjects(TreeEngineBean.class, con, null);
544: }
545: }
546:
547: /**
548: * {@inheritDoc}
549: */
550: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
551: public FxTreeNode getNode(FxTreeMode mode, long id)
552: throws FxApplicationException {
553: Connection con = null;
554: try {
555: con = Database.getDbConnection();
556: return StorageManager.getTreeStorage().getNode(con, mode,
557: id);
558: } catch (FxApplicationException fx) {
559: throw fx;
560: } catch (Throwable t) {
561: throw new FxLoadException(LOG, t,
562: "ex.tree.load.failed.node", id, mode, t
563: .getMessage());
564: } finally {
565: Database.closeObjects(TreeEngineBean.class, con, null);
566: }
567: }
568:
569: /**
570: * {@inheritDoc}
571: */
572: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
573: public List<String> getPaths(FxTreeMode mode, long... ids)
574: throws FxApplicationException {
575: if (ids == null || ids.length == 0)
576: return new ArrayList<String>(0);
577: Connection con = null;
578: try {
579: con = Database.getDbConnection();
580: List<String> res = new ArrayList<String>(ids.length);
581: TreeStorage tree = StorageManager.getTreeStorage();
582: for (long id : ids)
583: res.add(tree.getPathById(con, mode, id));
584: return res;
585: } catch (FxApplicationException ae) {
586: throw ae;
587: } catch (Throwable t) {
588: throw new FxTreeException(LOG, t,
589: "ex.tree.getPaths.failed", Arrays.toString(ids),
590: mode);
591: } finally {
592: Database.closeObjects(TreeEngineBean.class, con, null);
593: }
594: }
595:
596: /**
597: * {@inheritDoc}
598: */
599: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
600: public List<String> getLabels(FxTreeMode mode, long... ids)
601: throws FxApplicationException {
602: return getLabels(mode, FxContext.get().getTicket()
603: .getLanguage(), ids);
604: }
605:
606: /**
607: * {@inheritDoc}
608: */
609: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
610: public List<String> getLabels(FxTreeMode mode, FxLanguage language,
611: long... ids) throws FxApplicationException {
612: Connection con = null;
613: try {
614: con = Database.getDbConnection();
615: return StorageManager.getTreeStorage().getLabels(con, mode,
616: getCaptionPropertyId(), language, true, ids);
617: } catch (FxApplicationException ae) {
618: throw ae;
619: } catch (Throwable t) {
620: throw new FxUpdateException(LOG, t,
621: "ex.tree.getLabels.failed", mode, language
622: .getIso2digit(), t.getMessage());
623: } finally {
624: Database.closeObjects(TreeEngineBean.class, con, null);
625: }
626: }
627:
628: /**
629: * {@inheritDoc}
630: */
631: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
632: public boolean exist(FxTreeMode mode, long id)
633: throws FxApplicationException {
634: Connection con = null;
635: try {
636: con = Database.getDbConnection();
637: return StorageManager.getTreeStorage()
638: .exists(con, mode, id);
639: } catch (FxApplicationException ae) {
640: throw ae;
641: } catch (Throwable t) {
642: throw new FxLoadException(LOG, t, "ex.tree.exist.failed",
643: id, mode, t.getMessage());
644: } finally {
645: Database.closeObjects(TreeEngineBean.class, con, null);
646: }
647: }
648:
649: /**
650: * {@inheritDoc}
651: */
652: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
653: public String[] getTemplates(FxTreeMode mode, long id) {
654: throw new UnsupportedOperationException("Not implemented yet");
655: }
656:
657: /**
658: * {@inheritDoc}
659: */
660: @TransactionAttribute(TransactionAttributeType.REQUIRED)
661: public long[] getReverseIdChain(FxTreeMode mode, long id) {
662: throw new UnsupportedOperationException("Not implemented yet");
663: }
664:
665: /**
666: * {@inheritDoc}
667: */
668: @TransactionAttribute(TransactionAttributeType.REQUIRED)
669: public void setTemplate(FxTreeMode mode, long nodeId,
670: String template) {
671: throw new UnsupportedOperationException("Not implemented yet");
672: }
673:
674: /**
675: * {@inheritDoc}
676: */
677: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
678: public FxTreeNode findChild(FxTreeMode mode, long nodeId,
679: String name) throws FxApplicationException {
680: for (FxTreeNode node : getTree(mode, nodeId, 1).getChildren()) {
681: if (node.getName().equals(name)) {
682: return node;
683: }
684: }
685: throw new FxNotFoundException(LOG, "ex.tree.nodeNotFound.name",
686: name, mode, nodeId);
687: }
688:
689: /**
690: * {@inheritDoc}
691: */
692: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
693: public FxTreeNode findChild(FxTreeMode mode, long nodeId,
694: long referenceId) throws FxApplicationException {
695: for (FxTreeNode node : getTree(mode, nodeId, 1).getChildren())
696: if (node.getReference().getId() == referenceId)
697: return node;
698: throw new FxNotFoundException(LOG,
699: "ex.tree.nodeNotFound.reference", referenceId, mode,
700: nodeId);
701: }
702:
703: /**
704: * {@inheritDoc}
705: */
706: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
707: public FxTreeNode findChild(FxTreeMode mode, long nodeId, FxPK pk)
708: throws FxApplicationException {
709: return findChild(mode, nodeId, pk.getId());
710: }
711:
712: /**
713: * {@inheritDoc}
714: */
715: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
716: public FxTreeNode findChild(FxTreeMode mode, long nodeId,
717: FxReference reference) throws FxApplicationException {
718: return findChild(mode, nodeId, reference.getBestTranslation()
719: .getId());
720: }
721:
722: /**
723: * {@inheritDoc}
724: */
725: @TransactionAttribute(TransactionAttributeType.REQUIRED)
726: public long save(FxTreeNodeEdit node) throws FxApplicationException {
727: if (node.isPartialLoaded())
728: throw new FxTreeException("ex.tree.partialnode.notAllowed",
729: node.getMode(), node.getId());
730: if (node.isNew()) {
731: return createNode(node.getParentNodeId(), node.getName(),
732: node.getLabel(), node.getPosition(), node
733: .getReference(), node.getTemplate(), node
734: .getMode());
735: } else {
736: FxTreeNode old = getNode(node.getOriginalMode(), node
737: .getId());
738: if (!old.getName().equals(node.getName())
739: || !old.getLabel().equals(node.getLabel()))
740: renameNode(node.getId(), node.getOriginalMode(), node
741: .getName(), node.getLabel());
742: if (old.getParentNodeId() != node.getParentNodeId()
743: || old.getPosition() != node.getPosition())
744: move(node.getMode(), node.getId(), node
745: .getParentNodeId(), node.getPosition());
746: if (node.isActivate() && node.getMode() != FxTreeMode.Live)
747: activate(FxTreeMode.Edit, node.getId(), node
748: .isActivateWithChildren());
749: }
750: return node.getId();
751: }
752:
753: /**
754: * {@inheritDoc}
755: */
756: @TransactionAttribute(TransactionAttributeType.REQUIRED)
757: public void remove(FxTreeNode node,
758: boolean removeReferencedContent, boolean removeChildren)
759: throws FxApplicationException {
760: removeNode(node.getMode(), node.getId(),
761: removeReferencedContent, removeChildren);
762: }
763:
764: /**
765: * {@inheritDoc}
766: */
767: @TransactionAttribute(TransactionAttributeType.REQUIRED)
768: public void populate(FxTreeMode mode) throws FxApplicationException {
769: Connection con = null;
770: try {
771: con = Database.getDbConnection();
772: StorageManager.getTreeStorage().populate(con, seq,
773: contentEngine, mode);
774: FxContext.get().setTreeWasModified();
775: } catch (FxApplicationException ae) {
776: ctx.setRollbackOnly();
777: throw ae;
778: } catch (Throwable t) {
779: ctx.setRollbackOnly();
780: throw new FxLoadException(LOG, t, "ex.tree.populate", mode,
781: t.getMessage());
782: } finally {
783: Database.closeObjects(TreeEngineBean.class, con, null);
784: }
785: }
786: }
|