All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.websocket.jsr356.metadata.CoderMetadataSet Maven / Gradle / Ivy

There is a newer version: 11.0.0.beta1
Show newest version
//
//  ========================================================================
//  Copyright (c) 1995-2018 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;

/**
 * An durable collection of {@link CoderMetadata}.
 * 

* This is a write-only collection, and cannot be modified once initialized. * * @param * The type of coder ({@link Decoder} or {@link Encoder} * @param * The metadata for the coder */ public abstract class CoderMetadataSet> implements Iterable { /** * Collection of metadatas */ private final List metadatas; /** * Collection of declared Coder classes */ private final List> coders; /** * Mapping of supported Type to metadata list index */ private final Map, Integer> typeMap; /** * Mapping of Coder class to list of supported metadata */ private final Map, List> implMap; protected CoderMetadataSet() { metadatas = new ArrayList<>(); coders = new ArrayList<>(); typeMap = new ConcurrentHashMap<>(); implMap = new ConcurrentHashMap<>(); } public void add(Class coder) { List metadatas = discover(coder); trackMetadata(metadatas); } public List addAll(Class[] coders) { List metadatas = new ArrayList<>(); for (Class coder : coders) { metadatas.addAll(discover(coder)); } trackMetadata(metadatas); return metadatas; } public List addAll(List> coders) { List metadatas = new ArrayList<>(); for (Class 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 discover(Class coder); public Class getCoder(Class type) { M metadata = getMetadataByType(type); if (metadata == null) { return null; } return metadata.getCoderClass(); } public List> getList() { return coders; } public List getMetadataByImplementation(Class clazz) { List indexes = implMap.get(clazz); if (indexes == null) { return null; } List 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) { // Quick lookup failed, try slower lookup via isAssignable instead idx = getMetadataByAssignableType(type); if (idx != null) { // add new entry map typeMap.put(type,idx); } } // If idx is STILL null, we've got no match if (idx == null) { return null; } return metadatas.get(idx); } private Integer getMetadataByAssignableType(Class type) { for (Map.Entry, Integer> entry : typeMap.entrySet()) { if (entry.getKey().isAssignableFrom(type)) { return entry.getValue(); } } return null; } @Override public Iterator 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 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 coderClass = metadata.getCoderClass(); int newidx = metadatas.size(); metadatas.add(metadata); coders.add(coderClass); typeMap.put(type,newidx); List 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); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy