blob: 599752c5c71904199c3522371b3ea60aabba22fc [file] [log] [blame]
/*
* Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.corba.se.impl.transport;
import java.util.Iterator;
import java.util.List;
import org.omg.CORBA.COMM_FAILURE;
import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.INTERNAL;
import org.omg.CORBA.SystemException;
import com.sun.corba.se.pept.transport.ContactInfo ;
import com.sun.corba.se.pept.transport.ContactInfoList ;
import com.sun.corba.se.spi.ior.IOR ;
import com.sun.corba.se.spi.logging.CORBALogDomains;
import com.sun.corba.se.spi.orb.ORB ;
import com.sun.corba.se.spi.transport.CorbaContactInfo;
import com.sun.corba.se.spi.transport.CorbaContactInfoList;
import com.sun.corba.se.spi.transport.CorbaContactInfoListIterator;
import com.sun.corba.se.spi.transport.IIOPPrimaryToContactInfo;
import com.sun.corba.se.impl.logging.ORBUtilSystemException;
import com.sun.corba.se.impl.protocol.CorbaInvocationInfo;
// REVISIT: create a unit test for this class.
public class CorbaContactInfoListIteratorImpl
implements
CorbaContactInfoListIterator
{
protected ORB orb;
protected CorbaContactInfoList contactInfoList;
protected CorbaContactInfo successContactInfo;
protected CorbaContactInfo failureContactInfo;
protected RuntimeException failureException;
// ITERATOR state
protected Iterator effectiveTargetIORIterator;
protected CorbaContactInfo previousContactInfo;
protected boolean isAddrDispositionRetry;
protected IIOPPrimaryToContactInfo primaryToContactInfo;
protected ContactInfo primaryContactInfo;
protected List listOfContactInfos;
// End ITERATOR state
public CorbaContactInfoListIteratorImpl(
ORB orb,
CorbaContactInfoList corbaContactInfoList,
ContactInfo primaryContactInfo,
List listOfContactInfos)
{
this.orb = orb;
this.contactInfoList = corbaContactInfoList;
this.primaryContactInfo = primaryContactInfo;
if (listOfContactInfos != null) {
// listOfContactInfos is null when used by the legacy
// socket factory. In that case this iterator is NOT used.
this.effectiveTargetIORIterator = listOfContactInfos.iterator();
}
// List is immutable so no need to synchronize access.
this.listOfContactInfos = listOfContactInfos;
this.previousContactInfo = null;
this.isAddrDispositionRetry = false;
this.successContactInfo = null;
this.failureContactInfo = null;
this.failureException = null;
primaryToContactInfo = orb.getORBData().getIIOPPrimaryToContactInfo();
}
////////////////////////////////////////////////////
//
// java.util.Iterator
//
public boolean hasNext()
{
// REVISIT: Implement as internal closure iterator which would
// wraps sticky or default. Then hasNext and next just call
// the closure.
if (isAddrDispositionRetry) {
return true;
}
boolean result;
if (primaryToContactInfo != null) {
result = primaryToContactInfo.hasNext(primaryContactInfo,
previousContactInfo,
listOfContactInfos);
} else {
result = effectiveTargetIORIterator.hasNext();
}
return result;
}
public Object next()
{
if (isAddrDispositionRetry) {
isAddrDispositionRetry = false;
return previousContactInfo;
}
// We hold onto the last in case we get an addressing
// disposition retry. Then we use it again.
// We also hold onto it for the sticky manager.
if (primaryToContactInfo != null) {
previousContactInfo = (CorbaContactInfo)
primaryToContactInfo.next(primaryContactInfo,
previousContactInfo,
listOfContactInfos);
} else {
previousContactInfo = (CorbaContactInfo)
effectiveTargetIORIterator.next();
}
return previousContactInfo;
}
public void remove()
{
throw new UnsupportedOperationException();
}
////////////////////////////////////////////////////
//
// com.sun.corba.se.pept.transport.ContactInfoListIterator
//
public ContactInfoList getContactInfoList()
{
return contactInfoList;
}
public void reportSuccess(ContactInfo contactInfo)
{
this.successContactInfo = (CorbaContactInfo)contactInfo;
}
public boolean reportException(ContactInfo contactInfo,
RuntimeException ex)
{
this.failureContactInfo = (CorbaContactInfo)contactInfo;
this.failureException = ex;
if (ex instanceof COMM_FAILURE) {
SystemException se = (SystemException) ex;
if (se.completed == CompletionStatus.COMPLETED_NO) {
if (hasNext()) {
return true;
}
if (contactInfoList.getEffectiveTargetIOR() !=
contactInfoList.getTargetIOR())
{
// retry from root ior
updateEffectiveTargetIOR(contactInfoList.getTargetIOR());
return true;
}
}
}
return false;
}
public RuntimeException getFailureException()
{
if (failureException == null) {
return
ORBUtilSystemException.get( orb,
CORBALogDomains.RPC_TRANSPORT )
.invalidContactInfoListIteratorFailureException();
} else {
return failureException;
}
}
////////////////////////////////////////////////////
//
// spi.CorbaContactInfoListIterator
//
public void reportAddrDispositionRetry(CorbaContactInfo contactInfo,
short disposition)
{
previousContactInfo.setAddressingDisposition(disposition);
isAddrDispositionRetry = true;
}
public void reportRedirect(CorbaContactInfo contactInfo,
IOR forwardedIOR)
{
updateEffectiveTargetIOR(forwardedIOR);
}
////////////////////////////////////////////////////
//
// Implementation.
//
//
// REVISIT:
//
// The normal operation for a standard iterator is to throw
// ConcurrentModificationException whenever the underlying collection
// changes. This is implemented by keeping a modification counter (the
// timestamp may fail because the granularity is too coarse).
// Essentially what you need to do is whenever the iterator fails this
// way, go back to ContactInfoList and get a new iterator.
//
// Need to update CorbaClientRequestDispatchImpl to catch and use
// that exception.
//
public void updateEffectiveTargetIOR(IOR newIOR)
{
contactInfoList.setEffectiveTargetIOR(newIOR);
// If we report the exception in _request (i.e., beginRequest
// we cannot throw RemarshalException to the stub because _request
// does not declare that exception.
// To keep the two-level dispatching (first level chooses ContactInfo,
// second level is specific to that ContactInfo/EPT) we need to
// ensure that the request dispatchers get their iterator from the
// InvocationStack (i.e., ThreadLocal). That way if the list iterator
// needs a complete update it happens right here.
((CorbaInvocationInfo)orb.getInvocationInfo())
.setContactInfoListIterator(contactInfoList.iterator());
}
}
// End of file.