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.cocoon.portal.reading;
018:
019: import java.io.IOException;
020: import java.io.InputStream;
021: import java.net.HttpURLConnection;
022: import java.net.URL;
023: import java.util.Enumeration;
024: import java.util.Map;
025:
026: import org.apache.avalon.framework.parameters.Parameters;
027: import org.apache.cocoon.ProcessingException;
028: import org.apache.cocoon.environment.ObjectModelHelper;
029: import org.apache.cocoon.environment.Request;
030: import org.apache.cocoon.environment.Response;
031: import org.apache.cocoon.environment.SourceResolver;
032: import org.apache.cocoon.portal.coplet.CopletInstanceData;
033: import org.apache.cocoon.portal.transformation.ProxyTransformer;
034: import org.apache.cocoon.reading.ServiceableReader;
035: import org.apache.cocoon.util.NetUtils;
036: import org.xml.sax.SAXException;
037:
038: /**
039: * This reader is used to retrieve non XML content from external applications
040: * routet via the portal site. Requests from external resources are marked with
041: * a proxy prefix and have coplet id and portal name attached as request
042: * parameters. The portal name and coplet id are used to look up necessary
043: * connection data for the external request (like session id, cookies,
044: * document base, etc.) from the application coplet instance data.
045: *
046: * @author <a href="mailto:gernot.koller@rizit.at">Gernot Koller</a>
047: * @author <a href="mailto:friedrich.klenner@rzb.at">Friedrich Klenner</a>
048: *
049: * @version CVS $Id: ProxyReader.java 433543 2006-08-22 06:22:54Z crossley $
050: */
051: public class ProxyReader extends ServiceableReader {
052:
053: /**
054: * The coplet instance data
055: */
056: protected CopletInstanceData copletInstanceData;
057:
058: /**
059: * The HTTP response
060: */
061: protected Response response;
062:
063: /**
064: * The origninal HTTP request
065: */
066: protected Request request;
067:
068: /** The prefix */
069: protected String prefix;
070:
071: /**
072: * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(SourceResolver, Map, String, Parameters)
073: */
074: public void setup(SourceResolver resolver, Map objectModel,
075: String src, Parameters par) throws ProcessingException,
076: SAXException, IOException {
077: super .setup(resolver, objectModel, src, par);
078:
079: request = ObjectModelHelper.getRequest(objectModel);
080: response = ObjectModelHelper.getResponse(objectModel);
081:
082: String copletID = request
083: .getParameter(ProxyTransformer.COPLETID);
084: String portalName = request
085: .getParameter(ProxyTransformer.PORTALNAME);
086:
087: copletInstanceData = ProxyTransformer.getInstanceData(
088: this .manager, copletID, portalName);
089: this .prefix = par.getParameter("prefix",
090: ProxyTransformer.PROXY_PREFIX);
091: }
092:
093: /**
094: * @see org.apache.avalon.excalibur.pool.Recyclable#recycle()
095: */
096: public void recycle() {
097: this .response = null;
098: this .request = null;
099: this .copletInstanceData = null;
100: super .recycle();
101: }
102:
103: /**
104: * Send the request to the external WebServer
105: * @throws IOException on any exception that occures
106: * @see org.apache.cocoon.reading.Reader#generate()
107: */
108: public void generate() throws IOException {
109: String link = request.getRequestURI();
110: link = link.substring(link.indexOf(this .prefix)
111: + this .prefix.length());
112:
113: String documentBase = (String) copletInstanceData
114: .getAttribute(ProxyTransformer.DOCUMENT_BASE);
115: String remoteURI = null;
116:
117: remoteURI = ProxyTransformer.resolveURI(link, documentBase);
118:
119: HttpURLConnection connection = connect(request, remoteURI);
120: copyHeaderFields(connection, response);
121: sendData(connection.getInputStream());
122: }
123:
124: /**
125: * Copy the data to the original response stream
126: * @param in the response from external request to read from
127: * @throws IOException on any exception
128: */
129: protected void sendData(InputStream in) throws IOException {
130: int length = -1;
131: byte[] buf = new byte[4096];
132:
133: while ((length = in.read(buf)) > -1) {
134: out.write(buf, 0, length);
135: }
136: out.flush();
137: in.close();
138: }
139:
140: /**
141: * Establish the HttpURLConnection to the given uri.
142: * @param request the original request
143: * @param uri the remote uri
144: * @return the established HttpURLConnection
145: * @throws IOException on any exception
146: */
147: protected HttpURLConnection connect(Request request, String uri)
148: throws IOException {
149: String cookie = (String) copletInstanceData
150: .getAttribute(ProxyTransformer.COOKIE);
151:
152: Enumeration enumeration = request.getParameterNames();
153:
154: boolean firstattribute = true;
155: StringBuffer query = new StringBuffer();
156:
157: while (enumeration.hasMoreElements()) {
158: String paramName = (String) enumeration.nextElement();
159:
160: if (!paramName.startsWith("cocoon-portal-")) {
161:
162: String[] paramValues = request
163: .getParameterValues(paramName);
164:
165: for (int i = 0; i < paramValues.length; i++) {
166: if (firstattribute) {
167: query.append('?');
168: firstattribute = false;
169: } else {
170: query.append('&');
171: }
172:
173: query.append(NetUtils.encode(paramName, "utf-8"));
174: query.append('=');
175: query.append(NetUtils.encode(paramValues[i],
176: "utf-8"));
177:
178: }
179: }
180: }
181:
182: uri = uri + query.toString();
183:
184: URL url = new URL(uri);
185: HttpURLConnection connection = (HttpURLConnection) url
186: .openConnection();
187: connection.setInstanceFollowRedirects(true);
188:
189: if (cookie != null) {
190: connection.setRequestProperty(ProxyTransformer.COOKIE,
191: cookie);
192: }
193:
194: connection.connect();
195:
196: copletInstanceData.setAttribute(ProxyTransformer.COOKIE,
197: connection.getHeaderField(ProxyTransformer.COOKIE));
198:
199: return connection;
200: }
201:
202: /**
203: * Copy header fields from external response to original response.
204: * @param connection the connection to the external resource
205: * @param response the original HTTP response.
206: */
207: private void copyHeaderFields(HttpURLConnection connection,
208: Response response) {
209: String[] fieldNames = new String[] { "Content-Range",
210: "Accept-Ranges", "Content-Length", "Last-Modified",
211: "Content-Type", "Expires" };
212: for (int i = 0; i < fieldNames.length; i++) {
213: String value = connection.getHeaderField(fieldNames[i]);
214: if (value != null) {
215: response.setHeader(fieldNames[i], value);
216: }
217:
218: }
219: }
220: }
|