1 /*
   2  * Copyright (c) 1999, 2013, 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.util.ArrayList;
  29 import java.util.Collections;
  30 import java.util.List;
  31 import java.util.Properties;
  32 
  33 import javax.sound.midi.Receiver;
  34 import javax.sound.midi.Sequencer;
  35 import javax.sound.midi.Synthesizer;
  36 import javax.sound.midi.Transmitter;
  37 import javax.sound.midi.spi.MidiDeviceProvider;
  38 import javax.sound.midi.spi.MidiFileReader;
  39 import javax.sound.midi.spi.MidiFileWriter;
  40 import javax.sound.midi.spi.SoundbankReader;
  41 import javax.sound.sampled.Clip;
  42 import javax.sound.sampled.Port;
  43 import javax.sound.sampled.SourceDataLine;
  44 import javax.sound.sampled.TargetDataLine;
  45 import javax.sound.sampled.spi.AudioFileReader;
  46 import javax.sound.sampled.spi.AudioFileWriter;
  47 import javax.sound.sampled.spi.FormatConversionProvider;
  48 import javax.sound.sampled.spi.MixerProvider;
  49 
  50 
  51 /**
  52  * JDK13Services uses the Service class in JDK 1.3 to discover a list of service
  53  * providers installed in the system.
  54  * <p>
  55  * This class is public because it is called from javax.sound.midi.MidiSystem
  56  * and javax.sound.sampled.AudioSystem. The alternative would be to make
  57  * JSSecurityManager public, which is considered worse.
  58  *
  59  * @author Matthias Pfisterer
  60  */
  61 public final class JDK13Services {
  62 
  63     /**
  64      * Filename of the properties file for default provider properties. This
  65      * file is searched in the subdirectory "lib" of the JRE directory (this
  66      * behaviour is hardcoded).
  67      */
  68     private static final String PROPERTIES_FILENAME = "sound.properties";
  69 
  70     /**
  71      * Properties loaded from the properties file for default provider
  72      * properties.
  73      */
  74     private static Properties properties;
  75 
  76     /**
  77      * Private, no-args constructor to ensure against instantiation.
  78      */
  79     private JDK13Services() {
  80     }
  81 
  82     /**
  83      * Obtains a List containing installed instances of the providers for the
  84      * requested service. The returned List is immutable.
  85      *
  86      * @param serviceClass The type of providers requested. This should be one
  87      *                     of AudioFileReader.class, AudioFileWriter.class,
  88      *                     FormatConversionProvider.class, MixerProvider.class,
  89      *                     MidiDeviceProvider.class, MidiFileReader.class,
  90      *                     MidiFileWriter.class or SoundbankReader.class.
  91      *
  92      * @return A List of providers of the requested type. This List is
  93      *         immutable.
  94      */
  95     public static List<?> getProviders(final Class<?> serviceClass) {
  96         final List<?> providers;
  97         if (!MixerProvider.class.equals(serviceClass)
  98                 && !FormatConversionProvider.class.equals(serviceClass)
  99                 && !AudioFileReader.class.equals(serviceClass)
 100                 && !AudioFileWriter.class.equals(serviceClass)
 101                 && !MidiDeviceProvider.class.equals(serviceClass)
 102                 && !SoundbankReader.class.equals(serviceClass)
 103                 && !MidiFileWriter.class.equals(serviceClass)
 104                 && !MidiFileReader.class.equals(serviceClass)) {
 105             providers = new ArrayList<>(0);
 106         } else {
 107             providers = JSSecurityManager.getProviders(serviceClass);
 108         }
 109         return Collections.unmodifiableList(providers);
 110     }
 111 
 112     /** Obtain the provider class name part of a default provider property.
 113         @param typeClass The type of the default provider property. This
 114         should be one of Receiver.class, Transmitter.class, Sequencer.class,
 115         Synthesizer.class, SourceDataLine.class, TargetDataLine.class,
 116         Clip.class or Port.class.
 117         @return The value of the provider class name part of the property
 118         (the part before the hash sign), if available. If the property is
 119         not set or the value has no provider class name part, null is returned.
 120      */
 121     public static synchronized String getDefaultProviderClassName(Class<?> typeClass) {
 122         String value = null;
 123         String defaultProviderSpec = getDefaultProvider(typeClass);
 124         if (defaultProviderSpec != null) {
 125             int hashpos = defaultProviderSpec.indexOf('#');
 126             if (hashpos == 0) {
 127                 // instance name only; leave value as null
 128             } else if (hashpos > 0) {
 129                 value = defaultProviderSpec.substring(0, hashpos);
 130             } else {
 131                 value = defaultProviderSpec;
 132             }
 133         }
 134         return value;
 135     }
 136 
 137 
 138     /** Obtain the instance name part of a default provider property.
 139         @param typeClass The type of the default provider property. This
 140         should be one of Receiver.class, Transmitter.class, Sequencer.class,
 141         Synthesizer.class, SourceDataLine.class, TargetDataLine.class,
 142         Clip.class or Port.class.
 143         @return The value of the instance name part of the property (the
 144         part after the hash sign), if available. If the property is not set
 145         or the value has no instance name part, null is returned.
 146      */
 147     public static synchronized String getDefaultInstanceName(Class<?> typeClass) {
 148         String value = null;
 149         String defaultProviderSpec = getDefaultProvider(typeClass);
 150         if (defaultProviderSpec != null) {
 151             int hashpos = defaultProviderSpec.indexOf('#');
 152             if (hashpos >= 0 && hashpos < defaultProviderSpec.length() - 1) {
 153                 value = defaultProviderSpec.substring(hashpos + 1);
 154             }
 155         }
 156         return value;
 157     }
 158 
 159 
 160     /** Obtain the value of a default provider property.
 161         @param typeClass The type of the default provider property. This
 162         should be one of Receiver.class, Transmitter.class, Sequencer.class,
 163         Synthesizer.class, SourceDataLine.class, TargetDataLine.class,
 164         Clip.class or Port.class.
 165         @return The complete value of the property, if available.
 166         If the property is not set, null is returned.
 167      */
 168     private static synchronized String getDefaultProvider(Class<?> typeClass) {
 169         if (!SourceDataLine.class.equals(typeClass)
 170                 && !TargetDataLine.class.equals(typeClass)
 171                 && !Clip.class.equals(typeClass)
 172                 && !Port.class.equals(typeClass)
 173                 && !Receiver.class.equals(typeClass)
 174                 && !Transmitter.class.equals(typeClass)
 175                 && !Synthesizer.class.equals(typeClass)
 176                 && !Sequencer.class.equals(typeClass)) {
 177             return null;
 178         }
 179         String value;
 180         String propertyName = typeClass.getName();
 181         value = JSSecurityManager.getProperty(propertyName);
 182         if (value == null) {
 183             value = getProperties().getProperty(propertyName);
 184         }
 185         if ("".equals(value)) {
 186             value = null;
 187         }
 188         return value;
 189     }
 190 
 191 
 192     /** Obtain a properties bundle containing property values from the
 193         properties file. If the properties file could not be loaded,
 194         the properties bundle is empty.
 195     */
 196     private static synchronized Properties getProperties() {
 197         if (properties == null) {
 198             properties = new Properties();
 199             JSSecurityManager.loadProperties(properties, PROPERTIES_FILENAME);
 200         }
 201         return properties;
 202     }
 203 }