KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > web > bean > ForumsBean


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.web.bean;
18
19 import java.io.IOException JavaDoc;
20 import java.io.Writer JavaDoc;
21 import java.text.MessageFormat JavaDoc;
22 import java.text.SimpleDateFormat JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Collections JavaDoc;
25 import java.util.Date JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Map JavaDoc;
29
30 import javax.faces.component.UIComponent;
31 import javax.faces.context.FacesContext;
32 import javax.faces.context.ResponseWriter;
33 import javax.faces.event.ActionEvent;
34 import javax.transaction.UserTransaction JavaDoc;
35
36 import org.alfresco.error.AlfrescoRuntimeException;
37 import org.alfresco.model.ContentModel;
38 import org.alfresco.model.ForumModel;
39 import org.alfresco.service.cmr.dictionary.DictionaryService;
40 import org.alfresco.service.cmr.dictionary.TypeDefinition;
41 import org.alfresco.service.cmr.repository.AssociationRef;
42 import org.alfresco.service.cmr.repository.ChildAssociationRef;
43 import org.alfresco.service.cmr.repository.ContentReader;
44 import org.alfresco.service.cmr.repository.ContentService;
45 import org.alfresco.service.cmr.repository.InvalidNodeRefException;
46 import org.alfresco.service.cmr.repository.NodeRef;
47 import org.alfresco.service.cmr.repository.NodeService;
48 import org.alfresco.service.cmr.search.QueryParameterDefinition;
49 import org.alfresco.service.cmr.search.SearchService;
50 import org.alfresco.service.cmr.security.PermissionService;
51 import org.alfresco.service.namespace.NamespaceService;
52 import org.alfresco.service.namespace.QName;
53 import org.alfresco.service.namespace.RegexQNamePattern;
54 import org.alfresco.web.app.AlfrescoNavigationHandler;
55 import org.alfresco.web.app.Application;
56 import org.alfresco.web.app.context.IContextListener;
57 import org.alfresco.web.app.context.UIContextService;
58 import org.alfresco.web.bean.repository.MapNode;
59 import org.alfresco.web.bean.repository.Node;
60 import org.alfresco.web.bean.repository.NodePropertyResolver;
61 import org.alfresco.web.bean.repository.QNameNodeMap;
62 import org.alfresco.web.bean.repository.Repository;
63 import org.alfresco.web.config.ViewsConfigElement;
64 import org.alfresco.web.ui.common.Utils;
65 import org.alfresco.web.ui.common.component.UIActionLink;
66 import org.alfresco.web.ui.common.component.UIModeList;
67 import org.alfresco.web.ui.common.component.data.UIColumn;
68 import org.alfresco.web.ui.common.component.data.UIRichList;
69 import org.alfresco.web.ui.common.renderer.data.IRichListRenderer;
70 import org.apache.commons.logging.Log;
71 import org.apache.commons.logging.LogFactory;
72 import org.springframework.util.StringUtils;
73
74 /**
75  * Bean providing properties and behaviour for the forums screens.
76  *
77  * @author gavinc
78  */

