001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.geronimo.pluto;
017:
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.List;
021:
022: import org.apache.commons.logging.Log;
023: import org.apache.commons.logging.LogFactory;
024: import org.apache.geronimo.gbean.GBeanInfo;
025: import org.apache.geronimo.gbean.GBeanInfoBuilder;
026: import org.apache.geronimo.gbean.GBeanLifecycle;
027: import org.apache.pluto.driver.services.portal.PageConfig;
028: import org.apache.pluto.driver.services.portal.PortletWindowConfig;
029: import org.apache.pluto.driver.services.portal.RenderConfigService;
030: import org.apache.pluto.driver.services.portal.admin.RenderConfigAdminService;
031:
032: /* GBean for adding an item to the Administration Console's Navigator. Web apps
033: * that contain portlets can add those portlets to the navigator by including
034: * a GBean in their deployment plans like this:
035: *
036: * <gbean name="MyAdminConsoleExtension" class="org.apache.geronimo.pluto.AdminConsoleExtensionGBean">
037: * <attribute name="pageTitle">Hello</attribute>
038: * <attribute name="portletContext">/HelloWorldPortlet</attribute>
039: * <attribute name="portletList">[portlet_id_1, portlet_id_2]</attribute>
040: * </gbean>
041: */
042: public class AdminConsoleExtensionGBean implements GBeanLifecycle {
043: private static final Log log = LogFactory
044: .getLog(AdminConsoleExtensionGBean.class);
045: public static final GBeanInfo GBEAN_INFO;
046: private final String pageTitle;
047: private final String portletContext;
048: private final ArrayList<String> portletList;
049: private final PortalContainerServices portletContainerServices;
050:
051: /* Constructor for GBean */
052: public AdminConsoleExtensionGBean(String pageTitle,
053: String portletContext, ArrayList<String> portletList,
054: PortalContainerServices portalContainerServices) {
055: super ();
056: this .pageTitle = pageTitle;
057: this .portletContext = portletContext;
058: this .portletList = portletList;
059: this .portletContainerServices = portalContainerServices;
060: }
061:
062: /*
063: * Add the PageConfig to pluto. This will overwrite any existing pages with the same page name
064: * @see org.apache.geronimo.pluto.PlutoAccessInterface#addPage(org.apache.pluto.driver.services.portal.PageConfig)
065: */
066: private void addPage(PageConfig pageConfig) {
067: //Add the new PageConfig to Pluto
068: RenderConfigAdminService renderConfig = portletContainerServices
069: .getAdminConfiguration().getRenderConfigAdminService();
070: renderConfig.addPage(pageConfig);
071: }
072:
073: /*
074: * This will add the portlets to the PageConfig in Pluto.
075: * @see org.apache.geronimo.pluto.PlutoAccessInterface#addPortlets(java.lang.String, java.lang.String, java.util.ArrayList)
076: */
077: private void addPortlets() {
078: if (pageExists()) {
079: PageConfig pageConfig = getPageConfigFromPluto();
080: int portletCount = portletList.size();
081: for (int i = 0; i < portletCount; i++) {
082: pageConfig.addPortlet(portletContext, portletList
083: .get(i));
084: }
085: } else {
086: log.warn("Cannot add portlets to non-existent page "
087: + pageTitle);
088: }
089: }
090:
091: /*
092: * Removes a PageConfig object in Pluto with the pageTitle
093: * @see org.apache.geronimo.pluto.PlutoAccessInterface#removePage(java.lang.String)
094: */
095: private void removePage() {
096: //all we really need is a PageConfig with the page name
097: PageConfig pageConfig = createPageConfig();
098:
099: RenderConfigAdminService renderConfig = portletContainerServices
100: .getAdminConfiguration().getRenderConfigAdminService();
101:
102: //This removePage method was added into Pluto as a patch (PLUTO-387). addPage functionality
103: //was available, but removePage functionality was unavailable.
104: //NOTE: getList returns a copy of the Map that stores page data in List form. Since it's a copy,
105: //it does not serve our purpose, and since no simple workaround was available, the simpler
106: //solution was just to try to patch the code.
107: renderConfig.removePage(pageConfig);
108: }
109:
110: /*
111: * Removes the portletList from the PageConfig in Pluto
112: * @see org.apache.geronimo.pluto.PlutoAccessInterface#removePortlets(java.lang.String, java.util.ArrayList)
113: */
114: private void removePortlets() {
115: if (pageExists()) {
116: PageConfig pageConfig = getPageConfigFromPluto();
117: int portletCount = portletList.size();
118: Collection<String> list = pageConfig.getPortletIds();
119:
120: //run through the list of portlets to remove
121: for (int i = 0; i < portletCount; i++) {
122: String portletName = portletList.get(i);
123:
124: //run through the list of portlets on this page and see if we can find a match
125: for (String pid : list) {
126: String pletContext = PortletWindowConfig
127: .parseContextPath(pid);
128: String pletName = PortletWindowConfig
129: .parsePortletName(pid);
130: if (portletContext.equals(pletContext)
131: && portletName.equals(pletName)) {
132: pageConfig.removePortlet(pid);
133: break;
134: }
135: }
136: }
137: } else {
138: log.warn("can't remove portlets from non-existent page "
139: + pageTitle);
140: }
141: }
142:
143: /*
144: * Creates a new PageConfig object with this GBean's pageTitle
145: */
146: private PageConfig createPageConfig() {
147: //Create a new PageConfig
148: PageConfig pageConfig = new PageConfig();
149: pageConfig.setName(pageTitle);
150: pageConfig.setUri("/WEB-INF/themes/default-theme.jsp");
151: return pageConfig;
152: }
153:
154: /*
155: * Gets the PageConfig object from Pluto with that name
156: */
157: private PageConfig getPageConfigFromPluto() {
158: RenderConfigService service = portletContainerServices
159: .getRenderConfigService();
160:
161: return service.getPage(pageTitle);
162: }
163:
164: /*
165: * return true if Pluto contains a PageConfig with that name, else false
166: */
167: private boolean pageExists() {
168: if (pageTitle == null)
169: return false;
170:
171: RenderConfigService service = portletContainerServices
172: .getRenderConfigService();
173:
174: List<PageConfig> pageConfigs = service.getPages();
175: for (PageConfig pageConfig : pageConfigs) {
176: if (pageTitle.equals(pageConfig.getName())) {
177: return true;
178: }
179: }
180:
181: return false;
182: }
183:
184: /*
185: * returns true if Pluto contains a PageConfig with that name and it has 0 or if there isn't a page with that name
186: */
187: private boolean pageIsEmpty() {
188: if (pageExists()) {
189: PageConfig pageConfig = getPageConfigFromPluto();
190: return pageConfig.getPortletIds().size() == 0;
191: } else {
192: log.debug("no pageConfig found for " + pageTitle);
193: return true;
194: }
195: }
196:
197: /*
198: * Called when the GBean is started
199: * This adds/updates a Page in Pluto according to this GBean's specifications (ACE)
200: * @see org.apache.geronimo.gbean.GBeanLifecycle#doStart()
201: */
202: public synchronized void doStart() throws Exception {
203: // check to make sure that a portal driver has registered with the container services
204: if (portletContainerServices.getAdminConfiguration() == null) {
205: throw new RuntimeException(
206: "No portal driver has been registered with the portal container services");
207: }
208:
209: //add the page if it doesn't exist yet
210: if (!pageExists()) {
211: //create a PageConfig
212: PageConfig newPageConfig = createPageConfig();
213: addPage(newPageConfig);
214: }
215:
216: //add portlets to this newly created page
217: addPortlets();
218: log
219: .debug("Started AdminConsoleExtensionGBean for "
220: + pageTitle);
221: }
222:
223: /*
224: * Called when the GBean is stopped
225: * This removes/updates a Page in Pluto according to this GBean's specifications
226: * @see org.apache.geronimo.gbean.GBeanLifecycle#doStop()
227: */
228: public synchronized void doStop() throws Exception {
229: try {
230: //remove portlets from the page
231: removePortlets();
232:
233: //if the page has 0 portlets on it, then go ahead and remove it
234: if (pageIsEmpty()) {
235: removePage();
236: }
237: } catch (NullPointerException e) {
238: // during normal server shutdown the portal driver has been shut down before
239: // the admin console extensions. the way that pluto is currently implemented
240: // is that when the portal driver shuts down it destroys all its services.
241: // this leads to an NPE when you try to use them. currently there is no
242: // way to check to see if a service has been shut down.
243: log.debug("could not remove portlets for " + pageTitle, e);
244: }
245:
246: log
247: .debug("Stopped AdminConsoleExtensionGBean for "
248: + pageTitle);
249: }
250:
251: /*
252: * Called when the GBean fails
253: * @see org.apache.geronimo.gbean.GBeanLifecycle#doFail()
254: */
255: public synchronized void doFail() {
256: log.warn("AdminConsoleExtensionGBean for " + pageTitle
257: + " failed.");
258: }
259:
260: /*
261: * Standard GBean information
262: */
263: static {
264: GBeanInfoBuilder infoFactory = new GBeanInfoBuilder(
265: "AdminConsoleExtensionGBean",
266: AdminConsoleExtensionGBean.class);
267: infoFactory.addAttribute("pageTitle", String.class, true, true);
268: infoFactory.addAttribute("portletContext", String.class, true,
269: true);
270: infoFactory.addAttribute("portletList", ArrayList.class, true,
271: true);
272: infoFactory.addReference("PortalContainerServices",
273: PortalContainerServices.class, "GBean");
274: infoFactory.setConstructor(new String[] { "pageTitle",
275: "portletContext", "portletList",
276: "PortalContainerServices" });
277: GBEAN_INFO = infoFactory.getBeanInfo();
278: }
279:
280: public static GBeanInfo getGBeanInfo() {
281: return GBEAN_INFO;
282: }
283:
284: }
|