Java tutorial
/* * 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.synapse.transport.passthru.api; import org.apache.axis2.AxisFault; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.MessageContext; import org.apache.axis2.description.AxisService; import org.apache.axis2.wsdl.WSDLConstants; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.nio.NHttpServerConnection; import org.apache.http.nio.entity.ContentOutputStream; import org.apache.http.nio.util.SimpleOutputBuffer; import org.apache.http.protocol.HTTP; import org.apache.synapse.transport.nhttp.NHttpConfiguration; import org.apache.synapse.transport.nhttp.NhttpConstants; import org.apache.synapse.transport.passthru.HttpGetRequestProcessor; import org.apache.synapse.transport.passthru.PassThroughConstants; import org.apache.synapse.transport.passthru.ProtocolState; import org.apache.synapse.transport.passthru.SourceContext; import org.apache.synapse.transport.passthru.SourceHandler; import org.apache.ws.commons.schema.XmlSchema; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; public class PassThroughNHttpGetProcessor implements HttpGetRequestProcessor { private static final Log log = LogFactory.getLog(PassThroughNHttpGetProcessor.class); private static final String LOCATION = "Location"; private static final String CONTENT_TYPE = "Content-Type"; private static final String TEXT_HTML = "text/html"; private static final String TEXT_XML = "text/xml"; private static final String PASS_THROUGH_RESPONSE_SOURCE_BUFFER = "synapse.response-source-buffer"; private static final String GET_REQUEST_HANDLED = "GET_REQUEST_HANDLED"; protected ConfigurationContext cfgCtx; protected SourceHandler sourceHandler; public void init(ConfigurationContext cfgCtx, SourceHandler handler) throws AxisFault { this.cfgCtx = cfgCtx; this.sourceHandler = handler; } public void process(HttpRequest request, HttpResponse response, MessageContext msgContext, NHttpServerConnection conn, OutputStream ostream, boolean isRestDispatching) { String uri = request.getRequestLine().getUri(); String serviceName = getServiceName(request); Map<String, String> parameters = new HashMap<String, String>(); int pos = uri.indexOf("?"); if (pos != -1) { msgContext.setTo(new EndpointReference(uri.substring(0, pos))); StringTokenizer st = new StringTokenizer(uri.substring(pos + 1), "&"); while (st.hasMoreTokens()) { String param = st.nextToken(); pos = param.indexOf("="); if (pos != -1) { parameters.put(param.substring(0, pos), param.substring(pos + 1)); } else { parameters.put(param, null); } } } else { msgContext.setTo(new EndpointReference(uri)); } SimpleOutputBuffer outputBuffer = (SimpleOutputBuffer) conn.getContext() .getAttribute(PASS_THROUGH_RESPONSE_SOURCE_BUFFER); ContentOutputStream os = new ContentOutputStream(outputBuffer); if (isServiceListBlocked(uri)) { sendResponseAndFinish(response, HttpStatus.SC_FORBIDDEN, conn, os, msgContext); } else if (uri.equals("/favicon.ico")) { response.addHeader(LOCATION, "http://ws.apache.org/favicon.ico"); sendResponseAndFinish(response, HttpStatus.SC_MOVED_PERMANENTLY, conn, os, msgContext); } else if (serviceName != null && parameters.containsKey("wsdl")) { generateWsdl(response, msgContext, conn, os, serviceName, parameters); } else if (serviceName != null && parameters.containsKey("wsdl2")) { generateWsdl2(response, msgContext, conn, os, serviceName); } else if (serviceName != null && parameters.containsKey("xsd")) { generateXsd(response, msgContext, conn, os, serviceName, parameters); } else { msgContext.setProperty(PassThroughConstants.REST_GET_DELETE_INVOKE, true); } } private void sendResponseAndFinish(HttpResponse response, int status, NHttpServerConnection conn, OutputStream os, MessageContext msgContext) { response.setStatusCode(status); SourceContext.updateState(conn, ProtocolState.WSDL_RESPONSE_DONE); sourceHandler.commitResponseHideExceptions(conn, response); closeOutputStream(os); msgContext.setProperty(GET_REQUEST_HANDLED, Boolean.TRUE); } private void sendResponseAndFinish(HttpResponse response, byte[] data, NHttpServerConnection conn, OutputStream os, MessageContext msgContext) throws IOException { SourceContext.updateState(conn, ProtocolState.WSDL_RESPONSE_DONE); sourceHandler.commitResponseHideExceptions(conn, response); write(conn, os, data); closeOutputStream(os); msgContext.setProperty(GET_REQUEST_HANDLED, Boolean.TRUE); } private void closeOutputStream(OutputStream os) { try { os.flush(); os.close(); } catch (IOException ignore) { } } /** * Generate WSDL. * * @param response * HttpResponse * @param msgContext * MessageContext * @param conn * NHttpServerConnection * @param os * OutputStream * @param serviceName * service name * @param parameters * parameters */ protected void generateWsdl(HttpResponse response, MessageContext msgContext, NHttpServerConnection conn, OutputStream os, String serviceName, Map<String, String> parameters) { AxisService service = cfgCtx.getAxisConfiguration().getServices().get(serviceName); if (service != null) { try { ByteArrayOutputStream output = new ByteArrayOutputStream(); String parameterValue = parameters.get("wsdl"); if (parameterValue == null) { service.printWSDL(output, getIpAddress()); } else { // here the parameter value should be the wsdl file name service.printUserWSDL(output, parameterValue); } response.addHeader(CONTENT_TYPE, TEXT_XML); sendResponseAndFinish(response, output.toByteArray(), conn, os, msgContext); } catch (Exception e) { handleBrowserException(response, msgContext, conn, os, "Error generating ?wsdl output for service : " + serviceName, e); } } else { if (log.isDebugEnabled()) { log.debug("Unable to find service: " + serviceName + " for WSDL generation."); } msgContext.setProperty(PassThroughConstants.REST_GET_DELETE_INVOKE, true); } } /** * Generate WSDL2. * * @param response * HttpResponse * @param msgContext * MessageContext * @param conn * NHttpServerConnection * @param os * OutputStream * @param serviceName * service name */ protected void generateWsdl2(HttpResponse response, MessageContext msgContext, NHttpServerConnection conn, OutputStream os, String serviceName) { AxisService service = cfgCtx.getAxisConfiguration().getServices().get(serviceName); if (service != null) { String parameterValue = (String) service.getParameterValue("serviceType"); if ("proxy".equals(parameterValue) && !isWSDLProvidedForProxyService(service)) { handleBrowserException(response, msgContext, conn, os, "No WSDL was provided for the Service " + serviceName + ". A WSDL cannot be generated.", null); } try { ByteArrayOutputStream output = new ByteArrayOutputStream(); service.printWSDL2(output, getIpAddress()); response.addHeader(CONTENT_TYPE, TEXT_XML); sendResponseAndFinish(response, output.toByteArray(), conn, os, msgContext); } catch (Exception e) { handleBrowserException(response, msgContext, conn, os, "Error generating ?wsdl2 output for service : " + serviceName, e); } } else { msgContext.setProperty(PassThroughConstants.REST_GET_DELETE_INVOKE, true); } } /** * Returns the service name. * * @param request * HttpRequest * @return service name as a String */ protected String getServiceName(HttpRequest request) { String uri = request.getRequestLine().getUri(); String servicePath = cfgCtx.getServiceContextPath(); if (!servicePath.startsWith("/")) { servicePath = "/" + servicePath; } String serviceName = null; if (uri.startsWith(servicePath)) { serviceName = uri.substring(servicePath.length()); if (serviceName.startsWith("/")) { serviceName = serviceName.substring(1); } if (serviceName.contains("?")) { serviceName = serviceName.substring(0, serviceName.indexOf("?")); } } else { // this may be a custom URI String incomingURI = request.getRequestLine().getUri(); Map serviceURIMap = (Map) cfgCtx.getProperty(NhttpConstants.EPR_TO_SERVICE_NAME_MAP); if (serviceURIMap != null) { Set keySet = serviceURIMap.keySet(); for (Object key : keySet) { if (incomingURI.toLowerCase().contains(((String) key).toLowerCase())) { return (String) serviceURIMap.get(key); } } } } if (serviceName != null) { int opnStart = serviceName.indexOf("/"); if (opnStart != -1) { serviceName = serviceName.substring(0, opnStart); } } return serviceName; } /** * Generates Schema. * * @param response * HttpResponse * @param msgContext * Current MessageContext * @param conn * NHttpServerConnection * @param os * OutputStream * @param serviceName * service name * @param parameters * url parameters */ protected void generateXsd(HttpResponse response, MessageContext msgContext, NHttpServerConnection conn, OutputStream os, String serviceName, Map<String, String> parameters) { if (parameters.get("xsd") == null || "".equals(parameters.get("xsd"))) { AxisService service = cfgCtx.getAxisConfiguration().getServices().get(serviceName); if (service != null) { try { ByteArrayOutputStream output = new ByteArrayOutputStream(); service.printSchema(output); response.addHeader(CONTENT_TYPE, TEXT_XML); sendResponseAndFinish(response, output.toByteArray(), conn, os, msgContext); } catch (Exception e) { handleBrowserException(response, msgContext, conn, os, "Error generating ?xsd output for service : " + serviceName, e); } } else { msgContext.setProperty(PassThroughConstants.REST_GET_DELETE_INVOKE, true); } } else { // cater for named XSDs - check for the xsd name String schemaName = parameters.get("xsd"); AxisService service = cfgCtx.getAxisConfiguration().getServices().get(serviceName); if (service != null) { // run the population logic just to be sure service.populateSchemaMappings(); // write out the correct schema Map schemaTable = service.getSchemaMappingTable(); XmlSchema schema = (XmlSchema) schemaTable.get(schemaName); if (schema == null) { int dotIndex = schemaName.indexOf('.'); if (dotIndex > 0) { String schemaKey = schemaName.substring(0, dotIndex); schema = (XmlSchema) schemaTable.get(schemaKey); } } // schema found - write it to the stream if (schema != null) { try { ByteArrayOutputStream output = new ByteArrayOutputStream(); schema.write(output); response.addHeader(CONTENT_TYPE, TEXT_XML); sourceHandler.commitResponseHideExceptions(conn, response); write(conn, os, output.toByteArray()); closeOutputStream(os); msgContext.setProperty(GET_REQUEST_HANDLED, Boolean.TRUE); } catch (Exception e) { handleBrowserException(response, msgContext, conn, os, "Error generating named ?xsd output for service : " + serviceName, e); } } else { // no schema available by that name - send 404 response.setStatusCode(HttpStatus.SC_NOT_FOUND); closeOutputStream(os); msgContext.setProperty(GET_REQUEST_HANDLED, Boolean.TRUE); } } else { msgContext.setProperty(PassThroughConstants.REST_GET_DELETE_INVOKE, true); } } } /** * Handles browser exception. * * @param response HttpResponse * @param conn NHttpServerConnection * @param os OutputStream * @param msg message * @param e Exception */ protected void handleBrowserException(HttpResponse response, MessageContext msgContext, NHttpServerConnection conn, OutputStream os, String msg, Exception e) { if (e == null) { log.error(msg); } else { log.error(msg, e); } if (!response.containsHeader(HTTP.TRANSFER_ENCODING)) { response.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR); response.setReasonPhrase(msg); response.addHeader(CONTENT_TYPE, TEXT_HTML); sourceHandler.commitResponseHideExceptions(conn, response); try { write(conn, os, msg.getBytes()); os.close(); } catch (IOException ignore) { } } if (conn != null) { try { conn.shutdown(); } catch (IOException ignore) { } } msgContext.setProperty(GET_REQUEST_HANDLED, Boolean.TRUE); } /** * Is the incoming URI is requesting service list and * http.block_service_list=true in nhttp.properties * * @param incomingURI * incoming URI * @return whether to proceed with incomingURI */ protected boolean isServiceListBlocked(String incomingURI) { String isBlocked = NHttpConfiguration.getInstance().isServiceListBlocked(); return (("/services").equals(incomingURI) || ("/services" + "/").equals(incomingURI)) && Boolean.parseBoolean(isBlocked); } /** * Checks whether a wsdl is provided for a proxy service. * * @param service AxisService * @return whether the wsdl is provided or not */ protected boolean isWSDLProvidedForProxyService(AxisService service) { boolean isWSDLProvided = false; if (service.getParameterValue(WSDLConstants.WSDL_4_J_DEFINITION) != null || service.getParameterValue(WSDLConstants.WSDL_20_DESCRIPTION) != null) { isWSDLProvided = true; } return isWSDLProvided; } /** * Whatever this method returns as the IP is ignored by the actual http/s listener when * its getServiceEPR is invoked. This was originally copied from axis2 * * @return Returns String. * @throws java.net.SocketException if the socket can not be accessed */ protected static String getIpAddress() throws SocketException { Enumeration e = NetworkInterface.getNetworkInterfaces(); String address = "127.0.0.1"; while (e.hasMoreElements()) { NetworkInterface networkInterface = (NetworkInterface) e.nextElement(); Enumeration addresses = networkInterface.getInetAddresses(); while (addresses.hasMoreElements()) { InetAddress ip = (InetAddress) addresses.nextElement(); if (!ip.isLoopbackAddress() && isIP(ip.getHostAddress())) { return ip.getHostAddress(); } } } return address; } protected static boolean isIP(String hostAddress) { return hostAddress.split("[.]").length == 4; } private void write(NHttpServerConnection conn, OutputStream os, byte[] data) throws IOException { synchronized (conn.getContext()) { // The SimpleOutputBuffer on which this output stream is based is not thread safe. // Explicit synchronization required. // Do not worry about running out of buffer space. // SimpleOutputBuffer expands to fit the data. os.write(data); } } }