79 public class ForumsBean implements IContextListener, NodeEventListener
80 {
81    private static Log logger = LogFactory.getLog(ForumsBean.class);
82    private static final String JavaDoc PAGE_NAME_FORUMS = "forums";
83    private static final String JavaDoc PAGE_NAME_FORUM = "forum";
84    private static final String JavaDoc PAGE_NAME_TOPIC = "topic";
85    
86    /** The NodeService to be used by the bean */
87    protected NodeService nodeService;
88    
89    /** The ContentService to be used by the bean */
90    protected ContentService contentService;
91    
92    /** The DictionaryService bean reference */
93    protected DictionaryService dictionaryService;
94    
95    /** The SearchService bean reference. */
96    protected SearchService searchService;
97    
98    /** The NamespaceService bean reference. */
99    protected NamespaceService namespaceService;
100    
101    /** The browse bean */
102    protected BrowseBean browseBean;
103    
104    /** The NavigationBean bean reference */
105    protected NavigationBean navigator;
106    
107    /** Views configuration object */
108    protected ViewsConfigElement viewsConfig = null;
109    
110    /** Component references */
111    protected UIRichList forumsRichList;
112    protected UIRichList forumRichList;
113    protected UIRichList topicRichList;
114
115    /** Node lists */
116    private List JavaDoc<Node> forums;
117    private List JavaDoc<Node> topics;
118    private List JavaDoc<Node> posts;
119    
120    /** The current forums view mode - set to a well known IRichListRenderer identifier */
121    private String JavaDoc forumsViewMode;
122    
123    /** The current forums view page size */
124    private int forumsPageSize;
125    
126    /** The current forum view mode - set to a well known IRichListRenderer identifier */
127    private String JavaDoc forumViewMode;
128    
129    /** The current forum view page size */
130    private int forumPageSize;
131    
132    /** The current topic view mode - set to a well known IRichListRenderer identifier */
133    private String JavaDoc topicViewMode;
134    
135    /** The current topic view page size */
136    private int topicPageSize;
137    
138    
139    // ------------------------------------------------------------------------------
140
// Construction
141

142    /**
143     * Default Constructor
144     */

145    public ForumsBean()
146    {
147       UIContextService.getInstance(FacesContext.getCurrentInstance()).registerBean(this);
148       
149       initFromClientConfig();
150    }
151    
152    
153    // ------------------------------------------------------------------------------
154
// Bean property getters and setters
155

156    /**
157     * @param nodeService The NodeService to set.
158     */

159    public void setNodeService(NodeService nodeService)
160    {
161       this.nodeService = nodeService;
162    }
163    
164    /**
165     * Sets the content service to use
166     *
167     * @param contentService The ContentService
168     */

169    public void setContentService(ContentService contentService)
170    {
171       this.contentService = contentService;
172    }
173
174    /**
175     * @param dictionaryService The DictionaryService to set.
176     */

177    public void setDictionaryService(DictionaryService dictionaryService)
178    {
179       this.dictionaryService = dictionaryService;
180    }
181    
182    /**
183     * @param searchService The SearchService to set.
184     */

185    public void setSearchService(SearchService searchService)
186    {
187       this.searchService = searchService;
188    }
189
190    /**
191     * @param namespaceService The NamespaceService to set.
192     */

193    public void setNamespaceService(NamespaceService namespaceService)
194    {
195       this.namespaceService = namespaceService;
196    }
197
198    /**
199     * Sets the BrowseBean instance to use to retrieve the current document
200     *
201     * @param browseBean BrowseBean instance
202     */

203    public void setBrowseBean(BrowseBean browseBean)
204    {
205       this.browseBean = browseBean;
206    }
207    
208    /**
209     * @param navigator The NavigationBean to set.
210     */

211    public void setNavigator(NavigationBean navigator)
212    {
213       this.navigator = navigator;
214    }
215    
216    /**
217     * @param forumsRichList The forumsRichList to set.
218     */

219    public void setForumsRichList(UIRichList forumsRichList)
220    {
221       this.forumsRichList = forumsRichList;
222       if (this.forumsRichList != null)
223       {
224          // set the initial sort column and direction
225
this.forumsRichList.setInitialSortColumn(
226                this.viewsConfig.getDefaultSortColumn(PAGE_NAME_FORUMS));
227          this.forumsRichList.setInitialSortDescending(
228                this.viewsConfig.hasDescendingSort(PAGE_NAME_FORUMS));
229       }
230    }
231    
232    /**
233     * @return Returns the forumsRichList.
234     */

235    public UIRichList getForumsRichList()
236    {
237       return this.forumsRichList;
238    }
239    
240    /**
241     * @return Returns the forums View mode. See UIRichList
242     */

243    public String JavaDoc getForumsViewMode()
244    {
245       return this.forumsViewMode;
246    }
247    
248    /**
249     * @param forumsViewMode The forums View mode to set. See UIRichList.
250     */

251    public void setForumsViewMode(String JavaDoc forumsViewMode)
252    {
253       this.forumsViewMode = forumsViewMode;
254    }
255    
256    /**
257     * @return Returns the forumsPageSize.
258     */

259    public int getForumsPageSize()
260    {
261       return this.forumsPageSize;
262    }
263    
264    /**
265     * @param forumsPageSize The forumsPageSize to set.
266     */

267    public void setForumsPageSize(int forumsPageSize)
268    {
269       this.forumsPageSize = forumsPageSize;
270    }
271    
272    /**
273     * @param topicRichList The topicRichList to set.
274     */

275    public void setTopicRichList(UIRichList topicRichList)
276    {
277       this.topicRichList = topicRichList;
278       
279       if (this.topicRichList != null)
280       {
281          // set the initial sort column and direction
282
this.topicRichList.setInitialSortColumn(
283                this.viewsConfig.getDefaultSortColumn(PAGE_NAME_TOPIC));
284          this.topicRichList.setInitialSortDescending(
285                this.viewsConfig.hasDescendingSort(PAGE_NAME_TOPIC));
286       }
287    }
288    
289    /**
290     * @return Returns the topicRichList.
291     */

292    public UIRichList getTopicRichList()
293    {
294       return this.topicRichList;
295    }
296    
297    /**
298     * @return Returns the topics View mode. See UIRichList
299     */

300    public String JavaDoc getTopicViewMode()
301    {
302       return this.topicViewMode;
303    }
304    
305    /**
306     * @param topicViewMode The topic View mode to set. See UIRichList.
307     */

308    public void setTopicViewMode(String JavaDoc topicViewMode)
309    {
310       this.topicViewMode = topicViewMode;
311    }
312    
313    /**
314     * @return Returns the topicsPageSize.
315     */

316    public int getTopicPageSize()
317    {
318       return this.topicPageSize;
319    }
320    
321    /**
322     * @param topicPageSize The topicPageSize to set.
323     */

324    public void setTopicPageSize(int topicPageSize)
325    {
326       this.topicPageSize = topicPageSize;
327    }
328    
329    /**
330     * @param forumRichList The forumRichList to set.
331     */

332    public void setForumRichList(UIRichList forumRichList)
333    {
334       this.forumRichList = forumRichList;
335       
336       if (this.forumRichList != null)
337       {
338          // set the initial sort column and direction
339
this.forumRichList.setInitialSortColumn(
340                this.viewsConfig.getDefaultSortColumn(PAGE_NAME_FORUM));
341          this.forumRichList.setInitialSortDescending(
342                this.viewsConfig.hasDescendingSort(PAGE_NAME_FORUM));
343       }
344    }
345    
346    /**
347     * @return Returns the forumRichList.
348     */

349    public UIRichList getForumRichList()
350    {
351       return this.forumRichList;
352    }
353    
354    /**
355     * @return Returns the forum View mode. See UIRichList
356     */

357    public String JavaDoc getForumViewMode()
358    {
359       return this.forumViewMode;
360    }
361    
362    /**
363     * @param forumViewMode The forum View mode to set. See UIRichList.
364     */

365    public void setForumViewMode(String JavaDoc forumViewMode)
366    {
367       this.forumViewMode = forumViewMode;
368    }
369    
370    /**
371     * @return Returns the forumPageSize.
372     */

373    public int getForumPageSize()
374    {
375       return this.forumPageSize;
376    }
377    
378    /**
379     * @param forumPageSize The forumPageSize to set.
380     */

381    public void setForumPageSize(int forumPageSize)
382    {
383       this.forumPageSize = forumPageSize;
384    }
385    
386    public List JavaDoc<Node> getForums()
387    {
388       if (this.forums == null)
389       {
390          getNodes();
391       }
392       
393       return this.forums;
394    }
395    
396    public List JavaDoc<Node> getTopics()
397    {
398       if (this.topics == null)
399       {
400          getNodes();
401       }
402       
403       return this.topics;
404    }
405    
406    public List JavaDoc<Node> getPosts()
407    {
408       if (this.posts == null)
409       {
410          getNodes();
411       }
412       
413       return this.posts;
414    }
415    
416    private void getNodes()
417    {
418       long startTime = 0;
419       if (logger.isDebugEnabled())
420          startTime = System.currentTimeMillis();
421       
422       UserTransaction JavaDoc tx = null;
423       try
424       {
425          FacesContext context = FacesContext.getCurrentInstance();
426          tx = Repository.getUserTransaction(context, true);
427          tx.begin();
428          
429          // get the current space from NavigationBean
430
String JavaDoc parentNodeId = this.navigator.getCurrentNodeId();
431          
432          NodeRef parentRef;
433          if (parentNodeId == null)
434          {
435             // no specific parent node specified - use the root node
436
parentRef = this.nodeService.getRootNode(Repository.getStoreRef());
437          }
438          else
439          {
440             // build a NodeRef for the specified Id and our store
441
parentRef = new NodeRef(Repository.getStoreRef(), parentNodeId);
442          }
443          
444          List JavaDoc<ChildAssociationRef> childRefs = this.nodeService.getChildAssocs(parentRef,
445                ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
446          this.forums = new ArrayList JavaDoc<Node>(childRefs.size());
447          this.topics = new ArrayList JavaDoc<Node>(childRefs.size());
448          this.posts = new ArrayList JavaDoc<Node>(childRefs.size());
449          
450          for (ChildAssociationRef ref: childRefs)
451          {
452             // create our Node representation from the NodeRef
453
NodeRef nodeRef = ref.getChildRef();
454             
455             if (this.nodeService.exists(nodeRef))
456             {
457                // find it's type so we can see if it's a node we are interested in
458
QName type = this.nodeService.getType(nodeRef);
459                
460                // make sure the type is defined in the data dictionary
461
TypeDefinition typeDef = this.dictionaryService.getType(type);
462                
463                if (typeDef != null)
464                {
465                   // extract forums, forum, topic and post types
466

467                   if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER) == false)
468                   {
469                      if (this.dictionaryService.isSubClass(type, ForumModel.TYPE_FORUMS) ||
470                          this.dictionaryService.isSubClass(type, ForumModel.TYPE_FORUM))
471                      {
472                         // create our Node representation
473
MapNode node = new MapNode(nodeRef, this.nodeService, true);
474                         node.addPropertyResolver("icon", this.browseBean.resolverSpaceIcon);
475                         node.addPropertyResolver("smallIcon", this.resolverSmallIcon);
476                         
477                         this.forums.add(node);
478                      }
479                      if (this.dictionaryService.isSubClass(type, ForumModel.TYPE_TOPIC))
480                      {
481                         // create our Node representation
482
MapNode node = new MapNode(nodeRef, this.nodeService, true);
483                         node.addPropertyResolver("icon", this.browseBean.resolverSpaceIcon);
484                         node.addPropertyResolver("smallIcon", this.resolverSmallIcon);
485                         node.addPropertyResolver("replies", this.resolverReplies);
486                         
487                         this.topics.add(node);
488                      }
489                      else if (this.dictionaryService.isSubClass(type, ForumModel.TYPE_POST))
490                      {
491                         // create our Node representation
492
MapNode node = new MapNode(nodeRef, this.nodeService, true);
493                         
494                         this.browseBean.setupCommonBindingProperties(node);
495                         node.addPropertyResolver("smallIcon", this.resolverSmallIcon);
496                         node.addPropertyResolver("message", this.resolverContent);
497                         node.addPropertyResolver("replyTo", this.resolverReplyTo);
498                         
499                         this.posts.add(node);
500                      }
501                   }
502                }
503                else
504                {
505                   if (logger.isWarnEnabled())
506                      logger.warn("Found invalid object in database: id = " + nodeRef + ", type = " + type);
507                }
508             }
509          }
510          
511          // commit the transaction
512
tx.commit();
513       }
514       catch (InvalidNodeRefException refErr)
515       {
516          Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
517                FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object JavaDoc[] {refErr.getNodeRef()}) );
518          this.forums = Collections.<Node>emptyList();
519          this.topics = Collections.<Node>emptyList();
520          this.posts = Collections.<Node>emptyList();
521          try { if (tx != null) {tx.rollback();} } catch (Exception JavaDoc tex) {}
522       }
523       catch (Throwable JavaDoc err)
524       {
525          Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
526                FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
527          this.forums = Collections.<Node>emptyList();
528          this.topics = Collections.<Node>emptyList();
529          this.posts = Collections.<Node>emptyList();
530          try { if (tx != null) {tx.rollback();} } catch (Exception JavaDoc tex) {}
531       }
532       
533       if (logger.isDebugEnabled())
534       {
535          long endTime = System.currentTimeMillis();
536          logger.debug("Time to query and build forums nodes: " + (endTime - startTime) + "ms");
537       }
538    }
539    
540    
541    // ------------------------------------------------------------------------------
542
// IContextListener implementation
543

