/* * Universal Media Server, for streaming any media to DLNA * compatible renderers based on the http://www.ps3mediaserver.org. * Copyright (C) 2012 UMS developers. * * This program is a free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; version 2 * of the License only. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package net.pms.dlna.protocolinfo; import static org.apache.commons.lang3.StringUtils.isBlank; import java.io.Serializable; import java.util.HashSet; import java.util.Locale; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This interface represents {@code protocolInfo} attribute names like * {@code DLNA.ORG_OP}, {@code DLNA.ORG_PS} and {@code DLNA.ORG_FLAGS}. * * @author Nadahar */ public interface ProtocolInfoAttributeName extends Serializable { /** The static {@code NONE} instance representing a blank/empty name */ ProtocolInfoAttributeName NONE = new GenericProtocolInfoAttributeName(""); /** * The static {@code WILDCARD} instance representing an asterisk * ({@code *}). */ ProtocolInfoAttributeName WILDCARD = new GenericProtocolInfoAttributeName("*"); /** * The static factory used to create and retrieve * {@link ProtocolInfoAttributeName} instances. */ ProtocolInfoAttributeNameFactory FACTORY = new ProtocolInfoAttributeNameFactory(); /** * Get the attribute name as a {@link String} value. * * @return The attribute name {@link String}. */ String getName(); /** * A factory for creating, caching and retrieving * {@link ProtocolInfoAttributeName} instances. */ public static class ProtocolInfoAttributeNameFactory { /** The logger. */ private static final Logger LOGGER = LoggerFactory.getLogger(ProtocolInfoAttributeNameFactory.class); /** The instance cache lock. */ private final ReentrantReadWriteLock instanceCacheLock = new ReentrantReadWriteLock(); /** The instance cache. */ private final HashSet<ProtocolInfoAttributeName> instanceCache = new HashSet<>(); /** * For internal use only, use {@link ProtocolInfoAttributeName#FACTORY} * to get the singleton instance. */ protected ProtocolInfoAttributeNameFactory() { } /** * Retrieves a {@link ProtocolInfoAttributeName} instance representing * the attribute name {@code name} from the predefined instances or the * cache. If no such {@link ProtocolInfoAttributeName} instance exists, * {@code null} is returned. * * @param name the attribute name. * @return The {@link ProtocolInfoAttributeName} instance or * {@code null}. */ public ProtocolInfoAttributeName getAttributeName(String name) { // Check for static instances if (isBlank(name)) { return NONE; } name = name.trim().toUpperCase(Locale.ROOT); if ("*".equals(name)) { return WILDCARD; } // Check for known instances for (KnownProtocolInfoAttributeName knownAttribute : KnownProtocolInfoAttributeName.values()) { if (name.equals(knownAttribute.getName())) { return knownAttribute; } } // Check for cached instances instanceCacheLock.readLock().lock(); try { for (ProtocolInfoAttributeName cachedAttribute : instanceCache) { if (name.equals(cachedAttribute.getName())) { return cachedAttribute; } } } finally { instanceCacheLock.readLock().unlock(); } return null; } /** * Creates or retrieves a {@link ProtocolInfoAttributeName} instance * representing the attribute name {@code name}. Any existing predefined * or cached instances are first checked, and if none are found for * {@code value} a new instance is created. * * @param name the profile name. * @return The {@link ProtocolInfoAttributeName} instance. */ public ProtocolInfoAttributeName createAttributeName(String name) { ProtocolInfoAttributeName instance = getAttributeName(name); if (instance != null) { return instance; } // Null values will already have been handled above name = name.trim().toUpperCase(Locale.ROOT); // Prepare to create a new instance instanceCacheLock.writeLock().lock(); try { // Check cache again as it could have been added while the lock // was released for (ProtocolInfoAttributeName cachedAttribute : instanceCache) { if (name.equals(cachedAttribute.getName())) { return cachedAttribute; } } // None was found, create the instance instance = new GenericProtocolInfoAttributeName(name); instanceCache.add(instance); LOGGER.trace("ProtocolInfoAttributeNameFactory added unknown attribute name \"{}\"", name); return instance; } finally { instanceCacheLock.writeLock().unlock(); } } } /** * This contains predefined, known {@code protocolInfo} attribute names. */ public enum KnownProtocolInfoAttributeName implements ProtocolInfoAttributeName { // The order is important for protocolInfo /** DLNA.ORG_PN */ DLNA_ORG_PN("DLNA.ORG_PN"), /** ARIB.OR.JP_PN */ ARIB_OR_JP_PN("ARIB.OR.JP_PN"), /** DTV_MVP_PN */ DTV_MVP_PN("DTV_MVP_PN"), /** PANASONIC.COM_PN */ PANASONIC_COM_PN("PANASONIC.COM_PN"), /** MICROSOFT.COM_PN */ MICROSOFT_COM_PN("MICROSOFT.COM_PN"), /** SHARP.COM_PN */ SHARP_COM_PN("SHARP.COM_PN"), /** SONY.COM_PN */ SONY_COM_PN("SONY.COM_PN"), /** DLNA.ORG_OP */ DLNA_ORG_OP("DLNA.ORG_OP"), /** DLNA.ORG_PS */ DLNA_ORG_PS("DLNA.ORG_PS"), /** DLNA.ORG_CI */ DLNA_ORG_CI("DLNA.ORG_CI"), /** DLNA.ORG_FLAGS */ DLNA_ORG_FLAGS("DLNA.ORG_FLAGS"), /** DLNA.ORG_MAXSP */ DLNA_ORG_MAXSP("DLNA.ORG_MAXSP"); private final String name; private KnownProtocolInfoAttributeName(String name) { this.name = name; } @Override public String getName() { return name; } @Override public String toString() { return name; } } /** * This is the default/generic class implementing * {@link ProtocolInfoAttributeName}. * {@link ProtocolInfoAttributeNameFactory} creates and caches instances of * this class. Immutable. */ public static class GenericProtocolInfoAttributeName implements ProtocolInfoAttributeName { private static final long serialVersionUID = 1L; /** The attribute name value. */ protected final String name; /** * For internal use only, use * {@link ProtocolInfoAttributeNameFactory#createAttributeName} to * create new instances. * * @param name the attribute name. */ protected GenericProtocolInfoAttributeName(String name) { this.name = name; } @Override public String getName() { return name; } @Override public String toString() { return name; } } }