
com.caucho.v5.ramp.hamp.InHamp Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of baratine Show documentation
Show all versions of baratine Show documentation
A reactive Java web server.
/*
* Copyright (c) 1998-2015 Caucho Technology -- all rights reserved
*
* This file is part of Baratine(TM)
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Baratine is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Baratine is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Baratine; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.v5.ramp.hamp;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.caucho.v5.amp.AmpException;
import com.caucho.v5.amp.ServicesAmp;
import com.caucho.v5.amp.ServiceRefAmp;
import com.caucho.v5.amp.message.HeadersNull;
import com.caucho.v5.amp.message.SendMessage_N;
import com.caucho.v5.amp.message.StreamCallMessage;
import com.caucho.v5.amp.message.StreamResultMessage;
import com.caucho.v5.amp.remote.ChannelAmp;
import com.caucho.v5.amp.remote.GatewayReply;
import com.caucho.v5.amp.remote.GatewayReplyBase;
import com.caucho.v5.amp.remote.QueryGatewayReadMessage_N;
import com.caucho.v5.amp.service.MethodRefError;
import com.caucho.v5.amp.service.ServiceRefLazyInvalid;
import com.caucho.v5.amp.service.ServiceRefNull;
import com.caucho.v5.amp.spi.HeadersAmp;
import com.caucho.v5.amp.spi.InboxAmp;
import com.caucho.v5.amp.spi.MethodRefAmp;
import com.caucho.v5.amp.spi.OutboxAmp;
import com.caucho.v5.amp.spi.QueryRefAmp;
import com.caucho.v5.amp.spi.ShutdownModeAmp;
import com.caucho.v5.h3.H3;
import com.caucho.v5.h3.InH3;
import com.caucho.v5.h3.OutFactoryH3;
import com.caucho.v5.http.pod.PodContainer;
import com.caucho.v5.ramp.jamp.InAmpWebSocket;
import com.caucho.v5.util.Hex;
import com.caucho.v5.util.L10N;
import io.baratine.service.ServiceException;
import io.baratine.stream.ResultStream;
/**
* HmtpReader stream handles client packets received from the server.
*/
public class InHamp implements InAmpWebSocket
{
private static final L10N L = new L10N(InHamp.class);
private static final Logger log
= Logger.getLogger(InHamp.class.getName());
private final ChannelAmp _channelIn;
private String _id;
private InputStream _is;
//private Hessian2StreamingInput _in;
private InH3 _hIn;
private int _methodCacheIndex;
private MethodRefHamp []_methodCacheRing = new MethodRefHamp[256];
private int _toAddressCacheIndex;
private ServiceRefAmp []_toAddressCacheRing = new ServiceRefAmp[256];
private int _fromAddressCacheIndex;
private GatewayReply []_fromAddressCacheRing = new GatewayReply[256];
private ServicesAmp _ampManager;
//private Supplier _outboxFactory;
private final Level _logLevel = Level.FINEST;
// private final Level _logLevel = Level.FINER;
private long _queueTimeout = 1000L;
private int _dId;
private OutFactoryH3 _serializer;
private PodContainer _podContainer;
private static AtomicInteger _idGen = new AtomicInteger();
public InHamp(ServicesAmp rampManager,
ChannelAmp channel)
{
_ampManager = rampManager;
//_outboxFactory = rampManager.outboxFactory();
if (_ampManager.isClosed()) {
throw new IllegalStateException(String.valueOf(_ampManager));
}
_channelIn = channel;
_serializer = H3.newOutFactory().get();
//_hIn = new Hessian2Input();
//_hIn.setSerializerFactory(_factory);
if (channel == null) {
throw new IllegalStateException("HampReader requires a valid channel for callbacks");
}
//_outbox = _channelIn.createOutbox();
//_outbox.setInbox(rampManager.getSystemInbox());
//_outbox.setMessage(rampManager.getSystemMessage());
//_outbox = new OutboxAmpContextImpl();
//_outbox.setInbox(rampManager.getSystemInbox());
//_outbox.setMessage(rampManager.getSystemMessage());
_podContainer = PodContainer.getCurrent();
_dId = _idGen.incrementAndGet();
}
/*
private ClassLoader loadClassLoaderJar(String pathName)
{
if (pathName == null
|| ! pathName.startsWith("bfs:///system/lambda")
|| ! pathName.endsWith(".jar")) {
return null;
}
Path path = Vfs.lookup(pathName);
ClassLoader loader = SimpleLoader.create(path);
return loader;
}
*/
protected ServicesAmp getManager()
{
return _ampManager;
}
private InboxAmp getInboxCaller()
{
return _ampManager.inboxSystem();
}
public void setId(String id)
{
_id = id;
}
public void init(InputStream is)
{
//_hIn.reset();
_hIn = _serializer.in(is);
/*
_is = is;
if (log.isLoggable(Level.FINEST)) {
HessianDebugInputStream hIs
= new HessianDebugInputStream(is, log, Level.FINEST);
hIs.startStreaming();
is = hIs;
}
private Hessian2Input _hIn = new Hessian2Input();
_in = new Hessian2StreamingInput(is);
*/
}
/**
* Returns true if buffered read data is already available, i.e.
* the read stream will not block.
*/
public boolean isDataAvailable()
{
//return _in != null && _in.isDataAvailable();
return _hIn != null;
}
/**
* Reads the next HMTP packet from the stream, returning false on
* end of file.
*/
public boolean readMessage(InputStream is)
throws IOException
{
Thread thread = Thread.currentThread();
ClassLoader loader = thread.getContextClassLoader();
try (OutboxAmp outbox = OutboxAmp.currentOrCreate(getManager())) {
return readMessage(is, outbox);
} catch (Throwable e) {
log.log(Level.WARNING, e.toString(), e);
throw e;
} finally {
thread.setContextClassLoader(loader);
}
}
/**
* Reads the next HMTP packet from the stream, returning false on
* end of file.
*/
public boolean readMessage(InputStream is, OutboxAmp outbox)
throws IOException
{
InH3 hIn = _hIn;
if (is.available() < 0) {
return false;
}
//hIn.initPacket(is);
try {
return readMessage(hIn, outbox);
} finally {
//outbox.setInbox(null);
}
}
private boolean readMessage(InH3 hIn,
OutboxAmp outbox)
throws IOException
{
int type;
try {
type = (int) hIn.readLong();
} catch (Exception e) {
log.log(_logLevel, e.getMessage() + " (in " + this + ")");
throw e;
}
outbox.inbox(_ampManager.inboxSystem());
Thread thread = Thread.currentThread();
HeadersAmp headers = readHeaders(hIn);
switch (MessageTypeHamp.TYPES[type]) {
case SEND:
{
readSend(hIn, outbox, headers);
break;
}
case QUERY:
{
readQuery(hIn, outbox, headers);
//ServiceRef.flushOutbox();
break;
}
case QUERY_RESULT:
{
readQueryResult(hIn, headers);
break;
}
case QUERY_ERROR:
{
ServiceRefAmp serviceRef = readToAddress(hIn);
long id = hIn.readLong();
QueryRefAmp queryRef = serviceRef.removeQueryRef(id);
if (queryRef != null) {
ClassLoader loader = queryRef.getClassLoader();
thread.setContextClassLoader(loader);
// XXX: _serializer.setClassLoader(loader);
}
String code = hIn.readString();
String msg = hIn.readString();
Object detail = hIn.readObject();
if (log.isLoggable(_logLevel)) {
log.log(_logLevel, "query-error " + code + " " + msg + " (in " + this + ")"
+ "\n {id:" + id + ", to:" + serviceRef + "," + headers + "}");
}
if (queryRef == null) {
log.warning(L.l("Expected queryRef for {0} and qid {1}",
serviceRef, id));
}
else if (detail instanceof Throwable) {
queryRef.fail(headers, AmpException.createAndRethrow((Throwable) detail));
}
else {
AmpException exn = new AmpException(msg);
exn.fillInStackTrace();
queryRef.fail(headers, exn);
}
break;
}
case STREAM:
{
readStream(hIn, outbox, headers);
break;
}
case STREAM_RESULT:
{
readStreamResult(hIn, headers);
break;
}
case STREAM_CANCEL:
{
readStreamCancel(hIn, headers);
break;
}
default:
throw new UnsupportedOperationException("ERROR: " + type + " "+ MessageTypeHamp.TYPES[type]);
}
// ServiceRef.flushOutbox();
return true;
}
/**
* The send message is a on-way call to a service.
*/
private boolean readSend(InH3 hIn,
OutboxAmp outbox,
HeadersAmp headers)
throws IOException
{
MethodRefHamp methodHamp = null;
try {
methodHamp = readMethod(hIn);
} catch (Throwable e) {
log.log(Level.FINER, e.toString(), e);
skipArgs(hIn);
return true;
}
MethodRefAmp method = methodHamp.getMethod();
//ClassLoader loader = method.getService().getManager().getClassLoader();
ClassLoader loader = methodHamp.getClassLoader();
Thread thread = Thread.currentThread();
thread.setContextClassLoader(loader);
// XXX: _serializer.setClassLoader(loader);
Object []args = readArgs(methodHamp, hIn);
if (log.isLoggable(_logLevel)) {
log.log(_logLevel, this + " send-r " + method.getName() + debugArgs(args)
+ " {to:" + method + ", " + headers + "}");
}
// XXX: s/b systemMailbox
SendMessage_N sendMessage
= new SendMessage_N(outbox,
headers,
method.serviceRef(), method.method(),
args);
long timeout = 1000L; // mailbox delay timeout
try {
//sendMessage.offer(timeout);
//sendMessage.offerQueue(timeout);
// // sendMessage.getWorker().wake();
sendMessage.offer(timeout);
} catch (Throwable e) {
log.fine(e.toString());
if (log.isLoggable(Level.FINEST)) {
log.log(Level.FINEST, e.toString(), e);
}
}
return true;
}
/**
* The query message is a RPC call to a service.
*/
private void readQuery(InH3 hIn,
OutboxAmp outbox,
HeadersAmp headers)
throws IOException
{
GatewayReply from = readFromAddress(hIn);
long qid = hIn.readLong();
long timeout = 120 * 1000L;
/*
AmpQueryRef queryRef
= new QueryItem(NullMethodRef.NULL, _context, headers, timeout);
*/
MethodRefHamp methodHamp = null;
MethodRefAmp methodRef = null;
try {
try {
methodHamp = readMethod(hIn);
} catch (Throwable e) {
skipArgs(hIn);
throw e;
}
methodRef = methodHamp.getMethod();
ClassLoader loader = methodHamp.getClassLoader();
Thread thread = Thread.currentThread();
thread.setContextClassLoader(loader);
// XXX: _serializer.setClassLoader(loader);
Object []args = readArgs(methodHamp, hIn);
QueryGatewayReadMessage_N msg
= new QueryGatewayReadMessage_N(outbox,
getInboxCaller(),
headers,
from, qid,
methodRef.serviceRef(),
methodRef.method(),
timeout, args);
//msg.offer(_queueTimeout);
//msg.offerQueue(_queueTimeout);
// msg.getWorker().wake();
msg.offer(_queueTimeout);
//outbox.flush();
if (log.isLoggable(_logLevel)) {
log.log(_logLevel, "hamp-query " + methodRef.getName() + " " + debugArgs(args)
+ " (in " + this + ")"
+ "\n {qid:" + qid + ", to:" + methodRef.serviceRef() + ", from:" + from + "," + headers + "}");
}
} catch (Throwable e) {
if (log.isLoggable(Level.FINE)) {
log.fine("hamp-query error " + e
+ " (in " + this + ")"
+ "\n {id:" + qid + ", from:" + from + "," + headers + "," + methodRef + "}");
}
if (log.isLoggable(Level.FINER)) {
log.log(Level.FINER, e.toString(), e);
}
ServiceRefAmp serviceRef = getInboxCaller().serviceRef();
MethodRefError methodErr;
if (methodRef == null) {
methodErr = new MethodRefError(serviceRef, "unknown-method");
}
else {
methodErr = new MethodRefError(serviceRef, methodRef.getName());
}
QueryGatewayReadMessage_N queryRef
= new QueryGatewayReadMessage_N(outbox,
getInboxCaller(),
headers,
from, qid,
serviceRef, methodErr.method(),
timeout, null);
queryRef.toSent();
// queryRef.failed(headers, e);
//System.out.println("FAIL: " + e);
if (e instanceof ServiceException) {
queryRef.fail(e);
outbox.flush();
}
else {
HampException exn = new HampException(L.l("{0}\n while reading {1}", e.toString(), methodRef), e);
queryRef.fail(exn);
}
}
}
/**
* query reply parsing
*
*
* ["reply", {headers}, "from", qid, value]
*
*
* @param hIn the hessian input stream
* @param headers the message's headers
*/
private void readQueryResult(InH3 hIn, HeadersAmp headers)
throws IOException
{
ServiceRefAmp serviceRef = readToAddress(hIn);
long id = hIn.readLong();
QueryRefAmp queryRef = serviceRef.removeQueryRef(id);
if (queryRef != null) {
ClassLoader loader = queryRef.getClassLoader();
Thread thread = Thread.currentThread();
thread.setContextClassLoader(loader);
// XXX: _serializer.setClassLoader(loader);
}
else {
// XX: _serializer.setClassLoader(null);
}
Object value = hIn.readObject();
if (log.isLoggable(_logLevel)) {
log.log(_logLevel, "query-result-r " + value + " (in " + this + ")"
+ "\n {id:" + id + ", to:" + serviceRef + "," + headers + "}");
}
if (queryRef != null) {
queryRef.complete(headers, value);
}
else if (log.isLoggable(Level.WARNING)) {
log.warning("query-result qid=" + id + " for service " + serviceRef +
" does not match any known queries.\n" + headers);
}
}
private void readStream(InH3 hIn,
OutboxAmp outbox,
HeadersAmp headers)
throws IOException
{
GatewayReply from = readFromAddress(hIn);
long qid = hIn.readLong();
long timeout = 120 * 1000L;
/*
AmpQueryRef queryRef
= new QueryItem(NullMethodRef.NULL, _context, headers, timeout);
*/
MethodRefHamp methodHamp = null;
MethodRefAmp method = null;
try {
// String jarPath = hIn.readString();
// ClassLoader loader = loadClassLoaderJar(jarPath);
//if (loader != null) {
// thread.setContextClassLoader(loader);
//}
try {
methodHamp = readMethod(hIn);
} catch (Throwable e) {
hIn.readObject();
skipArgs(hIn);
throw e;
}
ClassLoader loader = methodHamp.getClassLoader();
Thread thread = Thread.currentThread();
thread.setContextClassLoader(loader);
// XXX: _serializer.setClassLoader(loader);
ResultStream
© 2015 - 2025 Weber Informatics LLC | Privacy Policy