544    /**
545     * @see org.alfresco.web.app.context.IContextListener#contextUpdated()
546     */

547    public void contextUpdated()
548    {
549       if (logger.isDebugEnabled())
550          logger.debug("Invalidating forums components...");
551       
552       // clear the value for the list components - will cause re-bind to it's data and refresh
553
if (this.forumsRichList != null)
554       {
555          this.forumsRichList.setValue(null);
556          if (this.forumsRichList.getInitialSortColumn() == null)
557          {
558             // set the initial sort column and direction
559
this.forumsRichList.setInitialSortColumn(
560                   this.viewsConfig.getDefaultSortColumn(PAGE_NAME_FORUMS));
561             this.forumsRichList.setInitialSortDescending(
562                   this.viewsConfig.hasDescendingSort(PAGE_NAME_FORUMS));
563          }
564       }
565       
566       if (this.forumRichList != null)
567       {
568          this.forumRichList.setValue(null);
569          if (this.forumRichList.getInitialSortColumn() == null)
570          {
571             // set the initial sort column and direction
572
this.forumRichList.setInitialSortColumn(
573                   this.viewsConfig.getDefaultSortColumn(PAGE_NAME_FORUM));
574             this.forumRichList.setInitialSortDescending(
575                   this.viewsConfig.hasDescendingSort(PAGE_NAME_FORUM));
576          }
577       }
578       
579       if (this.topicRichList != null)
580       {
581          this.topicRichList.setValue(null);
582          if (this.topicRichList.getInitialSortColumn() == null)
583          {
584             // set the initial sort column and direction
585
this.topicRichList.setInitialSortColumn(
586                   this.viewsConfig.getDefaultSortColumn(PAGE_NAME_TOPIC));
587             this.topicRichList.setInitialSortDescending(
588                   this.viewsConfig.hasDescendingSort(PAGE_NAME_TOPIC));
589          }
590       }
591       
592       // reset the lists
593
this.forums = null;
594       this.topics = null;
595       this.posts = null;
596    }
597    
598    
599    // ------------------------------------------------------------------------------
600
// NodeEventListener implementation
601

