001: package org.gridsphere.layout;
002:
003: import org.apache.commons.logging.Log;
004: import org.apache.commons.logging.LogFactory;
005: import org.gridsphere.portlet.impl.SportletProperties;
006: import org.gridsphere.portlet.service.spi.PortletServiceFactory;
007: import org.gridsphere.portletcontainer.GridSphereEvent;
008: import org.gridsphere.portletcontainer.PortletSessionListener;
009: import org.gridsphere.portletcontainer.impl.PortletSessionManager;
010: import org.gridsphere.services.core.customization.SettingsService;
011: import org.gridsphere.services.core.portal.PortalConfigService;
012: import org.gridsphere.services.core.user.User;
013:
014: import javax.portlet.PortletRequest;
015: import javax.portlet.PortletSession;
016: import javax.servlet.ServletContext;
017: import javax.servlet.http.HttpServletRequest;
018: import javax.servlet.http.HttpSession;
019: import java.io.*;
020: import java.net.URL;
021: import java.util.*;
022:
023: /**
024: * @author <a href="mailto:novotny@gridsphere.org">Jason Novotny</a>
025: * @version $Id: PortletPageFactory.java 6407 2008-01-16 15:20:21Z wehrens $
026: */
027: public class PortletPageFactory implements PortletSessionListener {
028:
029: private Log log = LogFactory.getLog(PortletPageFactory.class);
030:
031: public static final String TCK_PAGE = "TCK";
032: //public static final String SETUP_PAGE = "SetupLayout";
033: public static final String ERROR_PAGE = "error";
034: public static final String GUEST_PAGE = "guest";
035:
036: // TODO these need refactoring later on
037: public static final String TEMPLATE_PAGE = "TemplateLayout";
038: public static final String USER_PAGE = "loggedin";
039:
040: private static String USER_LAYOUT_DIR = null;
041:
042: public static final String DEFAULT_THEME = "default";
043:
044: private static PortletPageFactory instance = null;
045: private PortletSessionManager sessionManager = PortletSessionManager
046: .getInstance();
047: private PortalConfigService portalConfigService = null;
048:
049: protected URL LAYOUT_MAPPING_PATH = getClass().getResource(
050: "/org/gridsphere/layout/layout-mapping.xml");
051:
052: // Store user layouts in a hash
053: private static Map<String, PortletPage> userLayouts = new HashMap<String, PortletPage>();
054:
055: // a hash of hashes to contain all the users layouts
056: private static Map<String, Map<String, PortletPage>> layouts = new HashMap<String, Map<String, PortletPage>>();
057:
058: // a hash of loaded master layouts used to make copies
059: private static Map<String, PortletPage> masterLayouts = new HashMap<String, PortletPage>();
060: private static Set<String> editableLayoutIds = new HashSet<String>();
061:
062: private ServletContext context;
063:
064: private PortletPageFactory() {
065:
066: }
067:
068: public void init(ServletContext ctx) {
069:
070: this .context = ctx;
071:
072: SettingsService settingsService = (SettingsService) PortletServiceFactory
073: .createPortletService(SettingsService.class, true);
074:
075: USER_LAYOUT_DIR = settingsService
076: .getRealSettingsPath("layouts/users");
077: String layoutsDirPath = settingsService
078: .getRealSettingsPath("layouts");
079:
080: File layoutsDir = new File(layoutsDirPath);
081: File[] layoutFiles = layoutsDir.listFiles();
082: PortletPage page = null;
083: for (int i = 0; i < layoutFiles.length; i++) {
084: File layoutFile = layoutFiles[i];
085: String layoutFileName = layoutFile.getName();
086: if (layoutFileName.endsWith(".xml")) {
087: String layoutId = layoutFileName.substring(0,
088: layoutFileName.indexOf(".xml"));
089: try {
090: page = PortletLayoutDescriptor.loadPortletPage(
091: layoutFile.getAbsolutePath(),
092: LAYOUT_MAPPING_PATH);
093: page.setLayoutDescriptor(layoutFile
094: .getAbsolutePath());
095: if (page.getEditable())
096: editableLayoutIds.add(layoutId);
097: masterLayouts.put(layoutId, page);
098: } catch (Exception e) {
099: log.error("Unable to load portlet page: "
100: + layoutFileName, e);
101: }
102: }
103: }
104:
105: String newuserLayoutPath = settingsService
106: .getRealSettingsPath("layouts/users/");
107:
108: File userdir = new File(newuserLayoutPath);
109: if (!userdir.exists()) {
110: userdir.mkdir();
111: }
112:
113: // test page creation times
114: /*
115: PortletPage copy = null;
116: PortletPage guest = masterLayouts.get(GUEST_PAGE);
117: long startTime = System.currentTimeMillis();
118: try {
119: for (int i = 0; i < 1000; i++) {
120: copy = (PortletPage) deepCopy2(guest);
121: }
122: long endTime = System.currentTimeMillis();
123: System.err.println("Serialize copy 1000 pages in = " + (endTime - startTime) + " (ms) ");
124: for (int i = 0; i < 1000; i++) {
125: copy = (PortletPage) deepCopy(guest);
126: }
127: startTime = System.currentTimeMillis();
128: System.err.println("Clone copy 1000 pages in = " + (startTime - endTime) + " (ms) ");
129: } catch (Exception e) {
130: e.printStackTrace();
131: }
132: */
133:
134: portalConfigService = (PortalConfigService) PortletServiceFactory
135: .createPortletService(PortalConfigService.class, true);
136: }
137:
138: public static synchronized PortletPageFactory getInstance() {
139: if (instance == null) {
140: instance = new PortletPageFactory();
141: }
142: return instance;
143: }
144:
145: public void login(HttpServletRequest request) {
146:
147: }
148:
149: public void logout(HttpSession session) {
150: log.debug("in logout PortletPageFactory");
151: String sessionId = session.getId();
152:
153: Map usersLayouts = (Map) layouts.get(sessionId);
154: if (usersLayouts != null) {
155: Iterator it = usersLayouts.keySet().iterator();
156: while (it.hasNext()) {
157: String layoutId = (String) it.next();
158: log.debug("Removing " + layoutId + " container for:"
159: + sessionId);
160: it.remove();
161: }
162: layouts.remove(sessionId);
163: }
164: if (userLayouts.containsKey(sessionId)) {
165: log.debug("Removing user container for:" + sessionId);
166: userLayouts.remove(sessionId);
167: }
168:
169: }
170:
171: public Set<String> getEditableLayoutIds() {
172: return editableLayoutIds;
173: }
174:
175: public Set<String> getLayoutIds() {
176: return masterLayouts.keySet();
177: }
178:
179: public PortletTabbedPane getUserTabbedPane(PortletRequest req) {
180:
181: String sessionId = req.getPortletSession(true).getId();
182:
183: String userLayout = USER_LAYOUT_DIR + File.separator
184: + req.getUserPrincipal().getName();
185:
186: if (userLayouts.containsKey(sessionId)) {
187: PortletPage page = (PortletPage) userLayouts.get(USER_PAGE);
188: PortletTabbedPane pane = new PortletTabbedPane();
189: pane.setLayoutDescriptor(userLayout);
190: PortletComponent comp = (PortletComponent) page
191: .getPortletComponent();
192: PortletTabbedPane existPane = (PortletTabbedPane) comp;
193: List<PortletTab> tabs = existPane.getPortletTabs();
194: for (PortletTab tab : tabs) {
195: if (tab.getCanModify()) {
196: pane.addTab(tab);
197: }
198: }
199: return (!pane.getPortletTabs().isEmpty() ? pane : null);
200: }
201:
202: File f = new File(userLayout);
203: PortletTabbedPane pane = null;
204:
205: if (f.exists()) {
206: try {
207: pane = PortletLayoutDescriptor.loadPortletTabs(
208: userLayout, LAYOUT_MAPPING_PATH);
209: pane.setLayoutDescriptor(userLayout);
210: log.debug("Adding user tab to layout");
211: } catch (Exception e) {
212: log.error("Unable to make a clone of the templatePage",
213: e);
214: return null;
215: }
216: } else {
217: return null;
218: }
219:
220: // create tmp page
221: PortletPage tmpPage = new PortletPage();
222: try {
223: //tmpPage.setLayoutDescriptor(userLayout + ".tmp");
224: PortletTabbedPane tmpPane = (PortletTabbedPane) deepCopy((PortletComponent) pane);//changed by Valia: deepCopy for PortletTabbedPane throws exception...
225: tmpPage.setPortletComponent(tmpPane);
226: this .setPageTheme(tmpPage, req);
227: tmpPage.init(req, new ArrayList<ComponentIdentifier>());
228: tmpPane.save();
229: return tmpPane;
230: } catch (Exception e) {
231: log.error("Unable to save user pane!", e);
232: }
233:
234: return null;
235:
236: }
237:
238: public void setPageTheme(PortletPage page, PortletRequest req) {
239: String theme = null;
240: User user = (User) req
241: .getAttribute(SportletProperties.PORTLET_USER);
242: if (user != null)
243: theme = (String) user.getAttribute(User.THEME);
244: if (theme == null) {
245: theme = portalConfigService
246: .getProperty(PortalConfigService.DEFAULT_THEME);
247: }
248: req.getPortletSession().setAttribute(
249: SportletProperties.LAYOUT_THEME, theme,
250: PortletSession.APPLICATION_SCOPE);
251: }
252:
253: public PortletPage createPortletPageCopy(String layoutId) {
254: // get the master copy of the page
255: PortletPage masterPage = (PortletPage) masterLayouts
256: .get(layoutId);
257: PortletPage copy = null;
258: // there are two cases where a master may not be there, TCK case and logged in user
259: try {
260: copy = (PortletPage) deepCopy(masterPage);
261: } catch (Exception e) {
262: log.error("Failed to make a copy of the master page: "
263: + layoutId);
264: return createErrorPage();
265: }
266: return copy;
267: }
268:
269: public void savePortletPageMaster(PortletPage page) {
270: String layoutDesc = page.getLayoutDescriptor();
271: String layoutId = layoutDesc.substring(layoutDesc
272: .lastIndexOf(File.separator) + 1, layoutDesc
273: .lastIndexOf(".xml"));
274: log.debug("saving layout: " + layoutId);
275:
276: try {
277: PortletLayoutDescriptor.saveLayoutComponent(page,
278: layoutDesc, LAYOUT_MAPPING_PATH);
279: masterLayouts.put(layoutId, page);
280: } catch (Exception e) {
281: log.error(
282: "Unable to save layout descriptor: " + layoutDesc,
283: e);
284: }
285:
286: // remove any active layouts with this layoutId
287: for (Map<String, PortletPage> map : layouts.values()) {
288: Map userLayouts = (Map) map;
289: userLayouts.remove(layoutId);
290: log.debug("removing a layout: " + layoutId);
291: }
292: }
293:
294: /**
295: * This is the primary entrance to retrieving a PortletPage
296: *
297: * @param event the gridsphere event
298: * @return a portlet page
299: */
300: public PortletPage getPortletPage(GridSphereEvent event) {
301: // first check for layout id in request parameter
302: PortletRequest req = event.getRenderRequest();
303: String layoutId = (String) req
304: .getAttribute(SportletProperties.LAYOUT_PAGE);
305: //System.err.println("layoutId==" + layoutId);
306: if (layoutId == null) {
307: if (req.getUserPrincipal() == null) {
308: // if no reference to a layout exists, return a guest layout
309: //System.err.println("guest page");
310: layoutId = GUEST_PAGE;
311: } else {
312: //System.err.println("user page");
313: layoutId = USER_PAGE;
314: }
315: if (event.getLayoutID() != null) {
316: layoutId = event.getLayoutID();
317: // make sure if user has logged in and URL specifies guest page, then user gets directed to user page
318: if (layoutId.equals(GUEST_PAGE)
319: && (req.getUserPrincipal() != null))
320: layoutId = USER_PAGE;
321: }
322:
323: req.setAttribute(SportletProperties.LAYOUT_PAGE, layoutId);
324: }
325: return getPortletPageFromHash(req, layoutId);
326: }
327:
328: /**
329: * Added by Valia Tsagkalidou: We need this method so as to know where to put user's custom layout from a portlet.
330: *
331: * @return the path where users' layout are stored
332: */
333: public String getUserLayoutPath() {
334: return USER_LAYOUT_DIR;
335: }
336:
337: /**
338: * This returns the page from the hashtable or creates a new one if necessary
339: *
340: * @param req the portlet request
341: * @param layoutId the layout id
342: * @return the page
343: */
344: protected PortletPage getPortletPageFromHash(PortletRequest req,
345: String layoutId) {
346: PortletSession session = req.getPortletSession();
347: PortletPage page = null;
348: Map<String, PortletPage> usersLayouts = (Map<String, PortletPage>) layouts
349: .get(session.getId());
350: if (usersLayouts == null) {
351: usersLayouts = new HashMap<String, PortletPage>();
352: layouts.put(session.getId(), usersLayouts);
353: }
354:
355: // now check for existing layout in hash
356: page = (PortletPage) usersLayouts.get(layoutId);
357: // only if no page exists, create a new one and place in hash
358: if (page == null) {
359: page = createPortletPage(req, layoutId);
360: String role = page.getRequiredRole();
361: if (!role.equals("") && !req.isUserInRole(role)) {
362: // use existing page
363: log
364: .debug("User does not have proper permissions for layout="
365: + layoutId + "!!");
366: if (req.getUserPrincipal() == null) {
367: // if no reference to a layout exists, return a guest layout
368: layoutId = GUEST_PAGE;
369: } else {
370: layoutId = USER_PAGE;
371: }
372: page = (PortletPage) usersLayouts.get(layoutId);
373: if (page == null)
374: page = createPortletPage(req, layoutId);
375: req.setAttribute(SportletProperties.LAYOUT_PAGE,
376: layoutId);
377: }
378: usersLayouts.put(layoutId, page);
379: log.debug("Creating new page " + layoutId
380: + " placing in session " + session.getId());
381: sessionManager.addSessionListener(session.getId(), this );
382: }
383: setPageTheme(page, req);
384: return page;
385: }
386:
387: public PortletPage createPortletPage(PortletRequest req,
388: String layoutId) {
389: // get the master copy of the page
390:
391: PortletPage masterPage = (PortletPage) masterLayouts
392: .get(layoutId);
393: PortletPage copy = null;
394: // there are two cases where a master may not be there, TCK case and logged in user
395: if (masterPage == null) {
396: log.info("master page is null " + layoutId);
397: if (layoutId.equals(TCK_PAGE)) {
398: copy = createTCKPage(req);
399: } else {
400: if (req.getUserPrincipal() == null) {
401: // if no reference to a layout exists, return a guest layout
402: //changed by Valia: previously it returned
403: copy = getPortletPageFromHash(req, GUEST_PAGE);
404: } else {
405: //changed by Valia: previously it returned
406: copy = getPortletPageFromHash(req, USER_PAGE);
407: }
408: }
409: } else {
410: try {
411: copy = (PortletPage) deepCopy(masterPage);
412: log.info("Creating deep copy of page " + layoutId);
413: } catch (Exception e) {
414:
415: log.error("Failed to make a copy of the master page: "
416: + layoutId, e);
417: return createErrorPage();
418: }
419: }
420:
421: /* added by Valia Tsagkalidou */
422: PortletComponent generalPane = copy.getPortletComponent();
423: if (req.getUserPrincipal() != null
424: && generalPane instanceof PortletTabbedPane) {
425: PortletTabbedPane pane = (PortletTabbedPane) generalPane;
426: // place user tabs after group tabs
427: PortletTabbedPane userPane = getUserTabbedPane(req);
428: if (userPane != null) {
429: List userTabs = userPane.getPortletTabs();
430: for (int i = 0; i < userTabs.size(); i++) {
431: PortletTab subTab = (PortletTab) userTabs.get(i);
432: log.debug("adding user tab: "
433: + subTab.getTitle("en"));
434: try {
435: pane.addTab((PortletTab) deepCopy(subTab));
436: } catch (Exception e) {
437: // TODO Auto-generated catch block
438: e.printStackTrace();
439: }
440: }
441: }
442:
443: copy.setPortletComponent(pane);
444: }
445: /* End of addition */
446:
447: setPageTheme(copy, req);
448: copy.init(req, new ArrayList<ComponentIdentifier>());
449: return copy;
450: }
451:
452: public void removePortletPage(PortletRequest req) {
453: PortletSession session = req.getPortletSession();
454:
455: String id = session.getId();
456: if (layouts.containsKey(id)) {
457: layouts.remove(id);
458: }
459: //log.debug("removed user layout: " + userLayout);
460: }
461:
462: /*
463: public synchronized PortletPage shallowCopy(PortletPage page) throws CloneNotSupportedException {
464: return (PortletPage) page.clone();
465: }
466: */
467:
468: public synchronized PortletTabbedPane deepCopy(
469: PortletTabbedPane pane) throws CloneNotSupportedException {
470: return (PortletTabbedPane) deepCopy(pane);
471: }
472:
473: public synchronized Object deepCopy(Object oldObj) throws Exception {
474: ObjectOutputStream oos = null;
475: ObjectInputStream ois = null;
476: try {
477: ByteArrayOutputStream bos = new ByteArrayOutputStream(); // A
478: oos = new ObjectOutputStream(bos); // B
479: // serialize and pass the object
480: oos.writeObject(oldObj); // C
481: oos.flush(); // D
482: ByteArrayInputStream bin = new ByteArrayInputStream(bos
483: .toByteArray()); // E
484: ois = new ObjectInputStream(bin); // F
485: // return the new object
486: return ois.readObject(); // G
487: } catch (Exception e) {
488: throw e;
489: } finally {
490: if (oos != null)
491: oos.close();
492: if (ois != null)
493: ois.close();
494: }
495: }
496:
497: public void logStatistics() {
498: /*
499: log.debug("\n\nnumber of guest layouts: " + guests.size());
500: Iterator it = guests.keySet().iterator();
501: while (it.hasNext()) {
502: String id = (String) it.next();
503: log.debug("guest has session: " + id);
504: }
505: log.debug("number of user layouts: " + userLayouts.size());
506: it = userLayouts.keySet().iterator();
507: while (it.hasNext()) {
508: String id = (String) it.next();
509: log.debug("user has session: " + id);
510: }
511: */
512: }
513:
514: // TODO
515: public PortletPage createErrorPage() {
516: return createPortletPageCopy(ERROR_PAGE);
517: }
518:
519: public PortletPage createTCKPage(PortletRequest req) {
520: String[] portletNames = req.getParameterValues("portletName");
521: PortletPage page = null;
522: // Sun TCK test uses Jakarta Commons-HttpClient/2.0beta1
523:
524: // if (event.getClient().getUserAgent().indexOf("HttpClient") > 0) {
525: if (portletNames != null) {
526: log.info("Creating TCK LAYOUT!");
527: String pageName = req.getParameter("pageName");
528: page = new PortletPage();
529: PortletTableLayout tableLayout = new PortletTableLayout();
530: StringTokenizer tokenizer;
531: for (int i = 0; i < portletNames.length; i++) {
532: tokenizer = new StringTokenizer(portletNames[i], "/");
533: String appName = tokenizer.nextToken();
534: String portletName = tokenizer.nextToken();
535: //String portletClass = registry.getPortletClassName(appName, portletName);
536: //if (portletClass == null) {
537: // log.error("Unable to find portlet class for " + portletName);
538: //}
539: if (pageName == null) {
540: pageName = "TCK_testpage_" + portletName;
541: }
542: PortletFrame frame = new PortletFrame();
543: PortletTitleBar tb = new PortletTitleBar();
544: //tb.setPortletClass(portletClass);
545: tb.setPortletClass(appName + "#" + portletName);
546: frame.setPortletTitleBar(tb);
547: //frame.setPortletClass(portletClass);
548: frame.setPortletClass(appName + "#" + portletName);
549: tableLayout.addPortletComponent(frame);
550: }
551:
552: PortletTab tab = new PortletTab();
553: tab.setTitle("en", pageName);
554: tab.setPortletComponent(tableLayout);
555: PortletTabbedPane pane = new PortletTabbedPane();
556: pane.addTab(tab);
557: page.setPortletComponent(pane);
558: page.setLayoutDescriptor("/tmp/test.xml");
559: try {
560: page.save(context);
561: this .setPageTheme(page, req);
562: page.init(req, new ArrayList<ComponentIdentifier>());
563: } catch (IOException e) {
564: log
565: .error(
566: "Unable to save TCK page to /tmp/test.xml",
567: e);
568: }
569: }
570: // }
571: return page;
572: }
573:
574: // TODO
575: public void renameRole(PortletRequest req, String oldRole,
576: String newRole) {
577: List<PortletPage> pages = new ArrayList<PortletPage>();
578: pages.add(masterLayouts.get("GuestUserLayout"));
579: pages.add(masterLayouts.get("LoggedInUserLayout"));
580: try {
581: for (PortletPage p : pages) {
582: PortletPage page = (PortletPage) deepCopy(p);
583: page.init(req, new ArrayList<ComponentIdentifier>());
584: List<ComponentIdentifier> compList = page
585: .getComponentIdentifierList();
586: boolean resetLayout = false;
587: for (ComponentIdentifier compId : compList) {
588: PortletComponent comp = compId
589: .getPortletComponent();
590: String reqRole = comp.getRequiredRole();
591: if (reqRole.equalsIgnoreCase(oldRole)) {
592: resetLayout = true;
593: comp.setRequiredRole(newRole);
594: }
595: }
596: if (resetLayout)
597: savePortletPageMaster(page);
598: }
599: } catch (Exception e) {
600: log.error("Unable to load/save descriptor", e);
601: }
602:
603: }
604:
605: }
|