001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/site-manage/tags/sakai_2-4-1/site-manage-tool/tool/src/java/org/sakaiproject/site/tool/SiteBrowserAction.java $
003: * $Id: SiteBrowserAction.java 22876 2007-03-19 02:33:45Z daisyf@stanford.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.site.tool;
021:
022: import java.lang.reflect.Method;
023: import java.util.ArrayList;
024: import java.util.HashMap;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.Vector;
029:
030: import org.sakaiproject.announcement.cover.AnnouncementService;
031: import org.sakaiproject.cheftool.Context;
032: import org.sakaiproject.cheftool.JetspeedRunData;
033: import org.sakaiproject.cheftool.PagedResourceActionII;
034: import org.sakaiproject.cheftool.RunData;
035: import org.sakaiproject.cheftool.VelocityPortlet;
036: import org.sakaiproject.cheftool.api.Menu;
037: import org.sakaiproject.cheftool.menu.MenuImpl;
038: import org.sakaiproject.component.cover.ComponentManager;
039: import org.sakaiproject.component.cover.ServerConfigurationService;
040: import org.sakaiproject.content.cover.ContentHostingService;
041: import org.sakaiproject.content.cover.ContentTypeImageService;
042: import org.sakaiproject.entity.api.Reference;
043: import org.sakaiproject.entity.cover.EntityManager;
044: import org.sakaiproject.event.api.SessionState;
045: import org.sakaiproject.exception.IdUnusedException;
046: import org.sakaiproject.exception.PermissionException;
047: import org.sakaiproject.javax.PagingPosition;
048: import org.sakaiproject.site.api.Site; //import org.sakaiproject.site.cover.CourseManagementService;
049: import org.sakaiproject.site.cover.SiteService;
050: import org.sakaiproject.util.ResourceLoader;
051: import org.sakaiproject.util.StringUtil;
052:
053: /**
054: * <p>
055: * SiteBrowserAction is the Sakai site browser, showing a searchable list of the defined sites, and details including public resources of each when selected.
056: * </p>
057: */
058: public class SiteBrowserAction extends PagedResourceActionII {
059: private org.sakaiproject.coursemanagement.api.CourseManagementService cms = (org.sakaiproject.coursemanagement.api.CourseManagementService) ComponentManager
060: .get(org.sakaiproject.coursemanagement.api.CourseManagementService.class);
061:
062: private static ResourceLoader rb = new ResourceLoader("sitebrowser");
063:
064: private final static String SITE_TYPE_ANY = "Any";
065:
066: private final static String SITE_TERM_ANY = "Any";
067:
068: private final static String STATE_TERM_SELECTION = "termSelection";
069:
070: private final static String STATE_SEARCH_SITE_TYPE = "siteType";
071:
072: private final static String STATE_SEARCH_LIST = "searchList";
073:
074: private final static String STATE_PROP_SEARCH_MAP = "propertyCriteriaMap";
075:
076: private final static String SIMPLE_SEARCH_VIEW = "simpleSearch";
077:
078: private final static String LIST_VIEW = "list";
079:
080: // for the site with extra search criteria
081: private final static String SEARCH_TERM_SITE_TYPE = "termSearchSiteType";
082:
083: private final static String SEARCH_TERM_PROP = "termProp";
084:
085: private static final String NO_SHOW_SEARCH_TYPE = "noshow_search_sitetype";
086:
087: /** for navigating between sites in site list */
088: private static final String STATE_SITES = "state_sites";
089:
090: private static final String STATE_PREV_SITE = "state_prev_site";
091:
092: private static final String STATE_NEXT_SITE = "state_next_site";
093:
094: /**
095: * {@inheritDoc}
096: */
097: protected List readResourcesPage(SessionState state, int first,
098: int last) {
099: // search?
100: String search = StringUtil.trimToNull((String) state
101: .getAttribute(STATE_SEARCH));
102:
103: return SiteService
104: .getSites(
105: org.sakaiproject.site.api.SiteService.SelectionType.PUBVIEW,
106: state.getAttribute(STATE_SEARCH_SITE_TYPE),
107: search,
108: (HashMap) state
109: .getAttribute(STATE_PROP_SEARCH_MAP),
110: org.sakaiproject.site.api.SiteService.SortType.TITLE_ASC,
111: new PagingPosition(first, last));
112:
113: }
114:
115: /**
116: * {@inheritDoc}
117: */
118: protected int sizeResources(SessionState state) {
119: String search = StringUtil.trimToNull((String) state
120: .getAttribute(STATE_SEARCH));
121:
122: return SiteService
123: .countSites(
124: org.sakaiproject.site.api.SiteService.SelectionType.PUBVIEW,
125: state.getAttribute(STATE_SEARCH_SITE_TYPE),
126: search, (HashMap) state
127: .getAttribute(STATE_PROP_SEARCH_MAP));
128: }
129:
130: /**
131: * Populate the state object, if needed.
132: */
133: protected void initState(SessionState state,
134: VelocityPortlet portlet, JetspeedRunData rundata) {
135: super .initState(state, portlet, rundata);
136:
137: state.setAttribute(STATE_PAGESIZE, new Integer(
138: DEFAULT_PAGE_SIZE));
139:
140: // if site type which requires term search exists
141: // get all term-search related data from configuration,
142: String termSearchSiteType = ServerConfigurationService
143: .getString("sitebrowser.termsearch.type");
144: if (termSearchSiteType != null) {
145: state.setAttribute(SEARCH_TERM_SITE_TYPE,
146: termSearchSiteType);
147:
148: String termSearchProperty = ServerConfigurationService
149: .getString("sitebrowser.termsearch.property");
150: state.setAttribute(SEARCH_TERM_PROP, termSearchProperty);
151: }
152:
153: String noSearchSiteType = StringUtil
154: .trimToNull(ServerConfigurationService
155: .getString("sitesearch.noshow.sitetype"));
156: if (noSearchSiteType != null) {
157: state.setAttribute(NO_SHOW_SEARCH_TYPE, noSearchSiteType);
158: }
159:
160: // setup the observer to notify our main panel
161: /*
162: * if (state.getAttribute(STATE_OBSERVER) == null) { // the delivery location for this tool String deliveryId = clientWindowId(state, portlet.getID()); // the html element to update on delivery String elementId =
163: * mainPanelUpdateId(portlet.getID()); // the event resource reference pattern to watch for String pattern = SiteService.siteReference(""); state.setAttribute(STATE_OBSERVER, new EventObservingCourier(deliveryId, elementId, pattern)); } // make
164: * sure the observer is in sync with state updateObservationOfChannel(state, portlet.getID());
165: */
166: } // initState
167:
168: /**
169: * Setup our observer to be watching for change events for our channel.
170: *
171: * @param peid
172: * The portlet id.
173: */
174: private void updateObservationOfChannel(SessionState state,
175: String peid) {
176: /*
177: * EventObservingCourier observer = (EventObservingCourier) state.getAttribute(STATE_OBSERVER); // the delivery location for this tool String deliveryId = clientWindowId(state, peid); observer.setDeliveryId(deliveryId);
178: */
179: } // updateObservationOfChannel
180:
181: /**
182: * build the context
183: */
184: public String buildMainPanelContext(VelocityPortlet portlet,
185: Context context, RunData rundata, SessionState state) {
186: context.put("tlang", rb);
187: String template = null;
188:
189: // check mode and dispatch
190: String mode = (String) state.getAttribute("mode");
191: if ((mode == null) || mode.equals(SIMPLE_SEARCH_VIEW)) {
192: template = buildSimpleSearchContext(state, context);
193: } else if (mode.equals(LIST_VIEW)) {
194: template = buildListContext(state, context);
195: }
196: // else if (mode.equals(ADV_SEARCH_VIEW))
197: // {
198: // template = buildAdvSearchContext(state, context);
199: // }
200: else if (mode.equals("visit")) {
201: template = buildVisitContext(state, context);
202: } else {
203: Log.warn("chef", "SiteBrowserAction: mode: " + mode);
204: template = buildListContext(state, context);
205: }
206:
207: return (String) getContext(rundata).get("template") + template;
208:
209: } // buildMainPanelContext
210:
211: /**
212: * Build the context for the main list mode.
213: */
214: private String buildListContext(SessionState state, Context context) {
215: // put the service in the context (used for allow update calls on each site)
216: context.put("service", SiteService.getInstance());
217:
218: context.put("termProp", (String) state
219: .getAttribute(SEARCH_TERM_PROP));
220: context.put("searchText", (String) state
221: .getAttribute(STATE_SEARCH));
222: context.put("siteType", (String) state
223: .getAttribute(STATE_SEARCH_SITE_TYPE));
224: context.put("termSelection", (String) state
225: .getAttribute(STATE_TERM_SELECTION));
226:
227: // String newPageSize = state.getAttribute(STATE_PAGESIZE).toString();
228: Integer newPageSize = (Integer) state
229: .getAttribute("inter_size");
230: if (newPageSize != null) {
231: context.put("pagesize", newPageSize);
232: state.setAttribute(STATE_PAGESIZE, newPageSize);
233: } else {
234: state.setAttribute(STATE_PAGESIZE, new Integer(
235: DEFAULT_PAGE_SIZE));
236: context.put("pagesize", new Integer(DEFAULT_PAGE_SIZE));
237: }
238:
239: // prepare the paging of realms
240: List sites = prepPage(state);
241: state.setAttribute(STATE_SITES, sites);
242: context.put("sites", sites);
243:
244: if (state.getAttribute(STATE_NUM_MESSAGES) != null)
245: context.put("allMsgNumber", state.getAttribute(
246: STATE_NUM_MESSAGES).toString());
247:
248: // find the position of the message that is the top first on the page
249: if ((state.getAttribute(STATE_TOP_PAGE_MESSAGE) != null)
250: && (state.getAttribute(STATE_PAGESIZE) != null)) {
251: int topMsgPos = ((Integer) state
252: .getAttribute(STATE_TOP_PAGE_MESSAGE)).intValue() + 1;
253: context.put("topMsgPos", Integer.toString(topMsgPos));
254: int btmMsgPos = topMsgPos
255: + ((Integer) state.getAttribute(STATE_PAGESIZE))
256: .intValue() - 1;
257: if (state.getAttribute(STATE_NUM_MESSAGES) != null) {
258: int allMsgNumber = ((Integer) state
259: .getAttribute(STATE_NUM_MESSAGES)).intValue();
260: if (btmMsgPos > allMsgNumber)
261: btmMsgPos = allMsgNumber;
262: }
263: context.put("btmMsgPos", Integer.toString(btmMsgPos));
264: }
265:
266: // build the menu
267: Menu bar = new MenuImpl();
268:
269: // add the search commands
270: // bar.add( new MenuField(FORM_SEARCH, "toolbar", "doSearch", (String) state.getAttribute(STATE_SEARCH)));
271: // bar.add( new MenuEntry("Search", null, true, MenuItem.CHECKED_NA, "doSearch", "toolbar"));
272:
273: // add the refresh commands
274: // %%% we want manual only
275: addRefreshMenus(bar, state);
276:
277: if (bar.size() > 0) {
278: context.put(Menu.CONTEXT_MENU, bar);
279: }
280:
281: boolean goPPButton = state.getAttribute(STATE_PREV_PAGE_EXISTS) != null;
282: context.put("goPPButton", Boolean.toString(goPPButton));
283: boolean goNPButton = state.getAttribute(STATE_NEXT_PAGE_EXISTS) != null;
284: context.put("goNPButton", Boolean.toString(goNPButton));
285:
286: // }
287: // inform the observing courier that we just updated the page...
288: // if there are pending requests to do so they can be cleared
289: // justDelivered(state);
290:
291: return "_list";
292:
293: } // buildListContext
294:
295: /**
296: * Build the context for the simple search mode.
297: */
298: private String buildSimpleSearchContext(SessionState state,
299: Context context) {
300:
301: List newTypes = new Vector();
302: if (state.getAttribute(NO_SHOW_SEARCH_TYPE) != null) {
303: String noType = state.getAttribute(NO_SHOW_SEARCH_TYPE)
304: .toString();
305: List oldTypes = SiteService.getSiteTypes();
306: for (int i = 0; i < oldTypes.size(); i++) {
307: String siteType = oldTypes.get(i).toString();
308: if ((siteType.indexOf(noType)) == -1) {
309: newTypes.add(siteType);
310: }
311: }
312: } else {
313: newTypes = SiteService.getSiteTypes();
314: }
315:
316: // remove the "myworkspace" type
317: for (Iterator i = newTypes.iterator(); i.hasNext();) {
318: String t = (String) i.next();
319: if ("myworkspace".equalsIgnoreCase(t)) {
320: i.remove();
321: }
322: }
323:
324: context.put("siteTypes", newTypes);
325:
326: //List terms = CourseManagementService.getTerms();
327: List terms = cms.getAcademicSessions();
328:
329: String termSearchSiteType = (String) state
330: .getAttribute(SEARCH_TERM_SITE_TYPE);
331: if (termSearchSiteType != null) {
332: context.put("termSearchSiteType", termSearchSiteType);
333: context.put("terms", terms);
334: }
335:
336: return "_simpleSearch";
337:
338: } // buildSimpleSearchContext
339:
340: /**
341: * Build the context for the visit site mode.
342: */
343: private String buildVisitContext(SessionState state, Context context) {
344: List sites = (List) state.getAttribute(STATE_SITES);
345: String siteId = (String) state.getAttribute("siteId");
346:
347: try {
348: Site site = SiteService.getSite(siteId);
349:
350: if (sites != null) {
351: int pos = -1;
352: for (int index = 0; index < sites.size() && pos == -1; index++) {
353: if (((Site) sites.get(index)).getId()
354: .equals(siteId)) {
355: pos = index;
356: }
357: }
358:
359: // has any previous site in the list?
360: if (pos > 0) {
361: state.setAttribute(STATE_PREV_SITE, sites
362: .get(pos - 1));
363: } else {
364: state.removeAttribute(STATE_PREV_SITE);
365: }
366:
367: // has any next site in the list?
368: if (pos < sites.size() - 1) {
369: state.setAttribute(STATE_NEXT_SITE, sites
370: .get(pos + 1));
371: } else {
372: state.removeAttribute(STATE_NEXT_SITE);
373: }
374: }
375:
376: if (state.getAttribute(STATE_PREV_SITE) != null) {
377: context.put("prevSite", state
378: .getAttribute(STATE_PREV_SITE));
379: }
380: if (state.getAttribute(STATE_NEXT_SITE) != null) {
381: context.put("nextSite", state
382: .getAttribute(STATE_NEXT_SITE));
383: }
384:
385: context.put("site", site);
386:
387: // get the public announcements
388: String anncRef = AnnouncementService.channelReference(site
389: .getId(), SiteService.MAIN_CONTAINER);
390: List announcements = null;
391: try {
392: announcements = AnnouncementService.getMessages(
393: anncRef, null, 0, true, false, true);
394: } catch (PermissionException e) {
395: announcements = new Vector();
396: }
397:
398: context.put("announcements", announcements);
399:
400: // get the public syllabus
401: try {
402: Object syllabusService = ComponentManager
403: .get("org.sakaiproject.api.app.syllabus.SyllabusService");
404: Class syllabusServiceClass = syllabusService.getClass();
405: Class[] paramsClasses = new Class[1];
406: paramsClasses[0] = java.lang.String.class;
407: Method getMessages = syllabusServiceClass.getMethod(
408: "getMessages", paramsClasses);
409: String paramSiteId = site.getId();
410: List syllabusList = (ArrayList) getMessages.invoke(
411: syllabusService, new Object[] { paramSiteId });
412: context.put("syllabus", syllabusList);
413: } catch (Exception reflectionEx) {
414: Log.error(
415: "Reflection exceptions in SiteBrowserAction for getting public syllabus"
416: + reflectionEx, "");
417: reflectionEx.printStackTrace();
418: }
419:
420: // get the public resources
421: List resources = ContentHostingService
422: .getAllResources(ContentHostingService
423: .getSiteCollection(site.getId()));
424: context.put("resources", resources);
425:
426: // the height for the info frame
427: context.put("height", "300px");
428:
429: // the url for info
430: String url = site.getInfoUrl();
431: if (url != null) {
432: url = url.trim();
433: url = convertReferenceUrl(url);
434: context.put("infoUrl", url);
435: }
436:
437: context.put("contentTypeImageService",
438: ContentTypeImageService.getInstance());
439: } catch (IdUnusedException err) {
440: }
441:
442: return "_visit";
443:
444: } // buildVisitContext
445:
446: public void doNavigate_to_site(RunData data, Context context) {
447: SessionState state = ((JetspeedRunData) data)
448: .getPortletSessionState(((JetspeedRunData) data)
449: .getJs_peid());
450: String siteId = StringUtil.trimToNull(data.getParameters()
451: .getString("newSiteId"));
452: if (siteId != null) {
453: state.setAttribute("siteId", siteId);
454: } else {
455: doBack(data, context);
456: }
457:
458: } // doNavigate_to_site
459:
460: /**
461: * Handle a request to visit a site.
462: */
463: public void doVisit(RunData data, Context context) {
464: SessionState state = ((JetspeedRunData) data)
465: .getPortletSessionState(((JetspeedRunData) data)
466: .getJs_peid());
467: String id = data.getParameters().getString("id");
468: String position = data.getParameters().getString("pos");
469:
470: // get the site
471: try {
472: Site site = SiteService.getSite(id);
473: state.setAttribute("siteId", id);
474: state.setAttribute("mode", "visit");
475:
476: int pos = (new Integer(position)).intValue() - 1;
477: state.setAttribute(STATE_VIEW_ID, new Integer(pos));
478:
479: // disable auto-updates while in view mode
480: // ((EventObservingCourier) state.getAttribute(STATE_OBSERVER)).disable();
481: } catch (IdUnusedException e) {
482: Log.warn("chef",
483: "SiteBrowserAction.doEdit: site not found: " + id);
484:
485: addAlert(state, rb.getString("site") + " " + id + " "
486: + rb.getString("notfound"));
487: state.removeAttribute("mode");
488:
489: // make sure auto-updates are enabled
490: // enableObserver(state);
491: }
492:
493: } // doVisit
494:
495: /**
496: * Handle a request to return to the list.
497: */
498: public void doBack(RunData data, Context context) {
499: SessionState state = ((JetspeedRunData) data)
500: .getPortletSessionState(((JetspeedRunData) data)
501: .getJs_peid());
502:
503: // state.removeAttribute("mode");
504: state.removeAttribute("siteId");
505:
506: state.setAttribute("mode", LIST_VIEW);
507:
508: } // doBack
509:
510: /**
511: * Handle a request to go to Simple Search Mode.
512: */
513: public void doShow_simple_search(RunData data, Context context) {
514: SessionState state = ((JetspeedRunData) data)
515: .getPortletSessionState(((JetspeedRunData) data)
516: .getJs_peid());
517:
518: state.setAttribute("mode", SIMPLE_SEARCH_VIEW);
519:
520: } // doShow_simple_search
521:
522: /**
523: * Handle a request to go to Advanced Search Mode.
524: */
525: /*
526: * public void doShowadvsearch(RunData data, Context context) { SessionState state = ((JetspeedRunData)data).getPortletSessionState(((JetspeedRunData)data).getJs_peid()); state.setAttribute("mode", ADV_SEARCH_VIEW); } // doShowadvsearch
527: */
528:
529: /**
530: * Handle a request to search.
531: */
532: public void doSearch(RunData data, Context context) {
533: super .doSearch(data, context);
534:
535: SessionState state = ((JetspeedRunData) data)
536: .getPortletSessionState(((JetspeedRunData) data)
537: .getJs_peid());
538:
539: String mode = (String) state.getAttribute("mode");
540: state.setAttribute("searchMode", mode);
541:
542: state.removeAttribute(STATE_PROP_SEARCH_MAP);
543: state.removeAttribute(STATE_TERM_SELECTION);
544:
545: // read the search form field into the state object
546: String siteType = StringUtil.trimToNull(data.getParameters()
547: .getString("siteType"));
548: if (siteType != null) {
549: if (siteType.equalsIgnoreCase("Any"))
550: state.setAttribute(STATE_SEARCH_SITE_TYPE, null);
551: else {
552: state.setAttribute(STATE_SEARCH_SITE_TYPE, siteType);
553:
554: String termSearchSiteType = (String) state
555: .getAttribute(SEARCH_TERM_SITE_TYPE);
556: if (termSearchSiteType != null) {
557: if (siteType.equals(termSearchSiteType)) {
558: // search parameter - term; term.eid from UI
559: String term = StringUtil.trimToNull(data
560: .getParameters()
561: .getString("selectTerm"));
562: if (term != null) {
563: state.setAttribute(STATE_TERM_SELECTION,
564: term);
565:
566: // property criteria map
567: Map pMap = null;
568: if (!SITE_TERM_ANY.equals(term)) {
569: pMap = new HashMap();
570: pMap
571: .put(
572: (String) state
573: .getAttribute(SEARCH_TERM_PROP),
574: term);
575: state.setAttribute(
576: STATE_PROP_SEARCH_MAP, pMap);
577:
578: }
579: }
580:
581: }
582: }
583:
584: }
585: } else {
586: state.setAttribute(STATE_SEARCH_SITE_TYPE, null);
587: }
588:
589: state.setAttribute("mode", LIST_VIEW);
590:
591: state.setAttribute(STATE_PAGESIZE, new Integer(
592: DEFAULT_PAGE_SIZE));
593: state.removeAttribute("inter_size");
594:
595: } // doSearch
596:
597: /**
598: * Return the url unchanged, unless it's a reference, then return the reference url
599: */
600: private String convertReferenceUrl(String url) {
601: // make a reference
602: Reference ref = EntityManager.newReference(url);
603:
604: // if it didn't recognize this, return it unchanged
605: if (!ref.isKnownType())
606: return url;
607:
608: // return the reference's url
609: return ref.getUrl();
610:
611: } // convertReferenceUrl
612:
613: } // SiteBrowserAction
|