602    /**
603     * @see org.alfresco.web.bean.NodeEventListener#created(org.alfresco.web.bean.repository.Node, org.alfresco.service.namespace.QName)
604     */

605    public void created(Node node, QName type)
606    {
607       // override the checkin resolver if appropriate
608
if (node.containsPropertyResolver("checkIn") == true)
609       {
610          node.addPropertyResolver("checkIn", this.resolverCheckIn);
611       }
612       
613       // add the forums specific action resolver
614
node.addPropertyResolver("beingDiscussed", this.resolverBeingDiscussed);
615       
616       // override the small icon resolver if it's a forum model type
617
if (type.equals(ForumModel.TYPE_FORUMS) ||
618           type.equals(ForumModel.TYPE_FORUM) ||
619           type.equals(ForumModel.TYPE_TOPIC))
620       {
621          // override icon handling for forum objects - as we have a specific small icon set
622
node.addPropertyResolver("smallIcon", resolverSmallIcon);
623       }
624    }
625    
626    
627    // ------------------------------------------------------------------------------
628
// Navigation action event handlers
629

630    /**
631     * Change the current forums view mode based on user selection
632     *
633     * @param event ActionEvent
634     */

635    public void forumsViewModeChanged(ActionEvent event)
636    {
637       UIModeList viewList = (UIModeList)event.getComponent();
638       
639       // get the view mode ID
640
String JavaDoc viewMode = viewList.getValue().toString();
641       
642       // push the view mode into the lists
643
setForumsViewMode(viewMode);
644       
645       // get the default for the forum page
646
this.forumsPageSize = this.viewsConfig.getDefaultPageSize(PAGE_NAME_FORUMS,
647             this.forumsViewMode);
648       
649       if (logger.isDebugEnabled())
650          logger.debug("Set default forums page size to: " + this.forumsPageSize);
651    }
652    
653    /**
654     * Change the current forum view mode based on user selection
655     *
656     * @param event ActionEvent
657     */

658    public void forumViewModeChanged(ActionEvent event)
659    {
660       UIModeList viewList = (UIModeList)event.getComponent();
661       
662       // get the view mode ID
663
String JavaDoc viewMode = viewList.getValue().toString();
664       
665       // push the view mode into the lists
666
setForumViewMode(viewMode);
667       
668       // get the default for the forum page
669
this.forumPageSize = this.viewsConfig.getDefaultPageSize(PAGE_NAME_FORUM,
670             this.forumViewMode);
671       
672       if (logger.isDebugEnabled())
673          logger.debug("Set default forum page size to: " + this.forumPageSize);
674    }
675    
676    /**
677     * Change the current topic view mode based on user selection
678     *
679     * @param event ActionEvent
680     */

681    public void topicViewModeChanged(ActionEvent event)
682    {
683       UIModeList viewList = (UIModeList)event.getComponent();
684       
685       // get the view mode ID
686
String JavaDoc viewMode = viewList.getValue().toString();
687       
688       // push the view mode into the lists
689
setTopicViewMode(viewMode);
690       
691       // change the default page size if necessary
692
this.topicPageSize = this.viewsConfig.getDefaultPageSize(PAGE_NAME_TOPIC,
693             this.topicViewMode);
694       
695       if (logger.isDebugEnabled())
696          logger.debug("Set default topic page size to: " + this.topicPageSize);
697    }
698
699    /**
700     * Event handler called when a user wants to view or participate
701     * in a discussion on an object
702     *
703     * @param event ActionEvent
704     */

705    public void discuss(ActionEvent event)
706    {
707       UIActionLink link = (UIActionLink)event.getComponent();
708       Map JavaDoc<String JavaDoc, String JavaDoc> params = link.getParameterMap();
709       String JavaDoc id = params.get("id");
710       if (id == null || id.length() == 0)
711       {
712          throw new AlfrescoRuntimeException("discuss called without an id");
713       }
714       
715       FacesContext context = FacesContext.getCurrentInstance();
716       
717       NodeRef nodeRef = new NodeRef(Repository.getStoreRef(), id);
718          
719       if (this.nodeService.hasAspect(nodeRef, ForumModel.ASPECT_DISCUSSABLE) == false)
720       {
721          throw new AlfrescoRuntimeException("discuss called for an object that does not have a discussion!");
722       }
723       
724       // as the node has the discussable aspect there must be a discussions child assoc
725
List JavaDoc<ChildAssociationRef> children = this.nodeService.getChildAssocs(nodeRef,
726             ForumModel.ASSOC_DISCUSSION, RegexQNamePattern.MATCH_ALL);
727       
728       // there should only be one child, retrieve it if there is
729
if (children.size() != 1)
730       {
731          throw new IllegalStateException JavaDoc("Node has the discussable aspect but does not have 1 child, it has " +
732                                          children.size() + " children!");
733       }
734       
735       // show the forum for the discussion
736
NodeRef forumNodeRef = children.get(0).getChildRef();
737       this.browseBean.clickSpace(forumNodeRef);
738       context.getApplication().getNavigationHandler().handleNavigation(context, null, "showForum");
739    }
740       
741    /**
742     * Called when the user confirms they wish to delete a forum space
743     *
744     * @return The outcome
745     */

