/**
*
* Copyright 2004-2005 The Apache Software Foundation
*
* Licensed 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.geronimo.interop.rmi.iiop.server;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import org.apache.geronimo.interop.SystemException;
import org.apache.geronimo.interop.adapter.Adapter;
import org.apache.geronimo.interop.adapter.AdapterManager;
import org.apache.geronimo.interop.naming.NameService;
import org.apache.geronimo.interop.rmi.iiop.BadMagicException;
import org.apache.geronimo.interop.rmi.iiop.CdrInputStream;
import org.apache.geronimo.interop.rmi.iiop.CdrOutputStream;
import org.apache.geronimo.interop.rmi.iiop.GiopMessage;
import org.apache.geronimo.interop.rmi.iiop.ObjectInputStream;
import org.apache.geronimo.interop.rmi.iiop.ObjectOutputStream;
import org.apache.geronimo.interop.rmi.iiop.UnsupportedProtocolVersionException;
import org.apache.geronimo.interop.util.UTF8;
import org.omg.GIOP.KeyAddr;
import org.omg.GIOP.LocateReplyHeader_1_2;
import org.omg.GIOP.LocateRequestHeader_1_2;
import org.omg.GIOP.LocateStatusType_1_2;
import org.omg.GIOP.MsgType_1_1;
import org.omg.GIOP.ProfileAddr;
import org.omg.GIOP.ReferenceAddr;
import org.omg.GIOP.ReplyHeader_1_2;
import org.omg.GIOP.ReplyStatusType_1_2;
import org.omg.GIOP.RequestHeader_1_2;
import org.omg.GIOP.TargetAddress;
import org.omg.IOP.ServiceContext;
public class MessageHandler {
private AdapterManager adapterManager;
private boolean simpleIDL;
private boolean writeSystemExceptionStackTrace;
private NameService nameService = NameService.getInstance();
public MessageHandler( AdapterManager adapterManager, boolean simpleIDL,
boolean writeSystemExceptionStackTrace )
{
this.adapterManager = adapterManager;
this.simpleIDL = simpleIDL;
this.writeSystemExceptionStackTrace = writeSystemExceptionStackTrace;
}
public void service(Socket socket) throws Exception {
InputStream in;
OutputStream out;
String clientHostName;
String clientHostAddress;
String clientInfo;
in = socket.getInputStream();
out = socket.getOutputStream();
InetAddress addr = socket.getInetAddress();
clientHostName = addr.getHostName();
clientHostAddress = addr.getHostAddress();
clientInfo = clientHostName;
if (!clientHostAddress.equals(clientHostName)) {
clientInfo += " (" + clientHostAddress + ")";
}
boolean firstMessage = true;
CdrInputStream input = CdrInputStream.getInstance();
CdrOutputStream output = CdrOutputStream.getInstance();
CdrOutputStream results = CdrOutputStream.getInstance();
for (; ;) {
boolean sendResponse = true;
GiopMessage inputMessage;
try {
inputMessage = input.receive_message( in, clientInfo );
firstMessage = false;
} catch (BadMagicException ex) {
if (firstMessage) {
warnBadMagic(clientInfo, ex);
} else {
warnBadMagicBadSize(clientInfo, ex);
}
closeStreams( in, out );
return;
} catch (UnsupportedProtocolVersionException ex) {
warnGiopVersion( clientInfo, ex);
closeStreams( in, out );
return;
} catch (Exception ex) {
if (input.getOffset() > 0) {
ex.printStackTrace();
warnReceiveFailed( clientInfo, ex);
}
// Otherwise client shutdown was not in the middle of a
// request, i.e. probably 'normal' and unworthy of a
// log message.
closeStreams( in, out );
return;
}
output.setGiopVersion(input.getGiopVersion());
switch (inputMessage.type) {
case MsgType_1_1._Request:
processRequest(input, output, results, inputMessage.request, clientInfo);
if ((inputMessage.request.response_flags & 1) == 0) {
sendResponse = false; // oneway request
}
break;
case MsgType_1_1._LocateRequest:
processLocateRequest(output, inputMessage.locateRequest);
break;
default:
throw new SystemException("TODO: message type = " + inputMessage.type);
}
if (sendResponse) {
try {
if(inputMessage.httpTunneling)
{
output.send_http_response( out, clientInfo );
}
else
{
output.send_message( out, clientInfo );
}
} catch (Exception ex) {
warnSendFailed(clientInfo, ex);
closeStreams( in, out );
return;
}
}
input.reset();
output.reset();
results.reset();
}
}
protected void closeStreams( InputStream in, OutputStream out ) {
try {
if (in != null) {
in.close();
}
} catch (Exception ignore) {
}
try {
if (out != null) {
out.close();
}
} catch (Exception ignore) {
}
}
protected byte[] getObjectKey(TargetAddress target) {
switch (target.discriminator()) {
case KeyAddr.value:
return target.object_key();
case ProfileAddr.value:
case ReferenceAddr.value:
throw new SystemException("TODO");
default:
throw new IllegalArgumentException("target discriminator = " + target.discriminator());
}
}
protected void processRequest(CdrInputStream parameters,
CdrOutputStream output,
CdrOutputStream results,
RequestHeader_1_2 request,
String clientInfo
) {
byte[] objectKey = getObjectKey(request.target);
int keyLength = objectKey.length;
int keyType = keyLength == 0 ? 0 : objectKey[0];
ReplyHeader_1_2 reply = new ReplyHeader_1_2();
reply.request_id = request.request_id;
ObjectInputStream objectIn;
ObjectOutputStream objectOut;
if (simpleIDL || keyType == 'N' || keyType == 'J') {
// Name Service and JMS use simple IDL interoperability.
objectIn = org.apache.geronimo.interop.rmi.iiop.SimpleObjectInputStream.getInstance(parameters);
objectOut = org.apache.geronimo.interop.rmi.iiop.SimpleObjectOutputStream.getInstance(results);
} else {
// Otherwise use RMI-IIOP interoperability.
objectIn = org.apache.geronimo.interop.rmi.iiop.ObjectInputStream.getInstance(parameters);
objectOut = org.apache.geronimo.interop.rmi.iiop.ObjectOutputStream.getInstance(results);
}
try {
String objectName = null;
for (int colonPos = 0; colonPos < keyLength; colonPos++) {
if (objectKey[colonPos] == ':') {
objectName = UTF8.toString(objectKey, 0, colonPos);
int newKeyLength = keyLength - colonPos - 1;
byte[] newObjectKey = new byte[newKeyLength];
System.arraycopy(objectKey, colonPos + 1, newObjectKey, 0, newKeyLength);
objectKey = newObjectKey;
break;
}
}
if (objectName == null) {
objectName = UTF8.toString(objectKey);
}
processServiceContext(request);
Object object;
try
{
object = nameService.lookup(objectName);
}
catch (javax.naming.NameNotFoundException notFound)
{
warnLookupFailed(clientInfo, notFound);
throw new org.omg.CORBA.OBJECT_NOT_EXIST(objectName);
}
Adapter adapter = (Adapter)object;
if (adapter != null)
{
adapter.invoke(request.operation, objectKey, objectIn, objectOut);
if (objectOut.hasException()) {
reply.reply_status = ReplyStatusType_1_2.USER_EXCEPTION;
} else {
reply.reply_status = ReplyStatusType_1_2.NO_EXCEPTION;
}
output.write_reply(reply, results);
} else {
throw new org.omg.CORBA.OBJECT_NOT_EXIST(objectName);
}
} catch (Exception ex) {
warnSystemException(clientInfo, ex);
results = CdrOutputStream.getInstance(); // in case we already wrote to it
results.write_SystemException(ex, writeSystemExceptionStackTrace);
reply.reply_status = ReplyStatusType_1_2.SYSTEM_EXCEPTION;
output.write_reply(reply, results);
}
}
protected void processLocateRequest(CdrOutputStream output, LocateRequestHeader_1_2 request) {
// Fake LocateReply, pretend we host any object.
// Since we never move objects, this is sufficient.
LocateReplyHeader_1_2 reply = new LocateReplyHeader_1_2();
reply.request_id = request.request_id;
reply.locate_status = LocateStatusType_1_2.OBJECT_HERE;
output.write_reply(reply);
}
protected void processServiceContext(RequestHeader_1_2 request) {
ServiceContext[] contextList = request.service_context;
int n = contextList.length;
String username = null;
String password = null;
for (int i = 0; i < n; i++) {
ServiceContext context = contextList[i];
int tag = context.context_id;
/*
if (tag == SecurityInfo.TAG_USERNAME)
{
username = SecurityInfo.decode(context.context_data);
}
else if (tag == SecurityInfo.TAG_PASSWORD)
{
password = SecurityInfo.decode(context.context_data);
}
*/
// TODO: Is the ServiceContext a CSIv2 Security Context?
}
}
// log methods
protected void warnBadMagic(String clientHost, Exception ex) {
System.out.println("MH.warnBadMagic: clientHost: " + clientHost + ", ex = " + ex);
}
protected void warnBadMagicBadSize(String clientHost, Exception ex) {
System.out.println("MH.warnBadMagicBadSize: clientHost: " + clientHost + ", ex = " + ex);
}
protected void warnGiopVersion(String clientHost, Exception ex) {
System.out.println("MH.warnGiopVersion: clientHost: " + clientHost + ", ex = " + ex);
}
protected void warnInvokeFailedNoRemoteInterface(String clientHost, Object object, Class type) {
System.out.println("MH.warnInvokeFailedNoRemoteInterface: clientHost: " + clientHost + ", object = " + object + ", type: " + type);
}
protected void warnLookupFailed(String clientHost, Exception ex) {
System.out.println("MH.warnLookupFailed: clientHost: " + clientHost + ", ex = " + ex);
}
protected void warnReceiveFailed(String clientHost, Exception ex) {
System.out.println("MH.warnReceiveFailed: clientHost: " + clientHost + ", ex = " + ex);
}
protected void warnSendFailed(String clientHost, Exception ex) {
System.out.println("MH.warnSendFailed: clientHost: " + clientHost + ", ex = " + ex);
}
protected void warnSystemException(String clientHost, Exception ex) {
System.out.println("MH.warnSystemException: clientHost: " + clientHost + ", ex = " + ex);
}
}