| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.cocoon.portal.reading; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.HttpURLConnection; |
| import java.net.URL; |
| import java.util.Enumeration; |
| import java.util.Map; |
| |
| import org.apache.avalon.framework.parameters.Parameters; |
| import org.apache.cocoon.ProcessingException; |
| import org.apache.cocoon.environment.ObjectModelHelper; |
| import org.apache.cocoon.environment.Request; |
| import org.apache.cocoon.environment.Response; |
| import org.apache.cocoon.environment.SourceResolver; |
| import org.apache.cocoon.portal.coplet.CopletInstanceData; |
| import org.apache.cocoon.portal.transformation.ProxyTransformer; |
| import org.apache.cocoon.reading.ServiceableReader; |
| import org.apache.cocoon.util.NetUtils; |
| import org.xml.sax.SAXException; |
| |
| /** |
| * This reader is used to retrieve non XML content from external applications |
| * routet via the portal site. Requests from external resources are marked with |
| * a proxy prefix and have coplet id and portal name attached as request |
| * parameters. The portal name and coplet id are used to look up necessary |
| * connection data for the external request (like session id, cookies, |
| * document base, etc.) from the application coplet instance data. |
| * |
| * @author <a href="mailto:gernot.koller@rizit.at">Gernot Koller</a> |
| * @author <a href="mailto:friedrich.klenner@rzb.at">Friedrich Klenner</a> |
| * |
| * @version CVS $Id$ |
| */ |
| public class ProxyReader extends ServiceableReader { |
| |
| /** |
| * The coplet instance data |
| */ |
| protected CopletInstanceData copletInstanceData; |
| |
| /** |
| * The HTTP response |
| */ |
| protected Response response; |
| |
| /** |
| * The origninal HTTP request |
| */ |
| protected Request request; |
| |
| /** The prefix */ |
| protected String prefix; |
| |
| /** |
| * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(SourceResolver, Map, String, Parameters) |
| */ |
| public void setup(SourceResolver resolver, |
| Map objectModel, |
| String src, |
| Parameters par) |
| throws ProcessingException, SAXException, IOException { |
| super.setup(resolver, objectModel, src, par); |
| |
| request = ObjectModelHelper.getRequest(objectModel); |
| response = ObjectModelHelper.getResponse(objectModel); |
| |
| String copletID = request.getParameter(ProxyTransformer.COPLETID); |
| String portalName = request.getParameter(ProxyTransformer.PORTALNAME); |
| |
| copletInstanceData = |
| ProxyTransformer.getInstanceData( |
| this.manager, |
| copletID, |
| portalName); |
| this.prefix = par.getParameter("prefix", ProxyTransformer.PROXY_PREFIX); |
| } |
| |
| /** |
| * @see org.apache.avalon.excalibur.pool.Recyclable#recycle() |
| */ |
| public void recycle() { |
| this.response = null; |
| this.request = null; |
| this.copletInstanceData = null; |
| super.recycle(); |
| } |
| |
| /** |
| * Send the request to the external WebServer |
| * @throws IOException on any exception that occures |
| * @see org.apache.cocoon.reading.Reader#generate() |
| */ |
| public void generate() throws IOException { |
| String link = request.getRequestURI(); |
| link = link.substring(link.indexOf(this.prefix) + this.prefix.length()); |
| |
| String documentBase = |
| (String) copletInstanceData.getAttribute( |
| ProxyTransformer.DOCUMENT_BASE); |
| String remoteURI = null; |
| |
| remoteURI = ProxyTransformer.resolveURI(link, documentBase); |
| |
| HttpURLConnection connection = connect(request, remoteURI); |
| copyHeaderFields(connection, response); |
| sendData(connection.getInputStream()); |
| } |
| |
| /** |
| * Copy the data to the original response stream |
| * @param in the response from external request to read from |
| * @throws IOException on any exception |
| */ |
| protected void sendData(InputStream in) throws IOException { |
| int length = -1; |
| byte[] buf = new byte[4096]; |
| |
| while ((length = in.read(buf)) > -1) { |
| out.write(buf, 0, length); |
| } |
| out.flush(); |
| in.close(); |
| } |
| |
| /** |
| * Establish the HttpURLConnection to the given uri. |
| * @param request the original request |
| * @param uri the remote uri |
| * @return the established HttpURLConnection |
| * @throws IOException on any exception |
| */ |
| protected HttpURLConnection connect(Request request, String uri) |
| throws IOException { |
| String cookie = |
| (String) copletInstanceData.getAttribute(ProxyTransformer.COOKIE); |
| |
| Enumeration enumeration = request.getParameterNames(); |
| |
| boolean firstattribute = true; |
| StringBuffer query = new StringBuffer(); |
| |
| while (enumeration.hasMoreElements()) { |
| String paramName = (String) enumeration.nextElement(); |
| |
| if (!paramName.startsWith("cocoon-portal-")) { |
| |
| String[] paramValues = request.getParameterValues(paramName); |
| |
| for (int i = 0; i < paramValues.length; i++) { |
| if (firstattribute) { |
| query.append('?'); |
| firstattribute = false; |
| } |
| else { |
| query.append('&'); |
| } |
| |
| query.append(NetUtils.encode(paramName, "utf-8")); |
| query.append('='); |
| query.append(NetUtils.encode(paramValues[i], "utf-8")); |
| |
| } |
| } |
| } |
| |
| uri = uri + query.toString(); |
| |
| URL url = new URL(uri); |
| HttpURLConnection connection = (HttpURLConnection) url.openConnection(); |
| connection.setInstanceFollowRedirects(true); |
| |
| if (cookie != null) { |
| connection.setRequestProperty(ProxyTransformer.COOKIE, cookie); |
| } |
| |
| connection.connect(); |
| |
| copletInstanceData.setAttribute( |
| ProxyTransformer.COOKIE, |
| connection.getHeaderField(ProxyTransformer.COOKIE)); |
| |
| return connection; |
| } |
| |
| /** |
| * Copy header fields from external response to original response. |
| * @param connection the connection to the external resource |
| * @param response the original HTTP response. |
| */ |
| private void copyHeaderFields( |
| HttpURLConnection connection, |
| Response response) { |
| String[] fieldNames = |
| new String[] { |
| "Content-Range", |
| "Accept-Ranges", |
| "Content-Length", |
| "Last-Modified", |
| "Content-Type", |
| "Expires" }; |
| for (int i = 0; i < fieldNames.length; i++) { |
| String value = connection.getHeaderField(fieldNames[i]); |
| if (value != null) { |
| response.setHeader(fieldNames[i], value); |
| } |
| |
| } |
| } |
| } |