diff options
Diffstat (limited to 'jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadataSet.java')
-rw-r--r-- | jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadataSet.java | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadataSet.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadataSet.java new file mode 100644 index 0000000000..9835c05a89 --- /dev/null +++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadataSet.java @@ -0,0 +1,235 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.jsr356.metadata; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.websocket.Decoder; +import javax.websocket.Encoder; + +import org.eclipse.jetty.websocket.api.InvalidWebSocketException; + +/** + * An durable collection of {@link CoderMetadata}. + * <p> + * This is a write-only collection, and cannot be modified once initialized. + * + * @param <T> + * The type of coder ({@link Decoder} or {@link Encoder} + * @param <M> + * The metadata for the coder + */ +public abstract class CoderMetadataSet<T, M extends CoderMetadata<T>> implements Iterable<M> +{ + /** + * Collection of metadatas + */ + private final List<M> metadatas; + /** + * Collection of declared Coder classes + */ + private final List<Class<? extends T>> coders; + /** + * Mapping of supported Type to metadata list index + */ + private final Map<Class<?>, Integer> typeMap; + /** + * Mapping of Coder class to list of supported metadata + */ + private final Map<Class<? extends T>, List<Integer>> implMap; + + protected CoderMetadataSet() + { + metadatas = new ArrayList<>(); + coders = new ArrayList<>(); + typeMap = new ConcurrentHashMap<>(); + implMap = new ConcurrentHashMap<>(); + } + + public void add(Class<? extends T> coder) + { + List<M> metadatas = discover(coder); + trackMetadata(metadatas); + } + + public List<M> addAll(Class<? extends T>[] coders) + { + List<M> metadatas = new ArrayList<>(); + + for (Class<? extends T> coder : coders) + { + metadatas.addAll(discover(coder)); + } + + trackMetadata(metadatas); + return metadatas; + } + + public List<M> addAll(List<Class<? extends T>> coders) + { + List<M> metadatas = new ArrayList<>(); + + for (Class<? extends T> coder : coders) + { + metadatas.addAll(discover(coder)); + } + + trackMetadata(metadatas); + return metadatas; + } + + /** + * Coder Specific discovery of Metadata for a specific coder. + * + * @param coder + * the coder to discover metadata in. + * @return the list of metadata discovered + * @throws InvalidWebSocketException + * if unable to discover some metadata. Sucha as: a duplicate {@link CoderMetadata#getObjectType()} encountered, , or if unable to find the + * concrete generic class reference for the coder, or if the provided coder is not valid per spec. + */ + protected abstract List<M> discover(Class<? extends T> coder); + + public Class<? extends T> getCoder(Class<?> type) + { + M metadata = getMetadataByType(type); + if (metadata == null) + { + return null; + } + return metadata.getCoderClass(); + } + + public List<Class<? extends T>> getList() + { + return coders; + } + + public List<M> getMetadataByImplementation(Class<? extends T> clazz) + { + List<Integer> indexes = implMap.get(clazz); + if (indexes == null) + { + return null; + } + List<M> ret = new ArrayList<>(); + for (Integer idx : indexes) + { + ret.add(metadatas.get(idx)); + } + return ret; + } + + public M getMetadataByType(Class<?> type) + { + Integer idx = typeMap.get(type); + if (idx == null) + { + return null; + } + return metadatas.get(idx); + } + + @Override + public Iterator<M> iterator() + { + return metadatas.iterator(); + } + + @Override + public String toString() + { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + builder.append("[metadatas="); + builder.append(metadatas.size()); + builder.append(",coders="); + builder.append(coders.size()); + builder.append("]"); + return builder.toString(); + } + + protected void trackMetadata(List<M> metadatas) + { + for (M metadata : metadatas) + { + trackMetadata(metadata); + } + } + + protected void trackMetadata(M metadata) + { + synchronized (metadatas) + { + // Validate + boolean duplicate = false; + + // Is this metadata already declared? + if (metadatas.contains(metadata)) + { + duplicate = true; + } + + // Is this type already declared? + Class<?> type = metadata.getObjectType(); + if (typeMap.containsKey(type)) + { + duplicate = true; + } + + if (duplicate) + { + StringBuilder err = new StringBuilder(); + err.append("Duplicate decoder for type: "); + err.append(type); + err.append(" (class ").append(metadata.getCoderClass().getName()); + + // Get prior one + M dup = getMetadataByType(type); + err.append(" duplicates "); + err.append(dup.getCoderClass().getName()); + err.append(")"); + throw new IllegalStateException(err.toString()); + } + + // Track + Class<? extends T> coderClass = metadata.getCoderClass(); + int newidx = metadatas.size(); + metadatas.add(metadata); + coders.add(coderClass); + typeMap.put(type,newidx); + + List<Integer> indexes = implMap.get(coderClass); + if (indexes == null) + { + indexes = new ArrayList<>(); + } + if (indexes.contains(newidx)) + { + // possible duplicate, TODO: how? + } + indexes.add(newidx); + implMap.put(coderClass,indexes); + } + } +} |