746    public String JavaDoc deleteForumsOK()
747    {
748       String JavaDoc outcomeOverride = "browse";
749       
750       // find out what the parent type of the node being deleted
751
Node node = this.browseBean.getActionSpace();
752       ChildAssociationRef assoc = this.nodeService.getPrimaryParent(node.getNodeRef());
753       if (assoc != null)
754       {
755          NodeRef parent = assoc.getParentRef();
756          QName parentType = this.nodeService.getType(parent);
757          if (parentType.equals(ForumModel.TYPE_FORUMS))
758          {
759             outcomeOverride = "forumsDeleted";
760          }
761       }
762       
763       // call the generic handler
764
String JavaDoc outcome = this.browseBean.deleteSpaceOK();
765       
766       // if the delete was successful update the outcome
767
if (outcome != null)
768       {
769          // return an overidden outcome which closes the dialog with an outcome
770
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME +
771                    AlfrescoNavigationHandler.DIALOG_SEPARATOR + outcomeOverride;
772       }
773
774       return outcome;
775    }
776    
777    /**
778     * Called when the user confirms they wish to delete a forum space
779     *
780     * @return The outcome
781     */

782    public String JavaDoc deleteForumOK()
783    {
784       String JavaDoc outcomeOverride = "browse";
785       
786       // if this forum is being used for a discussion on a node we also
787
// need to remove the discussable aspect from the node.
788
Node forumSpace = this.browseBean.getActionSpace();
789       ChildAssociationRef assoc = this.nodeService.getPrimaryParent(forumSpace.getNodeRef());
790       if (assoc != null)
791       {
792          // get the parent node
793
NodeRef parent = assoc.getParentRef();
794          
795          // get the association type
796
QName type = assoc.getTypeQName();
797          if (type.equals(ForumModel.ASSOC_DISCUSSION))
798          {
799             // if the association type is the 'discussion' association we
800
// need to remove the discussable aspect from the parent node
801
this.nodeService.removeAspect(parent, ForumModel.ASPECT_DISCUSSABLE);
802          }
803          
804          // if the parent type is a forum space then we need the dialog to go
805
// back to the forums view otherwise it will use the default of 'browse',
806
// this happens when a forum being used to discuss a node is deleted.
807
QName parentType = this.nodeService.getType(parent);
808          if (parentType.equals(ForumModel.TYPE_FORUMS))
809          {
810             outcomeOverride = "forumDeleted";
811          }
812       }
813       
814       // call the generic handler
815
String JavaDoc outcome = this.browseBean.deleteSpaceOK();
816       
817       // if the delete was successful update the outcome
818
if (outcome != null)
819       {
820          // return an overidden outcome which closes the dialog with an outcome
821
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME +
822                    AlfrescoNavigationHandler.DIALOG_SEPARATOR + outcomeOverride;
823       }
824       
825       return outcome;
826    }
827    
828    /**
829     * Called when the user confirms they wish to delete a forum space
830     *
831     * @return The outcome
832     */

833    public String JavaDoc deleteTopicOK()
834    {
835       String JavaDoc outcomeOverride = "browse";
836       
837       // find out what the parent type of the node being deleted
838
Node node = this.browseBean.getActionSpace();
839       ChildAssociationRef assoc = this.nodeService.getPrimaryParent(node.getNodeRef());
840       if (assoc != null)
841       {
842          NodeRef parent = assoc.getParentRef();
843          QName parentType = this.nodeService.getType(parent);
844          if (parentType.equals(ForumModel.TYPE_FORUM))
845          {
846             outcomeOverride = "topicDeleted";
847          }
848       }
849       
850       // call the generic handler
851
String JavaDoc outcome = this.browseBean.deleteSpaceOK();
852       
853       // if the delete was successful update the outcome
854
if (outcome != null)
855       {
856          outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME +
857                    AlfrescoNavigationHandler.DIALOG_SEPARATOR + outcomeOverride;
858       }
859       
860       return outcome;
861    }
862    
863    /**
864     * Called when the user confirms they wish to delete a forum space
865     *
866     * @return The outcome
867     */

868    public String JavaDoc deletePostOK()
869    {
870       // call the generic handler
871
String JavaDoc outcome = this.browseBean.deleteFileOK();
872       
873       // if the delete was successful update the outcome
874
if (outcome != null)
875       {
876          outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME;
877       }
878       
879       return outcome;
880    }
881    
882    
883    // ------------------------------------------------------------------------------
884
// Property Resolvers
885

886    public NodePropertyResolver resolverCheckIn = new NodePropertyResolver() {
887       public Object JavaDoc get(Node node)
888       {
889          boolean canCheckin = false;
890          
891          // if the working copy has a discussion the user will also need to have
892
// contributor permission on the locked node
893
if (node.hasAspect(ContentModel.ASPECT_WORKING_COPY))
894          {
895             if (node.hasAspect(ForumModel.ASPECT_DISCUSSABLE))
896             {
897                // get the original locked node (via the copiedfrom aspect)
898
NodeRef lockedNodeRef = (NodeRef)nodeService.getProperty(node.getNodeRef(), ContentModel.PROP_COPY_REFERENCE);
899                if (lockedNodeRef != null)
900                {
901                   Node lockedNode = new Node(lockedNodeRef);
902                   canCheckin = node.hasPermission(PermissionService.CHECK_IN) &&
903                                lockedNode.hasPermission(PermissionService.CONTRIBUTOR);
904                }
905             }
906             else
907             {
908                // there is no discussion so just check they have checkin permission
909
// for the node
910
canCheckin = node.hasPermission(PermissionService.CHECK_IN);
911             }
912          }
913          
914          return canCheckin;
915       }
916    };
917    
918    public NodePropertyResolver resolverSmallIcon = new NodePropertyResolver() {
919       public Object JavaDoc get(Node node) {
920          QNameNodeMap props = (QNameNodeMap)node.getProperties();
921          String JavaDoc icon = (String JavaDoc)props.getRaw("app:icon");
922          
923          if (icon != null)
924          {
925             icon = StringUtils.replace(icon, "_large", "");
926          }
927          else
928          {
929             icon = BrowseBean.SPACE_SMALL_DEFAULT;
930          }
931          
932          return icon;
933       }
934    };
935    
936    public NodePropertyResolver resolverBeingDiscussed = new NodePropertyResolver() {
937       public Object JavaDoc get(Node node) {
938          return node.hasAspect(ForumModel.ASPECT_DISCUSSABLE);
939       }
940    };
941    
942    public NodePropertyResolver resolverReplies = new NodePropertyResolver() {
943       public Object JavaDoc get(Node node)
944       {
945          // query for the number of posts within the given node
946
String JavaDoc repliesXPath = "./*[(subtypeOf('" + ForumModel.TYPE_POST + "'))]";
947          List JavaDoc<NodeRef> replies = searchService.selectNodes(
948                 node.getNodeRef(),
949                 repliesXPath,
950                 new QueryParameterDefinition[] {},
951                 namespaceService,
952                 false);
953          
954          // reduce the count by 1 as one of the posts will be the initial post
955
int noReplies = replies.size() - 1;
956          
957          if (noReplies < 0)
958          {
959             noReplies = 0;
960          }
961          
962          return new Integer JavaDoc(noReplies);
963       }
964    };
965    
966    public NodePropertyResolver resolverContent = new NodePropertyResolver() {
967       public Object JavaDoc get(Node node)
968       {
969          String JavaDoc content = null;
970          
971          // get the content property from the node and retrieve the
972
// full content as a string (obviously should only be used
973
// for small amounts of content)
974

975          ContentReader reader = contentService.getReader(node.getNodeRef(),
976                ContentModel.PROP_CONTENT);
977          
978          if (reader != null)
979          {
980             content = reader.getContentString();
981          }
982          
983          return content;
984       }
985    };
986    
987    public NodePropertyResolver resolverReplyTo = new NodePropertyResolver() {
988       public Object JavaDoc get(Node node)
989       {
990          // determine if this node is a reply to another post, if so find
991
// the creator of the original poster
992

993          String JavaDoc replyTo = null;
994          
995          List JavaDoc<AssociationRef> assocs = nodeService.getTargetAssocs(node.getNodeRef(),
996                ContentModel.ASSOC_REFERENCES);
997          
998          // there should only be one association, if there is more than one
999
// just get the first one
1000
if (assocs.size() > 0)
1001         {
1002            AssociationRef assoc = assocs.get(0);
1003            NodeRef target = assoc.getTargetRef();
1004            Node targetNode = new Node(target);
1005            replyTo = (String JavaDoc)targetNode.getProperties().get("creator");
1006         }
1007         
1008         return replyTo;
1009      }
1010   };
1011   
1012   /**
1013    * Creates a file name for the message being posted
1014    *
1015    * @return The file name for the post
1016    */

1017   public static String JavaDoc createPostFileName()
1018   {
1019      StringBuilder JavaDoc name = new StringBuilder JavaDoc("posted-");
1020      
1021      // add a timestamp
1022
SimpleDateFormat JavaDoc dateFormat = new SimpleDateFormat JavaDoc("dd-MM-yyyy-hh:mm:ss");
1023      name.append(dateFormat.format(new Date JavaDoc()));
1024      
1025      // add the HTML file extension
1026
name.append(".html");
1027      
1028      return name.toString();
1029   }
1030   
1031   
1032   // ------------------------------------------------------------------------------
1033
// Private helpers
1034

1035   /**
1036    * Initialise default values from client configuration
1037    */

1038   private void initFromClientConfig()
1039   {
1040      this.viewsConfig = (ViewsConfigElement)Application.getConfigService(
1041            FacesContext.getCurrentInstance()).getConfig("Views").
1042            getConfigElement(ViewsConfigElement.CONFIG_ELEMENT_ID);
1043      
1044      // get the defaults for the forums page
1045
this.forumsViewMode = this.viewsConfig.getDefaultView(PAGE_NAME_FORUMS);
1046      this.forumsPageSize = this.viewsConfig.getDefaultPageSize(PAGE_NAME_FORUMS,
1047            this.forumsViewMode);
1048      
1049      // get the default for the forum page
1050
this.forumViewMode = this.viewsConfig.getDefaultView(PAGE_NAME_FORUM);
1051      this.forumPageSize = this.viewsConfig.getDefaultPageSize(PAGE_NAME_FORUM,
1052            this.forumViewMode);
1053      
1054      // get the default for the topic page
1055
this.topicViewMode = this.viewsConfig.getDefaultView(PAGE_NAME_TOPIC);
1056      this.topicPageSize = this.viewsConfig.getDefaultPageSize(PAGE_NAME_TOPIC,
1057            this.topicViewMode);
1058      
1059      if (logger.isDebugEnabled())
1060      {
1061         logger.debug("Set default forums view mode to: " + this.forumsViewMode);
1062         logger.debug("Set default forums page size to: " + this.forumsPageSize);
1063         logger.debug("Set default forum view mode to: " + this.forumViewMode);
1064         logger.debug("Set default forum page size to: " + this.forumPageSize);
1065         logger.debug("Set default topic view mode to: " + this.topicViewMode);
1066         logger.debug("Set default topic page size to: " + this.topicPageSize);
1067      }
1068   }
1069   
1070   /**
1071    * Class to implement a bubble view for the RichList component used in the topics screen
1072    *
1073    * @author gavinc
1074    */

