There is a race which could see us without a populated mapping while a
schemacontext change is underway. Use a immutablemap guarded by an
atomicreference to allow proper switching. Note that the fix is
incomplete, as the schema context needs to be replaced at the same time.
Change-Id: I7d64fae99a0bc0f7d1ec19f08450c1954cb7af97
Signed-off-by: Robert Varga <rovarga@cisco.com>
import com.google.common.collect.BiMap;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.BiMap;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashBiMap;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import java.io.UnsupportedEncodingException;
import com.google.common.collect.Iterables;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicReference;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.Response.Status;
private final Map<String, URI> moduleNameToUri = uriToModuleName.inverse();
private final Map<String, URI> moduleNameToUri = uriToModuleName.inverse();
- private final Map<QName, RpcDefinition> qnameToRpc = new ConcurrentHashMap<>();
+ private final AtomicReference<Map<QName, RpcDefinition>> qnameToRpc =
+ new AtomicReference<>(Collections.<QName, RpcDefinition>emptyMap());
private volatile SchemaContext globalSchema;
private volatile MountService mountService;
private volatile SchemaContext globalSchema;
private volatile MountService mountService;
public RpcDefinition getRpcDefinition(final String name) {
final QName validName = this.toQName(name);
public RpcDefinition getRpcDefinition(final String name) {
final QName validName = this.toQName(name);
- return validName == null ? null : this.qnameToRpc.get(validName);
+ return validName == null ? null : this.qnameToRpc.get().get(validName);
}
@Override
public void onGlobalContextUpdated(final SchemaContext context) {
if (context != null) {
}
@Override
public void onGlobalContextUpdated(final SchemaContext context) {
if (context != null) {
- this.qnameToRpc.clear();
- this.setGlobalSchema(context);
- Set<RpcDefinition> _operations = context.getOperations();
- for (final RpcDefinition operation : _operations) {
- {
- this.qnameToRpc.put(operation.getQName(), operation);
- }
+ final Collection<RpcDefinition> defs = context.getOperations();
+ final Map<QName, RpcDefinition> newMap = new HashMap<>(defs.size());
+
+ for (final RpcDefinition operation : defs) {
+ newMap.put(operation.getQName(), operation);
+
+ // FIXME: still not completely atomic
+ this.qnameToRpc.set(ImmutableMap.copyOf(newMap));
+ this.setGlobalSchema(context);