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.pluto.internal.impl;
018:
019: import org.apache.commons.logging.Log;
020: import org.apache.commons.logging.LogFactory;
021: import org.apache.pluto.PortletContainer;
022: import org.apache.pluto.descriptors.portlet.PortletDD;
023: import org.apache.pluto.descriptors.portlet.SupportsDD;
024: import org.apache.pluto.internal.Configuration;
025: import org.apache.pluto.internal.InternalPortletWindow;
026: import org.apache.pluto.internal.InternalRenderResponse;
027: import org.apache.pluto.spi.PortalCallbackService;
028: import org.apache.pluto.util.ArgumentUtility;
029: import org.apache.pluto.util.NamespaceMapper;
030: import org.apache.pluto.util.StringManager;
031: import org.apache.pluto.util.StringUtils;
032: import org.apache.pluto.util.impl.NamespaceMapperImpl;
033:
034: import javax.portlet.PortletURL;
035: import javax.portlet.RenderResponse;
036: import javax.servlet.http.HttpServletRequest;
037: import javax.servlet.http.HttpServletResponse;
038: import java.io.IOException;
039: import java.io.OutputStream;
040: import java.io.PrintWriter;
041: import java.util.Iterator;
042: import java.util.Locale;
043:
044: /**
045: * Implementation of the <code>javax.portlet.RenderResponse</code> interface.
046: *
047: */
048: public class RenderResponseImpl extends PortletResponseImpl implements
049: RenderResponse, InternalRenderResponse {
050:
051: /**
052: * Logger.
053: */
054: private static final Log LOG = LogFactory
055: .getLog(RenderResponseImpl.class);
056:
057: private static final StringManager EXCEPTIONS = StringManager
058: .getManager(RenderResponseImpl.class.getPackage().getName());
059:
060: // Private Member Variables ------------------------------------------------
061:
062: /**
063: * True if we are in an include call.
064: */
065: private boolean included = false;
066:
067: /**
068: * The current content type.
069: */
070: private String currentContentType;
071:
072: private final NamespaceMapper mapper = new NamespaceMapperImpl();
073:
074: // Constructor -------------------------------------------------------------
075:
076: public RenderResponseImpl(PortletContainer container,
077: InternalPortletWindow internalPortletWindow,
078: HttpServletRequest servletRequest,
079: HttpServletResponse servletResponse) {
080: super (container, internalPortletWindow, servletRequest,
081: servletResponse);
082: }
083:
084: // RenderResponse Impl -----------------------------------------------------
085:
086: public String getContentType() {
087: // NOTE: in servlet 2.4 we could simply use this:
088: // return super.getHttpServletResponse().getContentType();
089: return currentContentType;
090: }
091:
092: public PortletURL createRenderURL() {
093: return createURL(false);
094: }
095:
096: public PortletURL createActionURL() {
097: return createURL(true);
098: }
099:
100: public String getNamespace() {
101: String namespace = mapper.encode(getInternalPortletWindow()
102: .getId(), "");
103: StringBuffer validNamespace = new StringBuffer();
104: for (int i = 0; i < namespace.length(); i++) {
105: char ch = namespace.charAt(i);
106: if (Character.isJavaIdentifierPart(ch)) {
107: validNamespace.append(ch);
108: } else {
109: validNamespace.append('_');
110: }
111: }
112: return validNamespace.toString();
113: }
114:
115: public void setTitle(String title) {
116: PortalCallbackService callback = getContainer()
117: .getRequiredContainerServices()
118: .getPortalCallbackService();
119: callback.setTitle(this .getHttpServletRequest(),
120: getInternalPortletWindow(), title);
121: }
122:
123: public void setContentType(String contentType)
124: throws IllegalArgumentException {
125: ArgumentUtility.validateNotNull("contentType", contentType);
126: String mimeType = StringUtils
127: .getMimeTypeWithoutEncoding(contentType);
128: if (!isValidContentType(mimeType)) {
129: throw new IllegalArgumentException(
130: "Specified content type '" + mimeType
131: + "' is not supported.");
132: }
133: getHttpServletResponse().setContentType(mimeType);
134: this .currentContentType = mimeType;
135: }
136:
137: public String getCharacterEncoding() {
138: return getHttpServletResponse().getCharacterEncoding();
139: }
140:
141: /**
142: * @see PortletResponseImpl#getOutputStream()
143: * @see #getWriter()
144: */
145: public OutputStream getPortletOutputStream() throws IOException,
146: IllegalStateException {
147: if (currentContentType == null) {
148: String message = EXCEPTIONS
149: .getString("error.contenttype.null");
150: if (LOG.isWarnEnabled()) {
151: LOG.warn("Current content type is not set.");
152: }
153: throw new IllegalStateException(message);
154: }
155: return super .getOutputStream();
156: }
157:
158: /**
159: * @see PortletResponseImpl#getWriter()
160: * @see #getPortletOutputStream()
161: */
162: public PrintWriter getWriter() throws IOException,
163: IllegalStateException {
164: if (currentContentType == null) {
165: String message = EXCEPTIONS
166: .getString("error.contenttype.null");
167: if (LOG.isWarnEnabled()) {
168: LOG.warn("Current content type is not set.");
169: }
170: throw new IllegalStateException(message);
171: }
172: return super .getWriter();
173: }
174:
175: public Locale getLocale() {
176: return getHttpServletRequest().getLocale();
177: }
178:
179: public void setBufferSize(int size) {
180: if (Configuration.isBufferingSupported()) {
181: getHttpServletResponse().setBufferSize(size);
182: } else {
183: throw new IllegalStateException(
184: "portlet container does not support buffering");
185: }
186: }
187:
188: public int getBufferSize() {
189: if (Configuration.isBufferingSupported()) {
190: return getHttpServletResponse().getBufferSize();
191: }
192: return 0;
193: }
194:
195: public void flushBuffer() throws IOException {
196: getHttpServletResponse().flushBuffer();
197: }
198:
199: public void resetBuffer() {
200: getHttpServletResponse().resetBuffer();
201: }
202:
203: public boolean isCommitted() {
204: return getHttpServletResponse().isCommitted();
205: }
206:
207: public void reset() {
208: getHttpServletResponse().reset();
209: }
210:
211: // InternalRenderResponse Impl ---------------------------------------------
212:
213: public void setIncluded(boolean included) {
214: this .included = included;
215: }
216:
217: public boolean isIncluded() {
218: return included;
219: }
220:
221: // Included HttpServletResponse (Limited) Impl -----------------------------
222:
223: /**
224: * TODO
225: */
226: public String encodeRedirectUrl(String url) {
227: if (included) {
228: return null;
229: } else {
230: return super .encodeRedirectUrl(url);
231: }
232: }
233:
234: /**
235: * TODO
236: */
237: public String encodeRedirectURL(String url) {
238: if (included) {
239: return null;
240: } else {
241: return super .encodeRedirectURL(url);
242: }
243: }
244:
245: // Private Methods ---------------------------------------------------------
246:
247: /**
248: * Creates a portlet URL.
249: * TODO: make dynamic? as service?
250: *
251: * @param isAction true for an action URL, false for a render URL.
252: * @return the created portlet (action/render) URL.
253: */
254: private PortletURL createURL(boolean isAction) {
255: return new PortletURLImpl(getContainer(),
256: getInternalPortletWindow(), getHttpServletRequest(),
257: getHttpServletResponse(), isAction);
258: }
259:
260: /**
261: * Checks if the specified content type is valid (supported by the portlet).
262: * The specified content type should be a tripped mime type without any
263: * character encoding suffix.
264: *
265: * @param contentType the content type to check.
266: * @return true if the content type is valid, false otherwise.
267: */
268: private boolean isValidContentType(String contentType) {
269: boolean valid = false;
270:
271: PortletDD portletDD = getInternalPortletWindow()
272: .getPortletEntity().getPortletDefinition();
273: for (Iterator it = portletDD.getSupports().iterator(); !valid
274: && it.hasNext();) {
275:
276: SupportsDD supportsDD = (SupportsDD) it.next();
277: String supportedType = supportsDD.getMimeType();
278:
279: // Content type is supported by an exact match.
280: if (supportedType.equals(contentType)) {
281: valid = true;
282: }
283: // The supported type contains a wildcard.
284: else if (supportedType.indexOf("*") >= 0) {
285:
286: int index = supportedType.indexOf("/");
287: String supportedPrefix = supportedType.substring(0,
288: index);
289: String supportedSuffix = supportedType
290: .substring(index + 1);
291:
292: index = contentType.indexOf("/");
293: String typePrefix = contentType.substring(0, index);
294: String typeSuffix = contentType.substring(index + 1);
295:
296: // Check if the prefixes match AND the suffixes match.
297: if (supportedPrefix.equals("*")
298: || supportedPrefix.equals(typePrefix)) {
299: if (supportedSuffix.equals("*")
300: || supportedSuffix.equals(typeSuffix)) {
301: valid = true;
302: }
303: }
304: }
305: }
306: // Return the check result.
307: return valid;
308: }
309:
310: }
|