001: /******************************************************************************
002: * JBoss, a division of Red Hat *
003: * Copyright 2006, Red Hat Middleware, LLC, and individual *
004: * contributors as indicated by the @authors tag. See the *
005: * copyright.txt in the distribution for a full listing of *
006: * individual contributors. *
007: * *
008: * This is free software; you can redistribute it and/or modify it *
009: * under the terms of the GNU Lesser General Public License as *
010: * published by the Free Software Foundation; either version 2.1 of *
011: * the License, or (at your option) any later version. *
012: * *
013: * This software is distributed in the hope that it will be useful, *
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of *
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
016: * Lesser General Public License for more details. *
017: * *
018: * You should have received a copy of the GNU Lesser General Public *
019: * License along with this software; if not, write to the Free *
020: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
021: * 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
022: ******************************************************************************/package org.jboss.portal.theme.impl;
023:
024: import org.jboss.logging.Logger;
025: import org.jboss.portal.common.util.ContentInfo;
026: import org.jboss.portal.common.util.MediaType;
027: import org.jboss.portal.jems.as.system.AbstractJBossService;
028: import org.jboss.portal.theme.LayoutException;
029: import org.jboss.portal.theme.LayoutInfo;
030: import org.jboss.portal.theme.LayoutService;
031: import org.jboss.portal.theme.PortalLayout;
032: import org.jboss.portal.theme.PortalRenderSet;
033: import org.jboss.portal.theme.RuntimeContext;
034: import org.jboss.portal.theme.ServerRegistrationID;
035: import org.jboss.portal.theme.metadata.PortalLayoutMetaData;
036: import org.jboss.portal.theme.metadata.RenderSetMetaData;
037: import org.jboss.portal.theme.metadata.RendererSetMetaData;
038: import org.jboss.system.Service;
039:
040: import java.util.ArrayList;
041: import java.util.Collection;
042: import java.util.Collections;
043: import java.util.HashMap;
044: import java.util.Iterator;
045: import java.util.List;
046: import java.util.Map;
047:
048: /**
049: * Implementaion of the layout server. <p>The layout server is a registry of all available layouts. The server also
050: * allows access to all available render sets. Render sets can be independent (named), or children of a layout.
051: * Accordingly, the layout server provides accessor methods to get render set by name, or by layout. Render sets can,
052: * and must, be defined for a specific media type (mime type).</p>
053: *
054: * @author <a href="mailto:mholzner@novell.com">Martin Holzner</a>.
055: * @version <tt>$Revision: 8784 $</tt>
056: * @see org.jboss.portal.theme.PortalLayout
057: * @see org.jboss.portal.theme.PortalRenderSet
058: * @see MediaType
059: */
060: public class LayoutServiceImpl extends AbstractJBossService implements
061: LayoutService, Service {
062: private static Logger log = Logger
063: .getLogger(LayoutServiceImpl.class);
064:
065: /** Map of layout id to layout. */
066: private Map layouts;
067:
068: /** Map of layout name to layout id. */
069: private Map layoutNames;
070:
071: /** Map of appID + "." + layout name to layout id. */
072: private Map exactLayoutNames;
073:
074: /** Map of renderSet registration id to list of rendersets. */
075: private Map renderSets;
076:
077: /** Map of render set name to render set. */
078: private Map renderSetNames;
079:
080: /** Map of appID + "." + render set name to render set. */
081: private Map exactRenderSetNames;
082:
083: /** . */
084: private PortalLayout defaultLayout;
085:
086: /** . */
087: private String defaultName;
088:
089: private String defaultRenderSetName;
090:
091: public LayoutServiceImpl() {
092: log.debug("LayoutServiceImpl instantiated.");
093: }
094:
095: /** @see org.jboss.system.Service#create() */
096: protected void createService() throws Exception {
097: log.debug("create LayoutServiceImpl ....");
098: layouts = Collections.synchronizedMap(new HashMap());
099: layoutNames = Collections.synchronizedMap(new HashMap());
100: exactLayoutNames = Collections.synchronizedMap(new HashMap());
101: renderSets = Collections.synchronizedMap(new HashMap());
102: renderSetNames = Collections.synchronizedMap(new HashMap());
103: exactRenderSetNames = Collections
104: .synchronizedMap(new HashMap());
105: }
106:
107: /** @see org.jboss.system.Service#destroy() */
108: protected void destroyService() {
109: log.debug("destroy LayoutServiceImpl ....");
110: layouts.clear();
111: layoutNames.clear();
112: exactLayoutNames.clear();
113: renderSetNames.clear();
114: exactRenderSetNames.clear();
115: }
116:
117: /** @see org.jboss.system.Service#start() */
118: protected void startService() throws Exception {
119: log.debug("start LayoutServiceImpl ....");
120: }
121:
122: /** @see org.jboss.system.Service#stop() */
123: protected void stopService() {
124: log.debug("stop LayoutServiceImpl ....");
125: }
126:
127: public void addLayout(RuntimeContext runtimeContext,
128: PortalLayoutMetaData layoutMD) throws LayoutException {
129: // TODO: if there in no default layout, set one up.
130: try {
131: if (layoutMD == null) {
132: throw new IllegalArgumentException(
133: "Layout metaData is null");
134: }
135:
136: //
137: PortalLayout layout = (PortalLayout) runtimeContext
138: .getClassLoader()
139: .loadClass(layoutMD.getClassName()).newInstance();
140: log.debug("adding layout: " + layout);
141:
142: //
143: LayoutInfo info = new LayoutInfo(runtimeContext, layoutMD);
144: layout.init(this , info);
145:
146: //
147: if (layouts == null) {
148: create();
149: }
150:
151: layouts.put(info.getRegistrationId(), layout);
152: layoutNames.put(info.getName(), info.getRegistrationId());
153: exactLayoutNames.put(
154: info.getAppId() + "." + info.getName(), info
155: .getRegistrationId());
156: } catch (Exception e) {
157: throw new LayoutException(e);
158: }
159: }
160:
161: public void setDefaultLayoutName(String name) {
162: log.debug("setting default: " + name);
163: defaultName = name;
164: defaultLayout = null;
165: }
166:
167: /** @see LayoutService#getDefaultLayout() */
168: public PortalLayout getDefaultLayout() {
169: if (defaultLayout == null) {
170: if (exactLayoutNames.keySet().contains(defaultName)) {
171: ServerRegistrationID defaultID = (ServerRegistrationID) exactLayoutNames
172: .get(defaultName);
173: defaultLayout = (PortalLayout) layouts.get(defaultID);
174: } else if (layoutNames.keySet().contains(defaultName)) {
175: ServerRegistrationID defaultID = (ServerRegistrationID) layoutNames
176: .get(defaultName);
177: defaultLayout = (PortalLayout) layouts.get(defaultID);
178: }
179: }
180: if (defaultLayout == null) {
181: log.error("Couldn't find the default layout named:"
182: + defaultName);
183: }
184: return defaultLayout;
185: }
186:
187: /** @see LayoutService#getLayout(org.jboss.portal.theme.ServerRegistrationID,boolean) */
188: public PortalLayout getLayout(ServerRegistrationID id,
189: boolean defaultOnNull) {
190: log.debug("get " + id + "...");
191: if (id == null) {
192: throw new IllegalArgumentException(
193: "No null id argument allowed");
194: }
195:
196: if (!layouts.keySet().contains(id) && defaultOnNull) {
197: return getDefaultLayout();
198: }
199: return (PortalLayout) layouts.get(id);
200: }
201:
202: /** @see LayoutService#getLayout(String,boolean) */
203: public PortalLayout getLayout(String name, boolean defaultOnNull) {
204: log.debug("get " + name + "...");
205:
206: if (exactLayoutNames.containsKey(name)) {
207: log.debug("found exact: " + name);
208: return (PortalLayout) layouts.get(exactLayoutNames
209: .get(name));
210: } else if (layoutNames.containsKey(name)) {
211: log.debug("found " + name);
212: return (PortalLayout) layouts.get(layoutNames.get(name));
213: } else if (defaultOnNull) {
214: log.debug("try to return default " + name);
215: return getDefaultLayout();
216: }
217:
218: log.debug("oops , not found " + name);
219: return null;
220: }
221:
222: public PortalLayout getLayoutById(String layoutIdString) {
223: //
224: PortalLayout layout;
225:
226: if (layoutIdString == null) {
227: layout = getDefaultLayout();
228: } else if (layoutIdString.lastIndexOf(".") > 0) {
229: // if the id is provided in the form of context.name then look up the layout via a registration id
230: ServerRegistrationID layoutID = ServerRegistrationID
231: .createID(ServerRegistrationID.TYPE_LAYOUT,
232: ThemeServiceImpl.parseId(layoutIdString));
233: layout = getLayout(layoutID, true);
234: } else {
235: // otherwise use the ordinary layout name provided and lookup the layout via the name
236: layout = getLayout(layoutIdString, true);
237: }
238:
239: // Last Chance
240: if (layout == null) {
241: layout = getLayout("generic", true);
242: }
243:
244: // We don't like that situation
245: if (layout == null) {
246: throw new IllegalStateException("NO LAYOUT FOUND FOR "
247: + layoutIdString);
248: }
249:
250: //
251: return layout;
252: }
253:
254: /**
255: * Remove the layout identified by the provided registration id.
256: *
257: * @param id the id of the layout that needs to be removed
258: * @throws LayoutException
259: */
260: public void removeLayout(ServerRegistrationID id)
261: throws LayoutException {
262: log.debug("removing layout with id: " + id);
263: if (id == null) {
264: throw new IllegalArgumentException(
265: "No null id argument allowed");
266: }
267:
268: PortalLayout layout = (PortalLayout) layouts.get(id);
269:
270: if (layout == null) {
271: log.debug("Not found. Nothing to remove.");
272: return;
273: }
274:
275: LayoutInfo info = layout.getLayoutInfo();
276: final String layoutName = info.getAppId() + "."
277: + info.getName();
278: if (exactLayoutNames.keySet().contains(layoutName)) {
279: log.debug("removing layout exact " + layoutName);
280: exactLayoutNames.remove(layoutName);
281: }
282: if (layoutNames.keySet().contains(info.getName())) {
283: if (id.equals(layoutNames.get(info.getName()))) {
284: log.debug("removing layout " + info.getName());
285: layoutNames.remove(info.getName());
286: }
287: }
288:
289: layouts.remove(id);
290: layout.destroy();
291:
292: if (getDefaultLayout() != null
293: && getDefaultLayout().equals(layout)) {
294: log.debug("removed default layout, need to set new one...");
295: Iterator i = layouts.keySet().iterator();
296:
297: if (i.hasNext()) {
298: ServerRegistrationID defaultID = (ServerRegistrationID) i
299: .next();
300: layout = (PortalLayout) layouts.get(defaultID);
301: defaultLayout = layout;
302: defaultName = layout.getLayoutInfo().getName();
303: log.debug("set default layout to "
304: + layout.getLayoutInfo().getAppId() + "."
305: + layout.getLayoutInfo().getName());
306: } else {
307: // We're screwed there is no more layout.
308: defaultLayout = null;
309: defaultName = null;
310: }
311: }
312: }
313:
314: /** @see LayoutService#removeLayouts(String) */
315: public void removeLayouts(String appID) throws LayoutException {
316: List layoutsToDelete = new ArrayList();
317: ServerRegistrationID id;
318:
319: // first get all the layouts that fit the criteria (can't remove while iterating)
320: for (Iterator allLayouts = layouts.keySet().iterator(); allLayouts
321: .hasNext();) {
322: id = (ServerRegistrationID) allLayouts.next();
323: PortalLayout layout = (PortalLayout) layouts.get(id);
324: if (layout.getLayoutInfo().getAppId().equals(appID)) {
325: layoutsToDelete.add(id);
326: }
327: }
328:
329: // now remove them
330: for (Iterator toDelete = layoutsToDelete.iterator(); toDelete
331: .hasNext();) {
332: removeLayout((ServerRegistrationID) toDelete.next());
333: }
334: }
335:
336: public void addRenderSet(RuntimeContext runtimeContext,
337: RenderSetMetaData renderSetMD) throws LayoutException {
338: try {
339: for (Iterator s = renderSetMD.getRendererSet().iterator(); s
340: .hasNext();) {
341: RendererSetMetaData rendererSetMD = (RendererSetMetaData) s
342: .next();
343: PortalRenderSet renderSet = new PortalRenderSet(
344: renderSetMD.getName(), runtimeContext,
345: rendererSetMD);
346: log.debug("adding : " + renderSet.getRegistrationId());
347: Map sets = (Map) this .renderSets.get(renderSet
348: .getRegistrationId());
349: if (sets == null) {
350: sets = new HashMap();
351: this .renderSets.put(renderSet.getRegistrationId(),
352: sets);
353: }
354: sets.put(renderSet.getMediaType(), renderSet);
355: renderSetNames.put(renderSet.getName(), renderSet
356: .getRegistrationId());
357: exactRenderSetNames.put(renderSet.getAppId() + "."
358: + renderSet.getName(), renderSet
359: .getRegistrationId());
360: }
361: } catch (Exception e) {
362: throw new LayoutException(e);
363: }
364: }
365:
366: /** @see LayoutService#getRenderSet(String,org.jboss.portal.common.util.MediaType) */
367: public PortalRenderSet getRenderSet(String renderSetName,
368: MediaType mediaType) {
369: ServerRegistrationID id;
370: id = (ServerRegistrationID) exactRenderSetNames
371: .get(renderSetName);
372:
373: if (id == null) {
374: id = (ServerRegistrationID) renderSetNames
375: .get(renderSetName);
376: }
377:
378: return getRenderSet(id, mediaType);
379: }
380:
381: public PortalRenderSet getRenderSet(ServerRegistrationID id,
382: MediaType mediaType) {
383: if (id != null) {
384: Map sets = (Map) renderSets.get(id);
385: return (PortalRenderSet) sets.get(mediaType);
386: }
387: return null;
388: }
389:
390: /** @see LayoutService#removeRenderSets(String) */
391: public void removeRenderSets(String appId) throws LayoutException {
392: log.debug("removing named render sets for : " + appId);
393: List renderSetsToDelete = new ArrayList();
394: for (Iterator i = renderSets.keySet().iterator(); i.hasNext();) {
395: ServerRegistrationID id = (ServerRegistrationID) i.next();
396: if (appId.equals(id.getName(0))) {
397: renderSetsToDelete.add(id);
398: }
399: }
400:
401: for (Iterator i = renderSetsToDelete.iterator(); i.hasNext();) {
402: ServerRegistrationID id = (ServerRegistrationID) i.next();
403: renderSets.remove(id);
404: String key = id.getName(0) + "." + id.getName(1);
405: log.debug("removing render sets: " + key);
406: exactRenderSetNames.remove(key);
407:
408: // make sure that the we don't delete a render set with the same name in a different appId
409: if (id.equals(renderSetNames.get(id.getName(1)))) {
410: renderSetNames.remove(id.getName(1));
411: }
412: }
413: }
414:
415: /** @see org.jboss.portal.theme.LayoutService#getLayouts() */
416: public Collection getLayouts() {
417: return Collections.unmodifiableCollection(layouts.values());
418: }
419:
420: /** @see org.jboss.portal.theme.LayoutService#getRenderSets() */
421: public Collection getRenderSets() {
422: return Collections.unmodifiableCollection((renderSetNames
423: .values()));
424: }
425:
426: public void setDefaultRenderSetName(String name) {
427: log.debug("setting default render set: " + name);
428: defaultRenderSetName = name;
429: }
430:
431: public String getDefaultRenderSetName() {
432: return defaultRenderSetName;
433: }
434:
435: /**
436: * Get the PortalRenderSet to use for the provided layout, page and media type. <p>The render set can be defined
437: * specifically for a layout, a page, or a portal. The one defined for the layout overwrites the one defined for the
438: * page, which in turn overwrites the one defined for the portal. The render set is defined for a specific content
439: * type (media type), which will be determined from the provided HttpStreamInfo.</p>
440: */
441: public PortalRenderSet getRenderSet(LayoutInfo info,
442: ContentInfo streamInfo, String renderSetName) {
443: if (renderSetName == null) {
444: renderSetName = getDefaultRenderSetName();
445: }
446: if (info == null || renderSetName == null || streamInfo == null) {
447: throw new IllegalArgumentException(
448: "No null arguments allowed [" + info + "] ["
449: + renderSetName + "] [" + streamInfo + "]");
450: }
451: MediaType contentType = streamInfo.getContentType();
452: return getRenderSet(renderSetName, contentType);
453: }
454: }
|