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 */
017 package org.apache.geronimo.pluto;
018
019 import java.util.ArrayList;
020 import java.util.Collection;
021 import java.util.List;
022
023 import org.apache.commons.logging.Log;
024 import org.apache.commons.logging.LogFactory;
025 import org.apache.geronimo.gbean.GBeanInfo;
026 import org.apache.geronimo.gbean.GBeanInfoBuilder;
027 import org.apache.geronimo.gbean.GBeanLifecycle;
028 import org.apache.pluto.driver.services.portal.PageConfig;
029 import org.apache.pluto.driver.services.portal.PortletWindowConfig;
030 import org.apache.pluto.driver.services.portal.RenderConfigService;
031 import org.apache.pluto.driver.services.portal.admin.RenderConfigAdminService;
032
033 /* GBean for adding an item to the Administration Console's Navigator. Web apps
034 * that contain portlets can add those portlets to the navigator by including
035 * a GBean in their deployment plans like this:
036 *
037 * <gbean name="MyAdminConsoleExtension" class="org.apache.geronimo.pluto.AdminConsoleExtensionGBean">
038 * <attribute name="pageTitle">Hello</attribute>
039 * <attribute name="portletContext">/HelloWorldPortlet</attribute>
040 * <attribute name="portletList">[portlet_id_1, portlet_id_2]</attribute>
041 * </gbean>
042 */
043 public class AdminConsoleExtensionGBean implements GBeanLifecycle {
044 private static final Log log = LogFactory.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 String icon;
050 private final PortalContainerServices portletContainerServices;
051
052 /* Constructor for GBean */
053 public AdminConsoleExtensionGBean(String pageTitle, String portletContext, ArrayList<String> portletList, PortalContainerServices portalContainerServices) {
054 this(pageTitle, portletContext, portletList, null, portalContainerServices);
055 }
056
057 public AdminConsoleExtensionGBean(String pageTitle, String portletContext, ArrayList<String> portletList, String icon, PortalContainerServices portalContainerServices) {
058 super();
059 this.pageTitle = pageTitle;
060 this.portletContext = portletContext;
061 this.portletList = portletList;
062 this.icon = icon;
063 this.portletContainerServices = portalContainerServices;
064 }
065
066 /*
067 * Add the PageConfig to pluto. This will overwrite any existing pages with the same page name
068 * @see org.apache.geronimo.pluto.PlutoAccessInterface#addPage(org.apache.pluto.driver.services.portal.PageConfig)
069 */
070 private void addPage(PageConfig pageConfig) {
071 //Add the new PageConfig to Pluto
072 RenderConfigAdminService renderConfig = portletContainerServices.getAdminConfiguration().getRenderConfigAdminService();
073 renderConfig.addPage(pageConfig);
074 }
075
076 /*
077 * This will add the portlets to the PageConfig in Pluto.
078 * @see org.apache.geronimo.pluto.PlutoAccessInterface#addPortlets(java.lang.String, java.lang.String, java.util.ArrayList)
079 */
080 private void addPortlets() {
081 if (pageExists()) {
082 PageConfig pageConfig = getPageConfigFromPluto();
083 int portletCount = portletList.size();
084 for (int i = 0; i < portletCount; i++) {
085 pageConfig.addPortlet(portletContext, portletList.get(i));
086 }
087 } else {
088 log.warn("Cannot add portlets to non-existent page " + pageTitle);
089 }
090 }
091
092 /*
093 * Removes a PageConfig object in Pluto with the pageTitle
094 * @see org.apache.geronimo.pluto.PlutoAccessInterface#removePage(java.lang.String)
095 */
096 private void removePage() {
097 //all we really need is a PageConfig with the page name
098 PageConfig pageConfig = createPageConfig();
099
100 RenderConfigAdminService renderConfig = portletContainerServices.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.parseContextPath(pid);
127 String pletName = PortletWindowConfig.parsePortletName(pid);
128 if (portletContext.equals(pletContext) && portletName.equals(pletName)) {
129 pageConfig.removePortlet(pid);
130 break;
131 }
132 }
133 }
134 } else {
135 log.warn("can't remove portlets from non-existent page " + pageTitle);
136 }
137 }
138
139 /*
140 * Creates a new PageConfig object with this GBean's pageTitle
141 */
142 private PageConfig createPageConfig() {
143 //Create a new PageConfig
144 PageConfig pageConfig = new PageConfig();
145 pageConfig.setName(pageTitle);
146 pageConfig.setUri("/WEB-INF/themes/default-theme.jsp");
147 pageConfig.setIcon(icon);
148 return pageConfig;
149 }
150
151 /*
152 * Gets the PageConfig object from Pluto with that name
153 */
154 private PageConfig getPageConfigFromPluto() {
155 RenderConfigService service = portletContainerServices.getRenderConfigService();
156
157 return service.getPage(pageTitle);
158 }
159
160 /*
161 * return true if Pluto contains a PageConfig with that name, else false
162 */
163 private boolean pageExists() {
164 if (pageTitle == null) return false;
165
166 RenderConfigService service = portletContainerServices.getRenderConfigService();
167
168 List<PageConfig> pageConfigs = service.getPages();
169 for (PageConfig pageConfig : pageConfigs) {
170 if (pageTitle.equals(pageConfig.getName())) {
171 return true;
172 }
173 }
174
175 return false;
176 }
177
178 /*
179 * returns true if Pluto contains a PageConfig with that name and it has 0 or if there isn't a page with that name
180 */
181 private boolean pageIsEmpty() {
182 if (pageExists()) {
183 PageConfig pageConfig = getPageConfigFromPluto();
184 return pageConfig.getPortletIds().size() == 0;
185 } else {
186 log.debug("no pageConfig found for " + pageTitle);
187 return true;
188 }
189 }
190
191 /*
192 * Called when the GBean is started
193 * This adds/updates a Page in Pluto according to this GBean's specifications (ACE)
194 * @see org.apache.geronimo.gbean.GBeanLifecycle#doStart()
195 */
196 public synchronized void doStart() throws Exception {
197 // check to make sure that a portal driver has registered with the container services
198 if (portletContainerServices.getAdminConfiguration() == null) {
199 throw new RuntimeException("No portal driver has been registered with the portal container services");
200 }
201
202 //add the page if it doesn't exist yet
203 if (!pageExists()) {
204 //create a PageConfig
205 PageConfig newPageConfig = createPageConfig();
206 addPage(newPageConfig);
207 }
208
209 //add portlets to this newly created page
210 addPortlets();
211 log.debug("Started AdminConsoleExtensionGBean for " + pageTitle);
212 }
213
214 /*
215 * Called when the GBean is stopped
216 * This removes/updates a Page in Pluto according to this GBean's specifications
217 * @see org.apache.geronimo.gbean.GBeanLifecycle#doStop()
218 */
219 public synchronized void doStop() throws Exception {
220 try {
221 //remove portlets from the page
222 removePortlets();
223
224 //if the page has 0 portlets on it, then go ahead and remove it
225 if (pageIsEmpty()) {
226 removePage();
227 }
228 } catch (NullPointerException e) {
229 // during normal server shutdown the portal driver has been shut down before
230 // the admin console extensions. the way that pluto is currently implemented
231 // is that when the portal driver shuts down it destroys all its services.
232 // this leads to an NPE when you try to use them. currently there is no
233 // way to check to see if a service has been shut down.
234 log.debug("could not remove portlets for " + pageTitle, e);
235 }
236
237 log.debug("Stopped AdminConsoleExtensionGBean for " + pageTitle);
238 }
239
240 /*
241 * Called when the GBean fails
242 * @see org.apache.geronimo.gbean.GBeanLifecycle#doFail()
243 */
244 public synchronized void doFail() {
245 log.warn("AdminConsoleExtensionGBean for " + pageTitle + " failed.");
246 }
247
248 /*
249 * Standard GBean information
250 */
251 static {
252 GBeanInfoBuilder infoFactory = new GBeanInfoBuilder("AdminConsoleExtensionGBean", AdminConsoleExtensionGBean.class);
253 infoFactory.addAttribute("pageTitle", String.class, true, true);
254 infoFactory.addAttribute("portletContext", String.class, true, true);
255 infoFactory.addAttribute("portletList", ArrayList.class, true, true);
256 infoFactory.addAttribute("icon", String.class, true, true);
257 infoFactory.addReference("PortalContainerServices", PortalContainerServices.class, "GBean");
258 infoFactory.setConstructor(new String[]{
259 "pageTitle",
260 "portletContext",
261 "portletList",
262 "icon",
263 "PortalContainerServices"});
264 GBEAN_INFO = infoFactory.getBeanInfo();
265 }
266
267 public static GBeanInfo getGBeanInfo() {
268 return GBEAN_INFO;
269 }
270
271 }