1 /*
   2  * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.media.sound;
  27 
  28 import java.security.AccessController;
  29 import java.security.PrivilegedAction;
  30 import java.util.ArrayList;
  31 import java.util.Collections;
  32 import java.util.List;
  33 import java.util.Properties;
  34 
  35 import javax.sound.midi.Receiver;
  36 import javax.sound.midi.Sequencer;
  37 import javax.sound.midi.Synthesizer;
  38 import javax.sound.midi.Transmitter;
  39 import javax.sound.midi.spi.MidiDeviceProvider;
  40 import javax.sound.midi.spi.MidiFileReader;
  41 import javax.sound.midi.spi.MidiFileWriter;
  42 import javax.sound.midi.spi.SoundbankReader;
  43 import javax.sound.sampled.Clip;
  44 import javax.sound.sampled.Port;
  45 import javax.sound.sampled.SourceDataLine;
  46 import javax.sound.sampled.TargetDataLine;
  47 import javax.sound.sampled.spi.AudioFileReader;
  48 import javax.sound.sampled.spi.AudioFileWriter;
  49 import javax.sound.sampled.spi.FormatConversionProvider;
  50 import javax.sound.sampled.spi.MixerProvider;
  51 
  52 
  53 /**
  54  * JDK13Services uses the Service class in JDK 1.3 to discover a list of service
  55  * providers installed in the system.
  56  * <p>
  57  * This class is public because it is called from javax.sound.midi.MidiSystem
  58  * and javax.sound.sampled.AudioSystem. The alternative would be to make
  59  * JSSecurityManager public, which is considered worse.
  60  *
  61  * @author Matthias Pfisterer
  62  */
  63 public final class JDK13Services {
  64 
  65     /**
  66      * Filename of the properties file for default provider properties. This
  67      * file is searched in the subdirectory "conf" of the JRE directory (this
  68      * behaviour is hardcoded).
  69      */
  70     private static final String PROPERTIES_FILENAME = "sound.properties";
  71 
  72     /**
  73      * Properties loaded from the properties file for default provider
  74      * properties.
  75      */
  76     private static Properties properties;
  77 
  78     /**
  79      * Private, no-args constructor to ensure against instantiation.
  80      */
  81     private JDK13Services() {
  82     }
  83 
  84     /**
  85      * Obtains a List containing installed instances of the providers for the
  86      * requested service. The returned List is immutable.
  87      *
  88      * @param serviceClass The type of providers requested. This should be one
  89      *                     of AudioFileReader.class, AudioFileWriter.class,
  90      *                     FormatConversionProvider.class, MixerProvider.class,
  91      *                     MidiDeviceProvider.class, MidiFileReader.class,
  92      *                     MidiFileWriter.class or SoundbankReader.class.
  93      *
  94      * @return A List of providers of the requested type. This List is
  95      *         immutable.
  96      */
  97     public static List<?> getProviders(final Class<?> serviceClass) {
  98         final List<?> providers;
  99         if (!MixerProvider.class.equals(serviceClass)
 100                 && !FormatConversionProvider.class.equals(serviceClass)
 101                 && !AudioFileReader.class.equals(serviceClass)
 102                 && !AudioFileWriter.class.equals(serviceClass)
 103                 && !MidiDeviceProvider.class.equals(serviceClass)
 104                 && !SoundbankReader.class.equals(serviceClass)
 105                 && !MidiFileWriter.class.equals(serviceClass)
 106                 && !MidiFileReader.class.equals(serviceClass)) {
 107             providers = new ArrayList<>(0);
 108         } else {
 109             providers = JSSecurityManager.getProviders(serviceClass);
 110         }
 111         return Collections.unmodifiableList(providers);
 112     }
 113 
 114     /** Obtain the provider class name part of a default provider property.
 115         @param typeClass The type of the default provider property. This
 116         should be one of Receiver.class, Transmitter.class, Sequencer.class,
 117         Synthesizer.class, SourceDataLine.class, TargetDataLine.class,
 118         Clip.class or Port.class.
 119         @return The value of the provider class name part of the property
 120         (the part before the hash sign), if available. If the property is
 121         not set or the value has no provider class name part, null is returned.
 122      */
 123     public static synchronized String getDefaultProviderClassName(Class<?> typeClass) {
 124         String value = null;
 125         String defaultProviderSpec = getDefaultProvider(typeClass);
 126         if (defaultProviderSpec != null) {
 127             int hashpos = defaultProviderSpec.indexOf('#');
 128             if (hashpos == 0) {
 129                 // instance name only; leave value as null
 130             } else if (hashpos > 0) {
 131                 value = defaultProviderSpec.substring(0, hashpos);
 132             } else {
 133                 value = defaultProviderSpec;
 134             }
 135         }
 136         return value;
 137     }
 138 
 139 
 140     /** Obtain the instance name part of a default provider property.
 141         @param typeClass The type of the default provider property. This
 142         should be one of Receiver.class, Transmitter.class, Sequencer.class,
 143         Synthesizer.class, SourceDataLine.class, TargetDataLine.class,
 144         Clip.class or Port.class.
 145         @return The value of the instance name part of the property (the
 146         part after the hash sign), if available. If the property is not set
 147         or the value has no instance name part, null is returned.
 148      */
 149     public static synchronized String getDefaultInstanceName(Class<?> typeClass) {
 150         String value = null;
 151         String defaultProviderSpec = getDefaultProvider(typeClass);
 152         if (defaultProviderSpec != null) {
 153             int hashpos = defaultProviderSpec.indexOf('#');
 154             if (hashpos >= 0 && hashpos < defaultProviderSpec.length() - 1) {
 155                 value = defaultProviderSpec.substring(hashpos + 1);
 156             }
 157         }
 158         return value;
 159     }
 160 
 161 
 162     /** Obtain the value of a default provider property.
 163         @param typeClass The type of the default provider property. This
 164         should be one of Receiver.class, Transmitter.class, Sequencer.class,
 165         Synthesizer.class, SourceDataLine.class, TargetDataLine.class,
 166         Clip.class or Port.class.
 167         @return The complete value of the property, if available.
 168         If the property is not set, null is returned.
 169      */
 170     private static synchronized String getDefaultProvider(Class<?> typeClass) {
 171         if (!SourceDataLine.class.equals(typeClass)
 172                 && !TargetDataLine.class.equals(typeClass)
 173                 && !Clip.class.equals(typeClass)
 174                 && !Port.class.equals(typeClass)
 175                 && !Receiver.class.equals(typeClass)
 176                 && !Transmitter.class.equals(typeClass)
 177                 && !Synthesizer.class.equals(typeClass)
 178                 && !Sequencer.class.equals(typeClass)) {
 179             return null;
 180         }
 181         String name = typeClass.getName();
 182         String value = AccessController.doPrivileged(
 183                 (PrivilegedAction<String>) () -> System.getProperty(name));
 184         if (value == null) {
 185             value = getProperties().getProperty(name);
 186         }
 187         if ("".equals(value)) {
 188             value = null;
 189         }
 190         return value;
 191     }
 192 
 193 
 194     /** Obtain a properties bundle containing property values from the
 195         properties file. If the properties file could not be loaded,
 196         the properties bundle is empty.
 197     */
 198     private static synchronized Properties getProperties() {
 199         if (properties == null) {
 200             properties = new Properties();
 201             JSSecurityManager.loadProperties(properties, PROPERTIES_FILENAME);
 202         }
 203         return properties;
 204     }
 205 }