001 /* 002 * JBoss, Home of Professional Open Source 003 * Copyright 2012 Red Hat Inc. and/or its affiliates and other contributors 004 * as indicated by the @author tags. All rights reserved. 005 * See the copyright.txt in the distribution for a 006 * full listing of individual contributors. 007 * 008 * This copyrighted material is made available to anyone wishing to use, 009 * modify, copy, or redistribute it subject to the terms and conditions 010 * of the GNU Lesser General Public License, v. 2.1. 011 * This program is distributed in the hope that it will be useful, but WITHOUT A 012 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 013 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 014 * You should have received a copy of the GNU Lesser General Public License, 015 * v.2.1 along with this distribution; if not, write to the Free Software 016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 017 * MA 02110-1301, USA. 018 */ 019 package org.switchyard.remote.http; 020 021 import java.io.OutputStream; 022 import java.net.HttpURLConnection; 023 import java.net.MalformedURLException; 024 import java.net.URL; 025 026 import org.apache.log4j.Logger; 027 import org.switchyard.Context; 028 import org.switchyard.Exchange; 029 import org.switchyard.ExchangePattern; 030 import org.switchyard.Message; 031 import org.switchyard.Property; 032 import org.switchyard.Scope; 033 import org.switchyard.internal.DefaultContext; 034 import org.switchyard.remote.RemoteInvoker; 035 import org.switchyard.remote.RemoteMessage; 036 import org.switchyard.serial.FormatType; 037 import org.switchyard.serial.Serializer; 038 import org.switchyard.serial.SerializerFactory; 039 import org.switchyard.transform.TransformSequence; 040 041 /** 042 * Remote service invoker which uses HTTP as a transport. 043 */ 044 public class HttpInvoker implements RemoteInvoker { 045 046 /** 047 * HTTP header used to communicate the domain name for a service invocation. 048 */ 049 public static final String SERVICE_HEADER = "switchyard-service"; 050 051 private static Logger _log = Logger.getLogger(HttpInvoker.class); 052 private Serializer _serializer = SerializerFactory.create(FormatType.JSON, null, true); 053 private URL _endpoint; 054 055 /** 056 * Create a new HttpInvoker from the specified URL string. 057 * @param endpoint url string 058 */ 059 public HttpInvoker(String endpoint) { 060 try { 061 _endpoint = new URL(endpoint); 062 } catch (MalformedURLException badURL) { 063 throw new IllegalArgumentException( 064 "Invalid URL for remote endpoint: " + endpoint, badURL); 065 } 066 } 067 068 /** 069 * Create a new HttpInvoker with the specified URL. 070 * @param endpoint the endpoint URL 071 */ 072 public HttpInvoker(URL endpoint) { 073 _endpoint = endpoint; 074 } 075 076 @Override 077 public void invoke(Exchange exchange) { 078 RemoteMessage request = new RemoteMessage() 079 .setDomain(exchange.getProvider().getDomain().getName()) 080 .setService(exchange.getProvider().getName()) 081 .setContent(exchange.getMessage().getContent()) 082 .setContext(exchange.getContext()); 083 084 try { 085 RemoteMessage reply = invoke(request); 086 if (isInOut(exchange) && reply != null) { 087 Message msg = exchange.getMessage().setContent(reply.getContent()); 088 if (reply.isFault()) { 089 exchange.sendFault(msg); 090 } else { 091 exchange.send(msg); 092 } 093 } 094 } catch (java.io.IOException ioEx) { 095 ioEx.printStackTrace(); 096 exchange.sendFault(exchange.createMessage().setContent(ioEx)); 097 } 098 } 099 100 @Override 101 public RemoteMessage invoke(RemoteMessage request) throws java.io.IOException { 102 RemoteMessage reply = null; 103 HttpURLConnection conn = null; 104 105 if (_log.isDebugEnabled()) { 106 _log.debug("Invoking " + request.getService() + " at endpoint " + _endpoint.toString()); 107 } 108 109 // Initialize HTTP connection 110 conn = (HttpURLConnection)_endpoint.openConnection(); 111 conn.setDoOutput(true); 112 conn.addRequestProperty(SERVICE_HEADER, request.getService().toString()); 113 conn.connect(); 114 OutputStream os = conn.getOutputStream(); 115 116 // Sanitize context properties 117 Context ctx = cloneContext(request.getContext()); 118 request.setContext(ctx); 119 120 // Write the request message 121 _serializer.serialize(request, RemoteMessage.class, os); 122 os.flush(); 123 os.close(); 124 125 // Check for response and process accordingly 126 if (conn.getResponseCode() == 200) { 127 if (_log.isDebugEnabled()) { 128 _log.debug("Processing reply for service " + request.getService()); 129 } 130 reply = _serializer.deserialize(conn.getInputStream(), RemoteMessage.class); 131 } 132 133 return reply; 134 } 135 136 // Remove troublesome context properties from remote message. 137 private Context cloneContext(Context context) { 138 Context newCtx = new DefaultContext(); 139 // return empty context if context to clone is null 140 if (context == null) { 141 return newCtx; 142 } 143 144 newCtx.setProperties(context.getProperties()); 145 Property inTransform = newCtx.getProperty(TransformSequence.class.getName(), Scope.IN); 146 Property outTransform = newCtx.getProperty(TransformSequence.class.getName(), Scope.OUT); 147 if (inTransform != null) { 148 newCtx.removeProperty(inTransform); 149 } 150 if (outTransform != null) { 151 newCtx.removeProperty(outTransform); 152 } 153 154 return newCtx; 155 } 156 157 private boolean isInOut(Exchange exchange) { 158 return ExchangePattern.IN_OUT.equals( 159 exchange.getContract().getConsumerOperation().getExchangePattern()); 160 } 161 }