001/*
002 * Copyright 2002-2016 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.portlet.handler;
018
019import java.util.Collections;
020import java.util.Enumeration;
021import java.util.Locale;
022import java.util.Map;
023import java.util.ResourceBundle;
024import javax.portlet.Portlet;
025import javax.portlet.PortletConfig;
026import javax.portlet.PortletContext;
027import javax.portlet.PortletException;
028import javax.xml.XMLConstants;
029import javax.xml.namespace.QName;
030
031import org.springframework.beans.BeansException;
032import org.springframework.beans.factory.BeanInitializationException;
033import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
034import org.springframework.web.portlet.context.PortletConfigAware;
035import org.springframework.web.portlet.context.PortletContextAware;
036
037/**
038 * {@link org.springframework.beans.factory.config.BeanPostProcessor}
039 * that applies initialization and destruction callbacks to beans that
040 * implement the {@link javax.portlet.Portlet} interface.
041 *
042 * <p>After initialization of the bean instance, the Portlet {@code init}
043 * method will be called with a PortletConfig that contains the bean name
044 * of the Portlet and the PortletContext that it is running in.
045 *
046 * <p>Before destruction of the bean instance, the Portlet {@code destroy}
047 * will be called.
048 *
049 * <p><b>Note that this post-processor does not support Portlet initialization
050 * parameters.</b> Bean instances that implement the Portlet interface are
051 * supposed to be configured like any other Spring bean, that is, through
052 * constructor arguments or bean properties.
053 *
054 * <p>For reuse of a Portlet implementation in a plain Portlet container
055 * and as a bean in a Spring context, consider deriving from Spring's
056 * {@link org.springframework.web.portlet.GenericPortletBean} base class that
057 * applies Portlet initialization parameters as bean properties, supporting
058 * both the standard Portlet and the Spring bean initialization style.
059 *
060 * <p><b>Alternatively, consider wrapping a Portlet with Spring's
061 * {@link org.springframework.web.portlet.mvc.PortletWrappingController}.</b>
062 * This is particularly appropriate for existing Portlet classes,
063 * allowing to specify Portlet initialization parameters etc.
064 *
065 * @author Juergen Hoeller
066 * @author John A. Lewis
067 * @since 2.0
068 * @see javax.portlet.Portlet
069 * @see javax.portlet.PortletConfig
070 * @see SimplePortletHandlerAdapter
071 * @see org.springframework.web.portlet.GenericPortletBean
072 * @see org.springframework.web.portlet.mvc.PortletWrappingController
073 */
074public class SimplePortletPostProcessor
075        implements DestructionAwareBeanPostProcessor, PortletContextAware, PortletConfigAware {
076
077        private boolean useSharedPortletConfig = true;
078
079        private PortletContext portletContext;
080
081        private PortletConfig portletConfig;
082
083
084        /**
085         * Set whether to use the shared PortletConfig object passed in
086         * through {@code setPortletConfig}, if available.
087         * <p>Default is "true". Turn this setting to "false" to pass in
088         * a mock PortletConfig object with the bean name as portlet name,
089         * holding the current PortletContext.
090         * @see #setPortletConfig
091         */
092        public void setUseSharedPortletConfig(boolean useSharedPortletConfig) {
093                this.useSharedPortletConfig = useSharedPortletConfig;
094        }
095
096        @Override
097        public void setPortletContext(PortletContext portletContext) {
098                this.portletContext = portletContext;
099        }
100
101        @Override
102        public void setPortletConfig(PortletConfig portletConfig) {
103                this.portletConfig = portletConfig;
104        }
105
106
107        @Override
108        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
109                return bean;
110        }
111
112        @Override
113        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
114                if (bean instanceof Portlet) {
115                        PortletConfig config = this.portletConfig;
116                        if (config == null || !this.useSharedPortletConfig) {
117                                config = new DelegatingPortletConfig(beanName, this.portletContext, this.portletConfig);
118                        }
119                        try {
120                                ((Portlet) bean).init(config);
121                        }
122                        catch (PortletException ex) {
123                                throw new BeanInitializationException("Portlet.init threw exception", ex);
124                        }
125                }
126                return bean;
127        }
128
129        @Override
130        public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
131                if (bean instanceof Portlet) {
132                        ((Portlet) bean).destroy();
133                }
134        }
135
136        @Override
137        public boolean requiresDestruction(Object bean) {
138                return (bean instanceof Portlet);
139        }
140
141
142        /**
143         * Internal implementation of the PortletConfig interface, to be passed
144         * to the wrapped servlet.
145         */
146        private static class DelegatingPortletConfig implements PortletConfig {
147
148                private final String portletName;
149
150                private final PortletContext portletContext;
151
152                private final PortletConfig portletConfig;
153
154                public DelegatingPortletConfig(String portletName, PortletContext portletContext, PortletConfig portletConfig) {
155                        this.portletName = portletName;
156                        this.portletContext = portletContext;
157                        this.portletConfig = portletConfig;
158                }
159
160                @Override
161                public String getPortletName() {
162                        return this.portletName;
163                }
164
165                @Override
166                public PortletContext getPortletContext() {
167                        return this.portletContext;
168                }
169
170                @Override
171                public String getInitParameter(String paramName) {
172                        return null;
173                }
174
175                @Override
176                public Enumeration<String> getInitParameterNames() {
177                        return Collections.enumeration(Collections.<String>emptySet());
178                }
179
180                @Override
181                public ResourceBundle getResourceBundle(Locale locale) {
182                        return (this.portletConfig != null ? this.portletConfig.getResourceBundle(locale) : null);
183                }
184
185                @Override
186                public Enumeration<String> getPublicRenderParameterNames() {
187                        return Collections.enumeration(Collections.<String>emptySet());
188                }
189
190                @Override
191                public String getDefaultNamespace() {
192                        return XMLConstants.NULL_NS_URI;
193                }
194
195                @Override
196                public Enumeration<QName> getPublishingEventQNames() {
197                        return Collections.enumeration(Collections.<QName>emptySet());
198                }
199
200                @Override
201                public Enumeration<QName> getProcessingEventQNames() {
202                        return Collections.enumeration(Collections.<QName>emptySet());
203                }
204
205                @Override
206                public Enumeration<Locale> getSupportedLocales() {
207                        return Collections.enumeration(Collections.<Locale>emptySet());
208                }
209
210                @Override
211                public Map<String, String[]> getContainerRuntimeOptions() {
212                        return (this.portletConfig != null ? this.portletConfig.getContainerRuntimeOptions() : null);
213                }
214        }
215
216}