package com.sissi.server.exchange.impl; import io.netty.buffer.ByteBuf; import io.netty.util.ReferenceCountUtil; import java.io.OutputStream; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.sissi.commons.Trace; import com.sissi.commons.apache.IOUtil; import com.sissi.context.JIDBuilder; import com.sissi.persistent.Persistent; import com.sissi.pipeline.Transfer; import com.sissi.pipeline.TransferBuffer; import com.sissi.pipeline.TransferBuilder; import com.sissi.pipeline.TransferParam; import com.sissi.protocol.iq.si.Si; import com.sissi.resource.ResourceCounter; import com.sissi.server.exchange.Delegation; import com.sissi.server.exchange.Recall; /** * 离线代理传输 * * @author kim 2014年2月25日 */ public class DegelationTransferBuilder implements TransferBuilder { private final String resoure = this.getClass().getSimpleName(); private final Log log = LogFactory.getLog(this.getClass()); private final ResourceCounter resourceCounter; private final Persistent persistent; private final JIDBuilder jidBuilder; private final Delegation delegation; private final Recall recall; public DegelationTransferBuilder(Persistent persistent, ResourceCounter resourceCounter, Delegation delegation, JIDBuilder jidBuilder, Recall recall) { super(); this.resourceCounter = resourceCounter; this.persistent = persistent; this.delegation = delegation; this.jidBuilder = jidBuilder; this.recall = recall; } @Override public DelegationTransfer build(TransferParam param) { return new DelegationTransfer(param.find(TransferParam.KEY_SI, Si.class)); } private class DelegationTransfer implements Transfer { /** * 已读字节 */ private final AtomicLong readable = new AtomicLong(); /** * 有序锁 */ private final Lock lock = new ReentrantLock(true); private final OutputStream output; private final Si si; public DelegationTransfer(Si si) { super(); this.si = si; this.output = DegelationTransferBuilder.this.delegation.allocate(si.getId()); DegelationTransferBuilder.this.resourceCounter.increment(DegelationTransferBuilder.this.resoure); } @Override public DelegationTransfer transfer(TransferBuffer buffer) { ByteBuf buf = ByteBuf.class.cast(buffer.getBuffer()); try { this.lock.lock(); int readable = buf.readableBytes(); buf.readBytes(this.output, readable); this.readable.addAndGet(readable); return this; } catch (Exception e) { DegelationTransferBuilder.this.log.error(e); Trace.trace(DegelationTransferBuilder.this.log, e); throw new RuntimeException(e); } finally { this.lock.unlock(); if (buf.refCnt() > 0) { ReferenceCountUtil.release(buf); } } } @Override public void close() { IOUtil.closeQuietly(this.output); DegelationTransferBuilder.this.persistent.push(this.si); DegelationTransferBuilder.this.resourceCounter.decrement(DegelationTransferBuilder.this.resoure); DegelationTransferBuilder.this.recall.call(DegelationTransferBuilder.this.jidBuilder.build(si.parent().getTo()).asStringWithBare()); } } }