001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/portal/tags/sakai_2-4-1/portal-service-impl/impl/src/java/org/sakaiproject/portal/service/PortalServiceImpl.java $
003: * $Id: PortalServiceImpl.java 29143 2007-04-19 01:10:38Z ajpoland@iupui.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 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.portal.service;
021:
022: import java.util.ConcurrentModificationException;
023: import java.util.HashMap;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Map;
027: import java.util.Properties;
028:
029: import javax.servlet.http.HttpServletRequest;
030:
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033: import org.apache.pluto.core.PortletContextManager;
034: import org.apache.pluto.descriptors.portlet.PortletAppDD;
035: import org.apache.pluto.descriptors.portlet.PortletDD;
036: import org.apache.pluto.internal.InternalPortletContext;
037: import org.apache.pluto.spi.optional.PortletRegistryService;
038: import org.exolab.castor.util.LocalConfiguration;
039: import org.exolab.castor.util.Configuration.Property;
040: import org.sakaiproject.component.cover.ComponentManager;
041: import org.sakaiproject.component.cover.ServerConfigurationService;
042: import org.sakaiproject.portal.api.Portal;
043: import org.sakaiproject.portal.api.PortalHandler;
044: import org.sakaiproject.portal.api.PortalRenderEngine;
045: import org.sakaiproject.portal.api.PortalService;
046: import org.sakaiproject.portal.api.PortletApplicationDescriptor;
047: import org.sakaiproject.portal.api.PortletDescriptor;
048: import org.sakaiproject.portal.api.StoredState;
049: import org.sakaiproject.portal.api.StyleAbleProvider;
050: import org.sakaiproject.tool.api.Session;
051: import org.sakaiproject.tool.cover.SessionManager;
052:
053: /**
054: * @author ieb
055: * @since Sakai 2.4
056: * @version $Rev: 29143 $
057: */
058:
059: public class PortalServiceImpl implements PortalService {
060: private static final Log log = LogFactory
061: .getLog(PortalServiceImpl.class);
062:
063: /**
064: * Parameter to force state reset
065: */
066: public static final String PARM_STATE_RESET = "sakai.state.reset";
067:
068: private Map<String, PortalRenderEngine> renderEngines = new HashMap<String, PortalRenderEngine>();
069:
070: private Map<String, Map<String, PortalHandler>> handlerMaps = new HashMap<String, Map<String, PortalHandler>>();
071:
072: private Map<String, Portal> portals = new HashMap<String, Portal>();
073:
074: private StyleAbleProvider stylableServiceProvider;
075:
076: public void init() {
077: try {
078: try {
079: // configure the parser for castor.. before anything else get a
080: // chance
081: Properties castorProperties = LocalConfiguration
082: .getDefault();
083: String parser = ServerConfigurationService
084: .getString("sakai.xml.sax.parser",
085: "com.sun.org.apache.xerces.internal.parsers.SAXParser");
086: log.info("Configured Castor to use SAX Parser "
087: + parser);
088: castorProperties.put(Property.Parser, parser);
089: } catch (Exception ex) {
090: log.error("Failed to configure Castor", ex);
091: }
092: stylableServiceProvider = (StyleAbleProvider) ComponentManager
093: .get(StyleAbleProvider.class.getName());
094: } catch (Exception ex) {
095: }
096: if (stylableServiceProvider == null) {
097: log
098: .info("No Styleable Provider found, the portal will not be stylable");
099: }
100: }
101:
102: public StoredState getStoredState() {
103: Session s = SessionManager.getCurrentSession();
104: StoredState ss = (StoredState) s
105: .getAttribute("direct-stored-state");
106: log.debug("Got Stored State as [" + ss + "]");
107: return ss;
108: }
109:
110: public void setStoredState(StoredState ss) {
111: Session s = SessionManager.getCurrentSession();
112: if (s.getAttribute("direct-stored-state") == null || ss == null) {
113: StoredState ssx = (StoredState) s
114: .getAttribute("direct-stored-state");
115: log.debug("Removing Stored state " + ssx);
116: if (ssx != null) {
117: Exception ex = new Exception("traceback");
118: log
119: .debug(
120: "Removing active Stored State Traceback gives location ",
121: ex);
122: }
123:
124: s.setAttribute("direct-stored-state", ss);
125: log.debug(" Set StoredState as [" + ss + "]");
126: }
127: }
128:
129: private static final String TOOLSTATE_PARAM_PREFIX = "toolstate-";
130:
131: private static String computeToolStateParameterName(
132: String placementId) {
133: return TOOLSTATE_PARAM_PREFIX + placementId;
134: }
135:
136: public String decodeToolState(Map<String, String[]> params,
137: String placementId) {
138: String attrname = computeToolStateParameterName(placementId);
139: String[] attrval = params.get(attrname);
140: return attrval == null ? null : attrval[0];
141: }
142:
143: public Map<String, String[]> encodeToolState(String placementId,
144: String URLstub) {
145: String attrname = computeToolStateParameterName(placementId);
146: Map<String, String[]> togo = new HashMap<String, String[]>();
147: // could assemble state from other visible tools here
148: togo.put(attrname, new String[] { URLstub });
149: return togo;
150: }
151:
152: // To allow us to retain reset state across redirects
153: public String getResetState() {
154: Session s = SessionManager.getCurrentSession();
155: String ss = (String) s.getAttribute("reset-stored-state");
156: return ss;
157: }
158:
159: public void setResetState(String ss) {
160: Session s = SessionManager.getCurrentSession();
161: if (s.getAttribute("reset-stored-state") == null || ss == null) {
162: s.setAttribute("reset-stored-state", ss);
163: }
164: }
165:
166: public boolean isEnableDirect() {
167: boolean directEnable = "true".equals(ServerConfigurationService
168: .getString("charon.directurl", "true"));
169: log.debug("Direct Enable is " + directEnable);
170: return directEnable;
171: }
172:
173: public boolean isResetRequested(HttpServletRequest req) {
174: return "true".equals(req.getParameter(PARM_STATE_RESET))
175: || "true".equals(getResetState());
176: }
177:
178: public String getResetStateParam() {
179: // TODO Auto-generated method stub
180: return PARM_STATE_RESET;
181: }
182:
183: public StoredState newStoredState(String marker, String replacement) {
184: log.debug("Storing State for Marker=[" + marker
185: + "] replacement=[" + replacement + "]");
186: return new StoredStateImpl(marker, replacement);
187: }
188:
189: public Iterator<PortletApplicationDescriptor> getRegisteredApplications() {
190: PortletRegistryService registry = PortletContextManager
191: .getManager();
192: final Iterator apps = registry
193: .getRegisteredPortletApplications();
194: return new Iterator<PortletApplicationDescriptor>() {
195:
196: public boolean hasNext() {
197: return apps.hasNext();
198: }
199:
200: public PortletApplicationDescriptor next() {
201: final InternalPortletContext pc = (InternalPortletContext) apps
202: .next();
203:
204: final PortletAppDD appDD = pc
205: .getPortletApplicationDefinition();
206: return new PortletApplicationDescriptor() {
207:
208: public String getApplicationContext() {
209: return pc.getPortletContextName();
210: }
211:
212: public String getApplicationId() {
213: return pc.getApplicationId();
214: }
215:
216: public String getApplicationName() {
217: return pc.getApplicationId();
218: }
219:
220: public Iterator<PortletDescriptor> getPortlets() {
221: if (appDD != null) {
222: List portlets = appDD.getPortlets();
223:
224: final Iterator portletsI = portlets
225: .iterator();
226: return new Iterator<PortletDescriptor>() {
227:
228: public boolean hasNext() {
229: return portletsI.hasNext();
230: }
231:
232: public PortletDescriptor next() {
233: final PortletDD pdd = (PortletDD) portletsI
234: .next();
235: return new PortletDescriptor() {
236:
237: public String getPortletId() {
238: return pdd.getPortletName();
239: }
240:
241: public String getPortletName() {
242: return pdd.getPortletName();
243: }
244:
245: };
246: }
247:
248: public void remove() {
249: }
250:
251: };
252: } else {
253: log
254: .warn(" Portlet Application has no portlets "
255: + pc
256: .getPortletContextName());
257: return new Iterator<PortletDescriptor>() {
258:
259: public boolean hasNext() {
260: return false;
261: }
262:
263: public PortletDescriptor next() {
264: return null;
265: }
266:
267: public void remove() {
268: }
269:
270: };
271: }
272: }
273:
274: };
275: }
276:
277: public void remove() {
278: }
279:
280: };
281: }
282:
283: /*
284: * (non-Javadoc)
285: *
286: * @see org.sakaiproject.portal.api.PortalService#getRenderEngine(javax.servlet.http.HttpServletRequest)
287: */
288: public PortalRenderEngine getRenderEngine(String context,
289: HttpServletRequest request) {
290: // at this point we ignore request but we might use ut to return more
291: // than one render engine
292:
293: if (context == null || context.length() == 0) {
294: context = Portal.DEFAULT_PORTAL_CONTEXT;
295: }
296:
297: return (PortalRenderEngine) safeGet(renderEngines, context);
298: }
299:
300: /*
301: * (non-Javadoc)
302: *
303: * @see org.sakaiproject.portal.api.PortalService#addRenderEngine(org.sakaiproject.portal.api.PortalRenderEngine)
304: */
305: public void addRenderEngine(String context,
306: PortalRenderEngine vengine) {
307:
308: safePut(renderEngines, context, vengine);
309: }
310:
311: /*
312: * (non-Javadoc)
313: *
314: * @see org.sakaiproject.portal.api.PortalService#removeRenderEngine(org.sakaiproject.portal.api.PortalRenderEngine)
315: */
316: public void removeRenderEngine(String context,
317: PortalRenderEngine vengine) {
318: safePut(renderEngines, context, null);
319: }
320:
321: /*
322: * (non-Javadoc)
323: *
324: * @see org.sakaiproject.portal.api.PortalService#addHandler(java.lang.String,
325: * org.sakaiproject.portal.api.PortalHandler)
326: */
327: public void addHandler(Portal portal, PortalHandler handler) {
328: String portalContext = portal.getPortalContext();
329: Map<String, PortalHandler> handlerMap = getHandlerMap(portal);
330: String urlFragment = handler.getUrlFragment();
331: PortalHandler ph = (PortalHandler) safeGet(handlerMap,
332: urlFragment);
333: if (ph != null) {
334: handler.deregister(portal);
335: log.warn("Handler Present on " + urlFragment
336: + " will replace " + ph + " with " + handler);
337: }
338: handler.register(portal, this , portal.getServletContext());
339: safePut(handlerMap, urlFragment, handler);
340:
341: log.info("URL " + portalContext + ":/" + urlFragment
342: + " will be handled by " + handler);
343:
344: }
345:
346: /*
347: * (non-Javadoc)
348: *
349: * @see org.sakaiproject.portal.api.PortalService#getHandlerMap(java.lang.String)
350: */
351: public Map<String, PortalHandler> getHandlerMap(Portal portal) {
352: return getHandlerMap(portal, true);
353: }
354:
355: @SuppressWarnings("unchecked")
356: private Map<String, PortalHandler> getHandlerMap(Portal portal,
357: boolean create) {
358: String portalContext = portal.getPortalContext();
359: Map<String, PortalHandler> handlerMap = (Map<String, PortalHandler>) safeGet(
360: handlerMaps, portalContext);
361: if (create && handlerMap == null) {
362: handlerMap = new HashMap<String, PortalHandler>();
363: safePut(handlerMaps, portalContext, handlerMap);
364: }
365: return handlerMap;
366: }
367:
368: /*
369: * (non-Javadoc)
370: *
371: * @see org.sakaiproject.portal.api.PortalService#removeHandler(java.lang.String,
372: * java.lang.String) This method it NOT thread safe, but the likelyhood
373: * of a co
374: */
375: public void removeHandler(Portal portal, String urlFragment) {
376: Map<String, PortalHandler> handlerMap = getHandlerMap(portal,
377: false);
378: if (handlerMap != null) {
379: PortalHandler ph = (PortalHandler) safeGet(handlerMap,
380: urlFragment);
381: if (ph != null) {
382: ph.deregister(portal);
383: safePut(handlerMap, urlFragment, null);
384: log.warn("Handler Present on " + urlFragment + " "
385: + ph + " will be removed ");
386: }
387: }
388: }
389:
390: /**
391: * @param handlerMap
392: * @param urlFragment
393: * @param object
394: */
395: @SuppressWarnings("unchecked")
396: private void safePut(Map map, String key, Object object) {
397: int i = 3;
398: while (i > 0) {
399: try {
400: map.put(key, object);
401: i = -1;
402: } catch (ConcurrentModificationException ex) {
403: i--;
404: }
405: }
406: if (i != -1) {
407: map.put(key, object);
408: }
409: }
410:
411: private Object safeGet(Map map, String key) {
412: int i = 3;
413: while (i > 0) {
414: try {
415: return map.get(key);
416: } catch (ConcurrentModificationException ex) {
417:
418: i--;
419: }
420: }
421: return map.get(key);
422: }
423:
424: /*
425: * (non-Javadoc)
426: *
427: * @see org.sakaiproject.portal.api.PortalService#addPortal(org.sakaiproject.portal.api.Portal)
428: */
429: public void addPortal(Portal portal) {
430: String portalContext = portal.getPortalContext();
431: safePut(portals, portalContext, portal);
432: // reconnect any handlers
433: Map<String, PortalHandler> phm = getHandlerMap(portal);
434: for (Iterator<PortalHandler> pIterator = phm.values()
435: .iterator(); pIterator.hasNext();) {
436: PortalHandler ph = pIterator.next();
437: ph.register(portal, this , portal.getServletContext());
438: }
439: }
440:
441: /*
442: * (non-Javadoc)
443: *
444: * @see org.sakaiproject.portal.api.PortalService#removePortal(org.sakaiproject.portal.api.Portal)
445: */
446: public void removePortal(Portal portal) {
447: String portalContext = portal.getPortalContext();
448: safePut(portals, portalContext, null);
449: }
450:
451: /*
452: * (non-Javadoc)
453: *
454: * @see org.sakaiproject.portal.api.PortalService#getStylableService()
455: */
456: public StyleAbleProvider getStylableService() {
457: return stylableServiceProvider;
458: }
459:
460: }
|