1075   public static class TopicBubbleViewRenderer implements IRichListRenderer
1076   {
1077      public static final String JavaDoc VIEWMODEID = "bubble";
1078      
1079      /**
1080       * @see org.alfresco.web.ui.common.renderer.data.IRichListRenderer#getViewModeID()
1081       */

1082      public String JavaDoc getViewModeID()
1083      {
1084         return VIEWMODEID;
1085      }
1086      
1087      /**
1088       * @see org.alfresco.web.ui.common.renderer.data.IRichListRenderer#renderListBefore(javax.faces.context.FacesContext, org.alfresco.web.ui.common.component.data.UIColumn[])
1089       */

1090      public void renderListBefore(FacesContext context, UIRichList richList, UIColumn[] columns)
1091            throws IOException JavaDoc
1092      {
1093         // nothing to do
1094
}
1095      
1096      /**
1097       * @see org.alfresco.web.ui.common.renderer.data.IRichListRenderer#renderListRow(javax.faces.context.FacesContext, org.alfresco.web.ui.common.component.data.UIColumn[], java.lang.Object)
1098       */

1099      public void renderListRow(FacesContext context, UIRichList richList, UIColumn[] columns, Object JavaDoc row)
1100            throws IOException JavaDoc
1101      {
1102         ResponseWriter out = context.getResponseWriter();
1103         
1104         // find primary column (which must exist) and the actions column (which doesn't
1105
// have to exist)
1106
UIColumn primaryColumn = null;
1107         UIColumn actionsColumn = null;
1108         for (int i = 0; i < columns.length; i++)
1109         {
1110            if (columns[i].isRendered())
1111            {
1112               if (columns[i].getPrimary())
1113               {
1114                  primaryColumn = columns[i];
1115               }
1116               else if (columns[i].getActions())
1117               {
1118                  actionsColumn = columns[i];
1119               }
1120            }
1121         }
1122         
1123         if (primaryColumn == null)
1124         {
1125            if (logger.isWarnEnabled())
1126               logger.warn("No primary column found for RichList definition: " + richList.getId());
1127         }
1128         
1129         out.write("<tr>");
1130         
1131         Node node = (Node)row;
1132         if (node.getProperties().get("replyTo") == null)
1133         {
1134            renderNewPostBubble(context, out, node, primaryColumn, actionsColumn, columns);
1135         }
1136         else
1137         {
1138            renderReplyToBubble(context, out, node, primaryColumn, actionsColumn, columns);
1139         }
1140         
1141         out.write("</tr>");
1142         
1143         // add a little padding
1144
out.write("<tr><td><div style='padding:3px'></div></td></tr>");
1145      }
1146      
1147      /**
1148       * @see org.alfresco.web.ui.common.renderer.data.IRichListRenderer#renderListAfter(javax.faces.context.FacesContext, org.alfresco.web.ui.common.component.data.UIColumn[])
1149       */

1150      public void renderListAfter(FacesContext context, UIRichList richList, UIColumn[] columns)
1151            throws IOException JavaDoc
1152      {
1153         ResponseWriter out = context.getResponseWriter();
1154         
1155         out.write("<tr><td colspan='99' align='right'>");
1156         for (Iterator JavaDoc i = richList.getChildren().iterator(); i.hasNext(); /**/)
1157         {
1158            // output all remaining child components that are not UIColumn
1159
UIComponent child = (UIComponent)i.next();
1160            if (child instanceof UIColumn == false)
1161            {
1162               Utils.encodeRecursive(context, child);
1163            }
1164         }
1165         out.write("</td></tr>");
1166      }
1167      
1168      /**
1169       * Renders the top part of the bubble i.e. before the header
1170       *
1171       * @param out The writer to output to
1172       * @param contextPath Context path of the application
1173       * @param colour The colour of the bubble
1174       * @param titleBgColour Background colour of the header area
1175       */

1176      public static void renderBubbleTop(Writer JavaDoc out, String JavaDoc contextPath,
1177            String JavaDoc colour, String JavaDoc titleBgColour) throws IOException JavaDoc
1178      {
1179         out.write("<table border='0' cellpadding='0' cellspacing='0' width='100%'><tr>");
1180         out.write("<td style='background: url(");
1181         out.write(contextPath);
1182         out.write("/images/parts/");
1183         out.write(colour);
1184         out.write("header_1.gif) no-repeat #FFFFFF;' width='24' height='24'></td>");
1185         out.write("<td style='background: url(");
1186         out.write(contextPath);
1187         out.write("/images/parts/");
1188         out.write(colour);
1189         out.write("header_2.gif) repeat-x ");
1190         out.write(titleBgColour);
1191         out.write("'>");
1192      }
1193      
1194      /**
1195       * Renders the middle part of the bubble i.e. after the header and before the body
1196       *
1197       * @param out The writer to output to
1198       * @param contextPath Context path of the application
1199       * @param colour The colour of the bubble
1200       */

1201      public static void renderBubbleMiddle(Writer JavaDoc out, String JavaDoc contextPath, String JavaDoc colour)
1202            throws IOException JavaDoc
1203      {
1204         out.write("</td>");
1205         out.write("<td style='background: url(");
1206         out.write(contextPath);
1207         out.write("/images/parts/");
1208         out.write(colour);
1209         out.write("header_3.gif) no-repeat #FFFFFF;' width='24' height='24'></td>");
1210         out.write("</tr><tr>");
1211         out.write("<td width='24' height='13'><img width='24' height='13' alt='' SRC='");
1212         out.write(contextPath);
1213         out.write("/images/parts/");
1214         out.write(colour);
1215         out.write("body_1.gif' /></td>");
1216         out.write("<td background='");
1217         out.write(contextPath);
1218         out.write("/images/parts/");
1219         out.write(colour);
1220         out.write("body_2.gif'><img width='21' height='13' alt='' SRC='");
1221         out.write(contextPath);
1222         out.write("/images/parts/");
1223         out.write(colour);
1224         out.write("body_2.gif' /></td>");
1225         out.write("<td width='24' height='13'><img width='24' height='13' alt='' SRC='");
1226         out.write(contextPath);
1227         out.write("/images/parts/");
1228         out.write(colour);
1229         out.write("body_3.gif' /></td>");
1230         out.write("</tr><tr>");
1231         out.write("<td width='24' height='13' background='");
1232         out.write(contextPath);
1233         out.write("/images/parts/");
1234         out.write(colour);
1235         out.write("body_4.gif'><img width='24' height='4' alt='' SRC='");
1236         out.write(contextPath);
1237         out.write("/images/parts/");
1238         out.write(colour);
1239         out.write("body_4.gif' /></td>");
1240         out.write("<td>");
1241      }
1242      
1243      /**
1244       * Renders the bottom part of the bubble i.e. after the body
1245       *
1246       * @param out The writer to output to
1247       * @param contextPath Context path of the application
1248       * @param colour The colour of the bubble
1249       */

1250      public static void renderBubbleBottom(Writer JavaDoc out, String JavaDoc contextPath, String JavaDoc colour)
1251            throws IOException JavaDoc
1252      {
1253         out.write("</td>");
1254         out.write("<td width='24' height='13' background='");
1255         out.write(contextPath);
1256         out.write("/images/parts/");
1257         out.write(colour);
1258         out.write("body_6.gif'><img width='24' height='3' alt='' SRC='");
1259         out.write(contextPath);
1260         out.write("/images/parts/");
1261         out.write(colour);
1262         out.write("body_6.gif' /></td>");
1263         out.write("</tr><tr>");
1264         out.write("<td width='24' height='13'><img width='24' height='13' alt='' SRC='");
1265         out.write(contextPath);
1266         out.write("/images/parts/");
1267         out.write(colour);
1268         out.write("body_7.gif' /></td>");
1269         out.write("<td background='");
1270         out.write(contextPath);
1271         out.write("/images/parts/");
1272         out.write(colour);
1273         out.write("body_8.gif'><img width='20' height='13' alt='' SRC='");
1274         out.write(contextPath);
1275         out.write("/images/parts/");
1276         out.write(colour);
1277         out.write("body_8.gif' /></td>");
1278         out.write("<td width='24' height='13'><img width='24' height='13' alt='' SRC='");
1279         out.write(contextPath);
1280         out.write("/images/parts/");
1281         out.write(colour);
1282         out.write("body_9.gif' /></td>");
1283         out.write("</tr></table>");
1284      }
1285      
1286      /**
1287       * Renders the new post speech bubble
1288       *
1289       * @param context Faces context
1290       * @param out The response writer
1291       * @param node The Node for the row being rendered
1292       * @param primaryColumn The primary column containing the message content
1293       * @param actionsColumn The actions column containing all the actions
1294       * @param columns All configured columns
1295       */

1296      private void renderNewPostBubble(FacesContext context, ResponseWriter out, Node node,
1297            UIColumn primaryColumn, UIColumn actionsColumn, UIColumn[] columns) throws IOException JavaDoc
1298      {
1299         String JavaDoc contextPath = context.getExternalContext().getRequestContextPath();
1300         String JavaDoc colour = "orange";
1301         
1302         out.write("<td><table border='0' cellpadding='0' cellspacing='0' width='100%'><tr>");
1303         out.write("<td valign='top'><img SRC='");
1304         out.write(contextPath);
1305         out.write("/images/icons/user_large.gif'/><br/>");
1306         out.write((String JavaDoc)node.getProperties().get("creator"));
1307         out.write("</td><td width='100%'>");
1308         
1309         renderBubbleTop(out, contextPath, colour, "#FCC75E");
1310         renderHeaderContents(context, out, primaryColumn, actionsColumn, columns);
1311         renderBubbleMiddle(out, contextPath, colour);
1312         renderBodyContents(context, primaryColumn);
1313         renderBubbleBottom(out, contextPath, colour);
1314         
1315         out.write("</td><td><div style='width:32px;' /></td></table></td>");
1316      }
1317      
1318      /**
1319       * Renders the reply to post speech bubble
1320       *
1321       * @param context Faces context
1322       * @param out The response writer
1323       * @param node The Node for the row being rendered
1324       * @param primaryColumn The primary column containing the message content
1325       * @param actionsColumn The actions column containing all the actions
1326       * @param columns All configured columns
1327       */

1328      private void renderReplyToBubble(FacesContext context, ResponseWriter out, Node node,
1329            UIColumn primaryColumn, UIColumn actionsColumn, UIColumn[] columns) throws IOException JavaDoc
1330      {
1331         String JavaDoc contextPath = context.getExternalContext().getRequestContextPath();
1332         String JavaDoc colour = "yellow";
1333         
1334         out.write("<td width='100%'><table border='0' cellpadding='0' cellspacing='0' width='100%'><tr>");
1335         out.write("<td><div style='width:32px;' /></td><td width='100%'>");
1336         
1337         renderBubbleTop(out, contextPath, colour, "#FFF5A3");
1338         renderHeaderContents(context, out, primaryColumn, actionsColumn, columns);
1339         renderBubbleMiddle(out, contextPath, colour);
1340         renderBodyContents(context, primaryColumn);
1341         renderBubbleBottom(out, contextPath, colour);
1342         
1343         out.write("</td><td valign='top'><img SRC='");
1344         out.write(contextPath);
1345         out.write("/images/icons/user_large.gif'/><br/>");
1346         out.write((String JavaDoc)node.getProperties().get("creator"));
1347         out.write("</td></table></td>");
1348      }
1349
1350      private void renderHeaderContents(FacesContext context, ResponseWriter out,
1351            UIColumn primaryColumn, UIColumn actionsColumn, UIColumn[] columns) throws IOException JavaDoc
1352      {
1353         // render the header area with the configured columns
1354
out.write("<table width='100%' cellpadding='2' cellspacing='2' border='0'><tr>");
1355         
1356         for (int i = 0; i < columns.length; i++)
1357         {
1358            UIColumn column = columns[i];
1359            
1360            if (column.isRendered() == true &&
1361                column.getPrimary() == false &&
1362                column.getActions() == false)
1363            {
1364               // render the column header as the label
1365
UIComponent header = column.getFacet("header");
1366               if (header != null)
1367               {
1368                  out.write("<td><nobr><b>");
1369                  Utils.encodeRecursive(context, header);
1370                  out.write("</nobr></b></td>");
1371               }
1372               
1373               // render the contents of the column
1374
if (column.getChildCount() != 0)
1375               {
1376                  out.write("<td><nobr>");
1377                  Utils.encodeRecursive(context, column);
1378                  out.write("</nobr></td>");
1379               }
1380            }
1381         }
1382         
1383         // render the actions column
1384
out.write("<td align='right' width='100%'><nobr>");
1385         if (actionsColumn != null && actionsColumn.getChildCount() != 0)
1386         {
1387            Utils.encodeRecursive(context, actionsColumn);
1388         }
1389         out.write("</nobr></td></tr></table>");
1390      }
1391      
1392      /**
1393       * Renders the body contents for the bubble using the given primary coumn
1394       *
1395       * @param context Faces context
1396       * @param primaryColumn The primary column holding the message text
1397       */

1398      private void renderBodyContents(FacesContext context, UIColumn primaryColumn)
1399            throws IOException JavaDoc
1400      {
1401         // render the primary column
1402
if (primaryColumn != null && primaryColumn.getChildCount() != 0)
1403         {
1404            Utils.encodeRecursive(context, primaryColumn);
1405         }
1406      }
1407   }
1408}
1409
Popular Tags