/* * * * Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com) * * * * 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. * * * * For more information: http://www.orientechnologies.com * */ package com.orientechnologies.orient.server.network.protocol.binary; import com.orientechnologies.common.log.OLogManager; import com.orientechnologies.orient.core.command.OCommandResultListener; import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.exception.OFetchException; import com.orientechnologies.orient.core.fetch.OFetchContext; import com.orientechnologies.orient.core.fetch.OFetchHelper; import com.orientechnologies.orient.core.fetch.remote.ORemoteFetchContext; import com.orientechnologies.orient.core.fetch.remote.ORemoteFetchListener; import com.orientechnologies.orient.core.id.ORID; import com.orientechnologies.orient.core.record.ORecord; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.server.OClientConnection; import java.io.IOException; import java.util.HashSet; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; /** * Asynchronous command result manager. As soon as a record is returned by the command is sent over the wire. * * @author Luca Garulli (l.garulli--at--orientechnologies.com) * */ public class OAsyncCommandResultListener extends OAbstractCommandResultListener { private final ONetworkProtocolBinary protocol; private final AtomicBoolean empty = new AtomicBoolean(true); private final int txId; private final Set<ORID> alreadySent = new HashSet<ORID>(); private final OClientConnection connection; public OAsyncCommandResultListener(OClientConnection connection, final ONetworkProtocolBinary iNetworkProtocolBinary, final int txId, final OCommandResultListener wrappedResultListener) { super(wrappedResultListener); this.protocol = iNetworkProtocolBinary; this.txId = txId; this.connection = connection; } @Override public boolean result(final Object iRecord) { if (empty.compareAndSet(true, false)) try { protocol.sendOk(connection, txId); } catch (IOException ignored) { } try { fetchRecord(iRecord, new ORemoteFetchListener() { @Override protected void sendRecord(ORecord iLinked) { if (!alreadySent.contains(iLinked.getIdentity())) { alreadySent.add(iLinked.getIdentity()); try { protocol.channel.writeByte((byte) 2); // CACHE IT ON THE CLIENT protocol.writeIdentifiable(connection, iLinked); } catch (IOException e) { OLogManager.instance().error(this, "Cannot write against channel", e); } } } }); alreadySent.add(((OIdentifiable) iRecord).getIdentity()); protocol.channel.writeByte((byte) 1); // ONE MORE RECORD protocol.writeIdentifiable(connection, ((OIdentifiable) iRecord).getRecord()); protocol.channel.flush();// TODO review this flush... it's for non blocking... if (wrappedResultListener != null) // NOTIFY THE WRAPPED LISTENER wrappedResultListener.result(iRecord); } catch (IOException e) { return false; } return true; } public boolean isEmpty() { return empty.get(); } @Override public void linkdedBySimpleValue(ODocument doc) { ORemoteFetchListener listener = new ORemoteFetchListener() { @Override protected void sendRecord(ORecord iLinked) { if (!alreadySent.contains(iLinked.getIdentity())) { alreadySent.add(iLinked.getIdentity()); try { protocol.channel.writeByte((byte) 2); // CACHE IT ON THE CLIENT protocol.writeIdentifiable(connection, iLinked); } catch (IOException e) { OLogManager.instance().error(this, "Cannot write against channel", e); } } } @Override public void parseLinked(ODocument iRootRecord, OIdentifiable iLinked, Object iUserObject, String iFieldName, OFetchContext iContext) throws OFetchException { if (iLinked instanceof ORecord) sendRecord((ORecord) iLinked); } @Override public void parseLinkedCollectionValue(ODocument iRootRecord, OIdentifiable iLinked, Object iUserObject, String iFieldName, OFetchContext iContext) throws OFetchException { if (iLinked instanceof ORecord) sendRecord((ORecord) iLinked); } }; final OFetchContext context = new ORemoteFetchContext(); OFetchHelper.fetch(doc, doc, OFetchHelper.buildFetchPlan(""), listener, context, ""); } }