/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
/*
* RMSource.java
*
* @author Mike Grogan
* Created on October 15, 2005, 6:24 PM
*/
package com.sun.xml.ws.rm.jaxws.runtime.client;
import com.sun.xml.ws.rm.Message;
import com.sun.xml.ws.rm.RMException;
import com.sun.xml.ws.rm.jaxws.runtime.RMProvider;
import com.sun.xml.ws.rm.jaxws.runtime.SequenceConfig;
import javax.xml.namespace.QName;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import com.sun.xml.ws.rm.Constants;
import java.util.logging.Logger;
import java.util.logging.Level;
/**
* An RMSource represents a Collection of RMSequences with a
* common acksTo endpoint.
*/
public class RMSource extends RMProvider<ClientInboundSequence,
ClientOutboundSequence> {
private static final Logger logger =
Logger.getLogger(RMSource.class.getName());
private static RMSource rmSource = new RMSource();
public static RMSource getRMSource() {
return rmSource;
}
private long retryInterval;
private RetryTimer retryTimer;
public RMSource() {
retryInterval = 2000;
retryTimer = new RetryTimer(this);
}
public void setRetryInterval(long retryInterval) {
this.retryInterval = retryInterval;
}
public long getRetryInterval() {
return retryInterval;
}
public synchronized void terminateSequence(ClientOutboundSequence seq)
throws RMException {
String id = seq.getId();
if (seq != null && outboundMap.keySet().contains(id)) {
seq.disconnect();
removeOutboundSequence(id);
}
}
public synchronized void addOutboundSequence(ClientOutboundSequence seq) {
logger.fine(Messages.ADDING_SEQUENCE_MESSAGE.format(seq.getId()));
boolean firstSequence = outboundMap.isEmpty();
outboundMap.put(seq.getId(), seq);
ClientInboundSequence iseq =
(ClientInboundSequence)seq.getInboundSequence();
String iseqid = null;
if (iseq != null && null != (iseqid = iseq.getId())) {
inboundMap.put(iseqid, iseq);
}
if (firstSequence) {
retryTimer.start();
}
}
public synchronized void removeOutboundSequence(ClientOutboundSequence seq) {
logger.fine(Messages.REMOVING_SEQUENCE_MESSAGE.format( seq.getId()));
String id = seq.getId();
ClientInboundSequence iseq =
(ClientInboundSequence)seq.getInboundSequence();
String iseqid = null;
if (iseq != null && null != (iseqid = iseq.getId())) {
inboundMap.remove(iseqid);
}
outboundMap.remove(id);
if (outboundMap.isEmpty()) {
retryTimer.stop();
}
}
private void removeOutboundSequence(String id) {
ClientOutboundSequence seq = outboundMap.get(id);
if (seq != null) {
removeOutboundSequence(seq);
} else {
String message = Messages.NO_SUCH_OUTBOUND_SEQUENCE.format(id);
IllegalArgumentException e = new IllegalArgumentException(message);
logger.log(Level.FINE, message, e);
throw e;
}
}
/**
* Do the necessary maintenance tasks for each <code>ClientInboundSequence</code>
* managed by this RMSource. This is done by calling the <code>doMaintenanceTasks</code>
* method of each managed sequence.
*
* @throws RMException Propogates <code>RMException</code> thrown by any of the managed
* sequences.
*/
public void doMaintenanceTasks() throws RMException {
for (String key : outboundMap.keySet()) {
ClientOutboundSequence seq =
getOutboundSequence(key);
synchronized(seq) {
//1. resend all incomplete messages
//2. send ackRequested messages in any sequences
// in danger of timing out.
seq.doMaintenanceTasks();
}
}
}
/**
* Initialize a sequence using a CreateSequence handshake. The
* returned Sequence can be set in BindingProvider properies which will
* result in the Sequence being used for the BindingProvider's request messages.
*
* @param client A Service hosting the endpoint
* @param port The QName for the RM enpoint.
* @return The ClientOutboundSequence. null if the sequence could not be created
*
*/
public ClientOutboundSequence createSequence(javax.xml.ws.Service service,
QName portName)
{
Dispatch<Source> disp = service.createDispatch(portName,
Source.class,
Service.Mode.PAYLOAD,
new javax.xml.ws.RespectBindingFeature());
byte[] bytes = Constants.createSequencePayload.getBytes();
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
StreamSource source = new StreamSource(stream);
try {
disp.invoke(source);
} catch (Exception e) {
//dont care what happened processing the response message. We are only
//interested in the sequence that has been stored in the request context
//
//TODO - At the same time, it would be prettier to get something other than
//a fault
}
ClientOutboundSequence seq = (ClientOutboundSequence)disp.getRequestContext()
.get(Constants.sequenceProperty);
seq.setService(service);
return seq;
}
/**
* Initialize a sequence using an existing seuence id known to an RM endpoint.
* The method is designed to be used after a startup to reinitialize a
* sequence from persisted data.
*
* @param client A Service hosting the endpoint
* @param port The QName for the RM enpoing.
* @param sequencID The id to be used for the outbound sequence
* @param companionSequenceID The id to be used for the companion inbound sequence,
* if any
* @return The ClientOutboundSequence. null if the sequence could not be created
*/
public ClientOutboundSequence createSequence(javax.xml.ws.Service service,
QName portName, String sequenceID,
String companionSequenceID){
//this will throw and exception if the specified sequence does not exist.
//removeOutboundSequence(sequenceID);
ClientOutboundSequence seq = createSequence(service, portName);
if (seq == null ) {
return null;
}
try {
seq.disconnect(false);
} catch (Exception e) {
e.printStackTrace();
}
seq.setId(sequenceID);
ClientInboundSequence iseq =
(ClientInboundSequence)seq.getInboundSequence();
if (companionSequenceID != null) {
if (iseq == null || iseq.getId() == null) {
String message = Messages.NO_TWO_WAY_OPERATION.format();
IllegalArgumentException e = new IllegalArgumentException(message);
logger.log(Level.FINE, message, e);
throw e;
}
iseq.setId(companionSequenceID);
} else if (iseq != null && iseq.getId() != null) {
String message = Messages.NO_INBOUND_SEQUENCE_ID_SPECIFIED.format();
IllegalArgumentException e = new IllegalArgumentException(message);
logger.log(Level.FINE, message,e);
throw e;
}
if (outboundMap.get(sequenceID) != null) {
String message = Messages.SEQUENCE_ALREADY_EXISTS.format(sequenceID);
IllegalArgumentException e = new IllegalArgumentException(message);
logger.log(Level.FINE, message, e);
throw e;
}
if (companionSequenceID != null &&
inboundMap.get(companionSequenceID) != null) {
String message = Messages.SEQUENCE_ALREADY_EXISTS.format(companionSequenceID);
IllegalArgumentException e = new IllegalArgumentException(message);
logger.log(Level.FINE, message, e);
throw e;
}
addOutboundSequence(seq);
return seq;
}
}
|