/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.cxf.ws.rm; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.apache.cxf.helpers.CastUtils; import org.apache.cxf.ws.rm.persistence.RMStore; import org.apache.cxf.ws.rm.v200702.Identifier; public class Source extends AbstractEndpoint { private static final String REQUESTOR_SEQUENCE_ID = ""; private Map<String, SourceSequence> map; private Map<String, SourceSequence> current; private Lock sequenceCreationLock; private Condition sequenceCreationCondition; private boolean sequenceCreationNotified; Source(RMEndpoint reliableEndpoint) { super(reliableEndpoint); map = new ConcurrentHashMap<String, SourceSequence>(); current = new HashMap<>(); sequenceCreationLock = new ReentrantLock(); sequenceCreationCondition = sequenceCreationLock.newCondition(); } public SourceSequence getSequence(Identifier id) { return map.get(id.getValue()); } public Collection<SourceSequence> getAllSequences() { return CastUtils.cast(map.values()); } public void addSequence(SourceSequence seq) { addSequence(seq, true); } public void addSequence(SourceSequence seq, boolean persist) { seq.setSource(this); map.put(seq.getIdentifier().getValue(), seq); if (persist) { RMStore store = getReliableEndpoint().getManager().getStore(); if (null != store) { store.createSourceSequence(seq); } } processingSequenceCount.incrementAndGet(); } public void removeSequence(SourceSequence seq) { SourceSequence o; o = map.remove(seq.getIdentifier().getValue()); RMStore store = getReliableEndpoint().getManager().getStore(); if (null != store) { store.removeSourceSequence(seq.getIdentifier()); } if (o != null) { processingSequenceCount.decrementAndGet(); completedSequenceCount.incrementAndGet(); } } /** * Returns a collection of all sequences for which have not yet been * completely acknowledged. * * @return the collection of unacknowledged sequences. */ public Collection<SourceSequence> getAllUnacknowledgedSequences() { Collection<SourceSequence> seqs = new ArrayList<>(); for (SourceSequence seq : map.values()) { if (!seq.allAcknowledged()) { seqs.add(seq); } } return seqs; } /** * Returns the current sequence used by a client side source. * * @return the current sequence. */ SourceSequence getCurrent() { return getCurrent(null); } /** * Sets the current sequence used by a client side source. * @param s the current sequence. */ public void setCurrent(SourceSequence s) { setCurrent(null, s); } /** * Returns the current sequence used by a server side source for responses to a message * sent as part of the inbound sequence with the specified identifier. * * @return the current sequence. */ SourceSequence getCurrent(Identifier i) { sequenceCreationLock.lock(); try { return getAssociatedSequence(i); } finally { sequenceCreationLock.unlock(); } } /** * Returns the sequence associated with the given identifier. * * @param i the corresponding sequence identifier * @return the associated sequence * @pre the sequenceCreationLock is already held */ SourceSequence getAssociatedSequence(Identifier i) { return current.get(i == null ? REQUESTOR_SEQUENCE_ID : i.getValue()); } /** * Await the availability of a sequence corresponding to the given identifier. * * @param i the sequence identifier * @return */ SourceSequence awaitCurrent(Identifier i) { sequenceCreationLock.lock(); try { SourceSequence seq = getAssociatedSequence(i); while (seq == null) { while (!sequenceCreationNotified) { try { sequenceCreationCondition.await(); } catch (InterruptedException ie) { // ignore } } seq = getAssociatedSequence(i); } return seq; } finally { sequenceCreationLock.unlock(); } } /** * Sets the current sequence used by a server side source for responses to a message * sent as part of the inbound sequence with the specified identifier. * @param s the current sequence. */ void setCurrent(Identifier i, SourceSequence s) { sequenceCreationLock.lock(); try { current.put(i == null ? REQUESTOR_SEQUENCE_ID : i.getValue(), s); sequenceCreationNotified = true; sequenceCreationCondition.signal(); } finally { sequenceCreationLock.unlock(); } } }