/*
* Copyright 2010 NCHOVY
*
* 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.krakenapps.rpc.impl;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.krakenapps.rpc.RpcAsyncResult;
import org.krakenapps.rpc.RpcAsyncTable;
import org.krakenapps.rpc.RpcException;
import org.krakenapps.rpc.RpcMessage;
import org.krakenapps.rpc.RpcWaitingCall;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RpcAsyncTableImpl implements RpcAsyncTable {
private final Logger logger = LoggerFactory.getLogger(RpcAsyncTableImpl.class.getName());
private Map<Integer, RpcWaitingCall> callMap;
public RpcAsyncTableImpl() {
callMap = new ConcurrentHashMap<Integer, RpcWaitingCall>();
}
@Override
public Collection<RpcWaitingCall> getWaitingCalls() {
return Collections.unmodifiableCollection(callMap.values());
}
@Override
public boolean contains(int id) {
return callMap.containsKey(id);
}
@Override
public void cancel(int id) {
callMap.remove(id);
}
@Override
public void signal(int id, RpcMessage response) {
if (logger.isDebugEnabled())
logger.debug("kraken-rpc: signal call response {}", id);
RpcWaitingCallImpl item = (RpcWaitingCallImpl) callMap.get(id);
if (item == null) {
if (logger.isDebugEnabled())
logger.debug("kraken-rpc: no waiting item {}, maybe canceled", id);
return;
}
// invoke callback
Object type = response.getHeader("type");
String method = response.getString("method");
RpcAsyncResult asyncResult = item.result;
if (type.equals("rpc-error")) {
String cause = response.getString("cause");
if (logger.isDebugEnabled())
logger.debug("kraken-rpc: catching exception for id {}, method {}", id, method);
asyncResult.setException(new RpcException(cause));
}
if (type.equals("rpc-ret")) {
if (logger.isDebugEnabled())
logger.debug("kraken-rpc: response for id {}, method {}", id, method);
asyncResult.setReturn(response.get("ret"));
}
item.result.getCallback().onComplete(asyncResult);
}
@Override
public void submit(int id, RpcAsyncResult result) {
if (result == null)
throw new IllegalArgumentException("callback should not null");
callMap.put(id, new RpcWaitingCallImpl(id, result));
}
private static class RpcWaitingCallImpl implements RpcWaitingCall {
private int id;
private Date since;
private RpcAsyncResult result = null;
public RpcWaitingCallImpl(int id, RpcAsyncResult result) {
this.id = id;
this.result = result;
this.since = new Date();
}
@Override
public int getId() {
return id;
}
@Override
public Date getSince() {
return since;
}
@Override
public void done(RpcMessage result) {
throw new UnsupportedOperationException();
}
@Override
public void await(int timeout) throws InterruptedException {
throw new UnsupportedOperationException();
}
@Override
public RpcMessage getResult() {
throw new UnsupportedOperationException();
}
@Override
public String toString() {
return String.format("id=%s, since=%s", id, since.toString());
}
}
}